import { _decorator, Component, Node, input, Input, EventTouch, Vec3, Quat, v3, Button, tween, v2, Camera, director, geometry, screen, PhysicsSystem, Prefab, instantiate, ParticleSystem } from 'cc'; import { RagdollBone } from '../Ragdoll/RagdollBone'; import { SingletonBase } from './framework/SingletonBase'; import { GameController } from './GameController'; import { Ragdoll } from '../Ragdoll/Ragdoll'; import { UIManager } from './framework/ui/UIManager'; const { ccclass, property } = _decorator; @ccclass('FPSCameraController') export class FPSCameraController extends SingletonBase { // export class FPSCameraController extends Component { @property(Node) cameraNode: Node = null; // 相机节点 @property(Camera) camera: Camera = null; // 相机节点 @property(Camera) qingBao: Camera = null; // 相机节点 @property(ParticleSystem) particle: ParticleSystem = null; // 粒子系统 @property(Prefab) lastBulletPrefab: Prefab = null; lastBullet: Node = null; private _touchStartPos: Vec3 = new Vec3(); private _rotationSpeed: number = 0.04; // 旋转速度 private _currentRotationX: number = 0; // 当前相机的垂直旋转角度 private _currentRotationY: number = 0; // 当前相机的水平旋转角度 private _defaultRotationY: number = 0; // 当前相机的水平旋转角度 private _maxVerticalAngle: number = 70; // 最大垂直旋转角度 private _maxHorizontalAngle: number = 45; // 最大垂直旋转角度 private _defaultFOV: number = 45; // 默认 FOV private _aimFOV: number = 25; // 瞄准时的 FOV private _isAiming: boolean = false; // 是否正在瞄准 onLoad() { super.onLoad() } init(curCamera: Camera, aimFov: number) { this.camera = curCamera this.cameraNode = curCamera.node const initialRotation = this.cameraNode.getWorldRotation(); const eulerAngles = initialRotation.getEulerAngles(v3()); this._currentRotationX = eulerAngles.x; this._currentRotationY = eulerAngles.y; this._defaultRotationY = eulerAngles.y; this._aimFOV = aimFov; // 获取摄像机的默认 FOV const camera = this.cameraNode.getComponent(Camera); camera.fov = this._defaultFOV } onTouchStart(event: EventTouch) { // console.log("onTouchStart", event) const touch = event.touch; this._touchStartPos.set(touch.getLocation().x, touch.getLocation().y, 0); } onTouchMove(event: EventTouch) { // console.log("onTouchMove", event) const touch = event.touch; const deltaX = touch.getLocation().x - this._touchStartPos.x; const deltaY = touch.getLocation().y - this._touchStartPos.y; // 横向旋转(左右滑动):作用于摄像机的 Y 轴 const rotationY = -deltaX * this._rotationSpeed * this.camera.fov / 45; // console.log("this.camera.fov", this.camera.fov) this._currentRotationY += rotationY; // 纵向旋转(上下滑动):作用于摄像机的 X 轴 const rotationX = deltaY * this._rotationSpeed * this.camera.fov / 45;// 修正:去掉负号 this._currentRotationX += rotationX; // 限制垂直旋转角度 this._currentRotationX = Math.min(Math.max(this._currentRotationX, -this._maxVerticalAngle), 60); this._currentRotationY = Math.min(Math.max(this._currentRotationY, this._defaultRotationY - this._maxHorizontalAngle), this._defaultRotationY + this._maxHorizontalAngle); // 应用旋转到相机节点 const newRotation = Quat.fromEuler(new Quat(), this._currentRotationX, this._currentRotationY, 0); this.cameraNode.setWorldRotation(newRotation); // console.log("newRotation", this._currentRotationX, this._currentRotationY) // 更新起始位置 this._touchStartPos.set(touch.getLocation().x, touch.getLocation().y, 0); } setTutorialRotate() { this._currentRotationX = -3.99 this._currentRotationY = -32.27 const newRotation = Quat.fromEuler(new Quat(), this._currentRotationX, this._currentRotationY, 0); this.cameraNode.setWorldRotation(newRotation); } shoot() { let ray = new geometry.Ray(); this.camera.screenPointToRay(screen.windowSize.width / 2, screen.windowSize.height / 2, ray); // 以下参数可选 const mask = 0xffffffff; const maxDistance = 10000000; const queryTrigger = true; let result = false if (PhysicsSystem.instance.raycastClosest(ray, mask, maxDistance, queryTrigger)) { const raycastClosestResult = PhysicsSystem.instance.raycastClosestResult; const hitPoint = raycastClosestResult.hitPoint const hitNormal = raycastClosestResult.hitNormal; const collider = raycastClosestResult.collider; const distance = raycastClosestResult.distance; console.log("碰撞检测", raycastClosestResult.collider.node.name) let bone = raycastClosestResult.collider.node.getComponent(RagdollBone) if (bone != null) { if (!bone.ragdoll.isDie) { if (GameController.getInstance().curLevel.judgeLastBullet()) { this.fireLastBullet(bone.ragdoll, hitPoint) } else { this.scheduleOnce(() => { bone.ragdoll.node.active = false }, 2); bone.ragdoll.setEnabled(true); result = true this.particle.node.setWorldPosition(hitPoint.clone()) this.particle.play() } } } } tween(this.camera.node) .by(0.05, { position: new Vec3(0, 2, 0) }, { easing: 'sineOutIn' }) .by(0.05, { position: new Vec3(0, -2, 0) }, { easing: 'sineOutIn' }) .start() return result } closeQingBao() { this.qingBao.node.active = false } showQingBao() { this.qingBao.node.active = true var enemy = GameController.getInstance().curLevel.getQingBaoEnemey().centerNode; let pos = enemy.getWorldPosition().add(enemy.getWorldPosition().subtract(this.cameraNode.getWorldPosition()).normalize().multiplyScalar(-5)) let enemyPos = enemy.getWorldPosition() let cameraPos = this.cameraNode.getWorldPosition() let dirNor = enemy.getWorldPosition().subtract(this.cameraNode.getWorldPosition()).normalize() let newPos = enemy.getWorldPosition().add(dirNor.multiplyScalar(-15)) let dir = this.cameraNode.getWorldPosition().subtract(enemy.getWorldPosition()) console.log("enemy", enemy.getWorldPosition()) console.log("camera", this.cameraNode.getWorldPosition()) console.log("newPos", newPos) console.log("dirNor", enemy.getWorldPosition().subtract(this.cameraNode.getWorldPosition()).normalize()) this.qingBao.node.setWorldPosition(newPos) this.qingBao.node.forward = enemy.getWorldPosition().subtract(this.cameraNode.getWorldPosition()).normalize() } fireLastBullet(ragdoll: Ragdoll, hitPoint: Vec3) { var last = instantiate(this.lastBulletPrefab) last.setParent(this.node) last.setWorldPosition(this.cameraNode.worldPosition) last.forward = this.cameraNode.worldPosition.subtract(hitPoint).normalize() this.lastBullet = last this.camera.enabled = false UIManager.instance.closeAllPanels() tween(last) .to(1.67, { worldPosition: hitPoint }, { easing: 'cubicIn' }) .call(() => { ragdoll.setEnabled(true); last.getChildByName("bullet").active = false GameController.getInstance().curLevel.win() }) .start() } clear() { if (this.lastBullet != null) { this.lastBullet.destroy() this.lastBullet = null } } onAimButtonClick(isAnim: boolean) { const camera = this.cameraNode.getComponent(Camera); if (!camera) return; this._isAiming = isAnim; // 切换瞄准状态 if (this._isAiming) { // 瞄准状态:缩小 FOV tween(camera) .to(0.1, { fov: this._aimFOV }) // 平滑过渡到瞄准 FOV .start(); } else { // 非瞄准状态:恢复默认 FOV tween(camera) .to(0.1, { fov: this._defaultFOV }) // 平滑过渡到默认 FOV .start(); } } }