import { _decorator, Component, Node, v3, RigidBody, Vec3, find, Camera, SkeletalAnimation,Animation, AnimationClip, Collider, ICollisionEvent } from 'cc'; import { EasyController, EasyControllerEvent } from './EasyController'; const { ccclass, property } = _decorator; const v3_1 = v3(); @ccclass('tgxCharacterMovement') export class CharacterMovement extends Component { @property(Camera) mainCamera: Camera; @property velocity = 1.0; @property jumpVelocity = 1.0; @property maxJumpTimes: number = 0; private _curJumpTimes: number = 0; @property(AnimationClip) idleAnimClip: AnimationClip; @property(AnimationClip) moveAnimClip: AnimationClip; @property(AnimationClip) jumpBeginAnimClip: AnimationClip; @property(AnimationClip) jumpLoopAnimClip: AnimationClip; @property(AnimationClip) jumpLandAnimClip: AnimationClip; _rigidBody: RigidBody; _isMoving: boolean = false; _velocityScale: number = 1.0; _isInTheAir: boolean = false; _currentVerticalVelocity: number = 0.0; private _anim: Animation; start() { if (!this.mainCamera) { this.mainCamera = find('Main Camera')?.getComponent(Camera); } this._rigidBody = this.node.getComponent(RigidBody); this._anim = this.node.getComponent(Animation); if (this._anim) { let clipArr = [ this.idleAnimClip, this.moveAnimClip, this.jumpBeginAnimClip, this.jumpLoopAnimClip, this.jumpLandAnimClip ]; for (let i = 0; i < clipArr.length; ++i) { let clip = clipArr[i]; if (clip) { if (!this._anim.getState(clip.name)) { this._anim.addClip(clip); } } } if (this.idleAnimClip) { this._anim.play(this.idleAnimClip.name); } } EasyController.on(EasyControllerEvent.MOVEMENT, this.onMovement, this); EasyController.on(EasyControllerEvent.MOVEMENT_STOP, this.onMovementRelease, this); EasyController.on(EasyControllerEvent.BUTTON, this.onJump, this); let myCollider = this.getComponent(Collider); myCollider?.on('onCollisionEnter',(target:ICollisionEvent)=>{ if(target.otherCollider != target.selfCollider){ this.onLand(); } }); } onDestroy() { EasyController.off(EasyControllerEvent.MOVEMENT, this.onMovement, this); EasyController.off(EasyControllerEvent.MOVEMENT_STOP, this.onMovementRelease, this); EasyController.off(EasyControllerEvent.MOVEMENT_STOP, this.onJump, this); } update(deltaTime: number) { if (this._isMoving) { this._tmp.set(this.node.forward); this._tmp.multiplyScalar(-1.0); this._tmp.multiplyScalar(this.velocity * this._velocityScale); if (this._rigidBody) { this._rigidBody.getLinearVelocity(v3_1); this._tmp.y = v3_1.y; this._rigidBody.setLinearVelocity(this._tmp); } else { this._tmp.multiplyScalar(deltaTime); this._tmp.add(this.node.position); this.node.setPosition(this._tmp); } } if (this._isInTheAir) { if(this.jumpBeginAnimClip && this._anim){ let state = this._anim.getState(this.jumpBeginAnimClip.name); if(state.isPlaying && state.current >= state.duration){ if(this.jumpLoopAnimClip){ this._anim.crossFade(this.jumpLoopAnimClip.name); } } } if(!this._rigidBody){ this._currentVerticalVelocity -= 9.8 * deltaTime; let oldPos = this.node.position; let nextY = oldPos.y + this._currentVerticalVelocity * deltaTime; if (nextY <= 0) { this.onLand(); nextY = 0.0; } this.node.setPosition(oldPos.x, nextY, oldPos.z); } } } onLand(){ this._isInTheAir = false; this._currentVerticalVelocity = 0.0; this._curJumpTimes = 0; if (this.moveAnimClip) { if(this._isMoving){ this._anim.crossFade(this.moveAnimClip.name, 0.5); } else{ this._anim.crossFade(this.idleAnimClip.name, 0.5); } } } private _tmp = v3(); onMovement(degree: number, offset: number) { let cameraRotationY = 0; if (this.mainCamera) { cameraRotationY = this.mainCamera.node.eulerAngles.y; } this._velocityScale = offset; //2D界面是 正X 为 0, 3D场景是 正前方为0,所以需要 - 90 度。(顺时针转90度) this._tmp.set(0, cameraRotationY + degree - 90 + 180, 0); this.node.setRotationFromEuler(this._tmp); if (this._anim) { if (!this._isMoving && !this._isInTheAir) { if (this.moveAnimClip) { this._anim.crossFade(this.moveAnimClip.name, 0.1); } } if (this.moveAnimClip) { this._anim.getState(this.moveAnimClip.name).speed = this._velocityScale; } } this._isMoving = true; } onMovementRelease() { if (!this._isInTheAir && this.idleAnimClip) { this._anim?.crossFade(this.idleAnimClip.name, 0.5); } this._isMoving = false; if (this._rigidBody) { this._rigidBody.setLinearVelocity(Vec3.ZERO); } } onJump(btnName:string) { console.log(btnName); if(btnName != 'btn_slot_0'){ return; } if (this._curJumpTimes >= this.maxJumpTimes) { return; } if(this._curJumpTimes == 0 || true){ if(this.jumpBeginAnimClip){ this._anim?.crossFade(this.jumpBeginAnimClip.name); } } this._curJumpTimes++; if(this._rigidBody){ this._rigidBody.getLinearVelocity(v3_1); v3_1.y = this.jumpVelocity; this._rigidBody.setLinearVelocity(v3_1); } else{ this._currentVerticalVelocity = this.jumpVelocity; } this._isInTheAir = true; } }