221 lines
8.6 KiB
TypeScript
221 lines
8.6 KiB
TypeScript
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<FPSCameraController> {
|
|
// 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();
|
|
}
|
|
}
|
|
} |