squidGame/tgx-games-client/assets/module_arean/level1/Script/WoodenManPlayer.ts

398 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { _decorator, Component, Node, SkeletalAnimation, Input, EventTouch, input, Label, Button, Vec3, tween, Animation, Prefab, instantiate } from 'cc';
import { WoodenManGame } from './WoodenManGame';
import { CameraManager } from './CameraManager';
import { resLoader } from 'db://assets/core_tgx/base/utils/ResLoader';
import { ModuleDef } from 'db://assets/scripts/ModuleDef';
import { tgxAudioMgr } from 'db://assets/core_tgx/tgx';
import { EMusicDefine } from 'db://assets/module_basic/scripts/MusicDefine';
const { ccclass, property } = _decorator;
/** 玩家状态 */
enum EPlayerState {
IDLE,
WALK,
RUN,
DIE,
VICTORY
}
@ccclass('WoodenManPlayer')
export class WoodenManPlayer extends Component {
private id: number = 0;
private game: WoodenManGame;
private alive: boolean = true;
private passed: boolean = false;
isLocalPlayer: boolean = false;
private animator: SkeletalAnimation = null;
public isMoving: boolean = false;
private hasPlayedDieAnimation: boolean = false;
private moveTimer: number = 0; // 添加移动计时器
private readonly RUN_SPEED = 6; // 跑步速度
private _playerState: EPlayerState = EPlayerState.IDLE;
private isButtonPressed: boolean = false;
@property(CameraManager)
private cameraManager: CameraManager = null;
init(id: number, isLocal: boolean, game: WoodenManGame) {
this.id = id;
this.game = game;
this.isLocalPlayer = isLocal;
this.animator = this.getComponentInChildren(SkeletalAnimation);
if (!this.animator) {
console.error(`Player ${id} 缺少 SkeletalAnimation 组件`);
} else {
const idleState = this.animator.getState('player_idle1');
if (idleState && this._playerState === EPlayerState.IDLE) {
this.animator.crossFade('player_idle1', 0.3);
}
}
}
getId(): number {
return this.id;
}
isAlive(): boolean {
return this.alive;
}
isPassed(): boolean {
return this.passed;
}
setAlive(alive: boolean) {
if (this.alive === alive) return;
this.alive = alive;
if (!alive) {
// 确保停止所有运动和动画
this.isMoving = false;
this.isButtonPressed = false;
// 停止当前节点的 tween
tween(this.node).stop();
// 重置状态
this._playerState = EPlayerState.DIE;
// 切换到死亡摄像机
if (this.isLocalPlayer && this.cameraManager) {
this.cameraManager.switchToDeadCamera(this.node.worldPosition);
}
// 播放死亡 GUI 动画
if (this.isLocalPlayer) {
resLoader.load(ModuleDef.Arean, 'common/prefabs/settlement', (err: Error | null, prefab: Prefab) => {
if (!err && prefab) {
const n = instantiate(prefab);
this.game.guiNode.addChild(n);
n.getComponent(Animation).play("showLose");
}
});
}
}
}
setPassed(value: boolean) {
this.passed = value;
}
// 播放死亡动画
playDieAnimation() {
if (this.hasPlayedDieAnimation) return;
this.hasPlayedDieAnimation = true;
// 播放音效
tgxAudioMgr.inst.playOneShot(EMusicDefine.GUN, 1, ModuleDef.BASIC);
tgxAudioMgr.inst.playOneShot(EMusicDefine.WOODENMANDIE, 1, ModuleDef.BASIC);
// 加载并播放死亡特效
resLoader.load(ModuleDef.Arean, 'common/prefabs/hit001', (err: Error | null, prefab: Prefab) => {
if (!err && prefab) {
const effectNode = instantiate(prefab);
this.node.addChild(effectNode);
effectNode.setPosition(new Vec3(0, 1, 0)); // 稍微抬高一点,让特效更明显
}
});
if (this._getAnimator()) {
// 转向动画
const state = this.animator.getState('player_die');
if (state) {
state.wrapMode = 1; // 1 表示只播放一次
this.animator.crossFade('player_die', 0.3);
// 动画结束后确保停止
state.once(SkeletalAnimation.EventType.FINISHED, () => {
this.animator.stop();
});
}
}
}
// 播放胜利动画
playVictoryAnimation() {
// if (this.animator) {
// // 胜利动画带过渡
// this.animator.crossFade('victory', 0.5);
// }
}
// 播放行走动画
playWalkAnimation() {
if (this._getAnimator()) {
const state = this.animator.getState('player_walk');
if (state) {
this._playerState = EPlayerState.WALK;
state.wrapMode = 2; // 2 表示循环模式
//this.animator.play('player_walk');
this.animator.crossFade('player_walk', 0.3);
}
}
}
// 播放跑步动画
playRunAnimation() {
if (this._getAnimator()) {
const state = this.animator.getState('player_run');
if (state) {
this._playerState = EPlayerState.RUN;
state.wrapMode = 2; // 2 表示循环模式
//this.animator.play('player_run');
this.animator.crossFade('player_run', 0.3);
}
}
}
// 停止移动c
stopMoving() {
this.isMoving = false;
if (this._getAnimator()) {
const game = this.game as WoodenManGame;
if (game.getIsDollTurning()) {
// 如果娃娃正在转身,只改变动画速度
const runState = this.animator.getState('player_run');
if (runState?.isPlaying) {
runState.speed = 0;
} else {
// 如果跑步动画没有播放,可能需要先播放再暂停
this.animator.crossFade('player_run', 0.1);
this.scheduleOnce(() => {
const state = this.animator.getState('player_run');
if (state) state.speed = 0;
}, 0.1);
}
} else {
// 如果娃娃还没开始转身,切换到待机动画
this.animator.crossFade('player_idle1', 0.2);
}
}
}
// 添加 setter 方法
setButtonPressed(pressed: boolean) {
this.isButtonPressed = pressed;
}
private _getAnimator() {
if (!this.animator) {
this.animator = this.getComponentInChildren(SkeletalAnimation);
if (!this.animator) {
console.error(`Player ${this.id} 缺少 SkeletalAnimation 组件`);
}
}
return this.animator;
}
public startMoving() {
if (!this.isAlive() || this.isPassed()) return;
this.isMoving = true;
if (this._getAnimator()) {
const game = this.game as WoodenManGame;
const runState = this.animator.getState('player_run');
runState.speed = 1;
if (game.getIsDollTurning()) {
// 如果娃娃正在转身,需要确保动画正确播放
this.animator.crossFade('player_run', 0.1);
} else {
// 如果娃娃还没开始转身,正常播放跑步动画
this.playRunAnimation();
}
this._playerState = EPlayerState.RUN;
}
}
update(dt: number) {
if (!this.game.getGameStarted()) return;
if (this.isMoving) {
this.moveTimer += dt;
// 直接使用跑步速度
const newPos = this.node.position.clone();
newPos.z -= this.RUN_SPEED * dt;
this.node.setPosition(newPos);
if (this.node.position.z <= -49.5) {
this.handleFinishLine();
}
}
}
// 添加处理终点线的方法
private handleFinishLine() {
if (!this.isPassed()) {
this.game.qualifiedCount++;
this.setPassed(true);
// 同时旋转角色和摄像机
const duration = 1.0; // 转身动画持续时间
// 角色转身动画
tween(this.node)
.to(duration, {
eulerAngles: new Vec3(0, 0, 0)
}, {
easing: 'quadOut'
})
.start();
// 如果是本地玩家,执行摄像机旋转
if (this.isLocalPlayer && this.cameraManager) {
const camera = this.cameraManager.defaultCamera;
if (camera) {
// 保存摄像机初始位置
const startPos = camera.position.clone();
const centerPos = this.node.position.clone();
centerPos.y += 1.5; // 调整旋转中心点高度
// 计算摄像机到角色的距离和高度差
const radius = Vec3.distance(
new Vec3(startPos.x, centerPos.y, startPos.z),
centerPos
);
const heightOffset = startPos.y - centerPos.y;
// 执行摄像机环绕动画
tween(camera)
.to(duration, {
position: new Vec3(
centerPos.x,
centerPos.y + heightOffset,
centerPos.z - radius
)
}, {
easing: 'quadOut',
onUpdate: (target: Node, ratio: number) => {
// 计算当前角度
const angle = Math.PI * ratio;
const x = centerPos.x + Math.sin(angle) * radius;
const z = centerPos.z + Math.cos(angle) * radius;
// 更新摄像机位置
target.setPosition(x, centerPos.y + heightOffset, z);
// 始终看向角色
target.lookAt(centerPos);
}
})
.start();
}
}
// 播放晋级动画
if (this.isLocalPlayer && this.game.guiNode) {
resLoader.load(ModuleDef.Arean, 'common/prefabs/settlement', (err: Error | null, prefab: Prefab) => {
if (!err && prefab) {
const n = instantiate(prefab);
this.game.guiNode.addChild(n);
n.getComponent(Animation).play("showWin");
}
});
}
this.game.updateWinCount();
if (this.game.qualifiedCount >= this.game.REQUIRED_QUALIFIED) {
this.game.endGame('达到晋级人数要求!游戏结束');
}
}
// 停止移动并播放待机动画
this.stopMoving();
if (this._getAnimator()) {
const idleState = this.animator.getState('player_idle1');
if (idleState) {
idleState.speed = 1;
this.animator.crossFade('player_idle1', 0.3);
}
}
}
// 添加 getter 方法
public getIsLocalPlayer(): boolean {
return this.isLocalPlayer;
}
// 添加一个方法来检查玩家是否应该被击杀
public shouldBeKilled(): boolean {
// 如果玩家已经停止移动,就不应该被击杀
if (!this.isMoving) return false;
// 如果玩家按住了按钮,也不应该被击杀
if (this.isButtonPressed) return false;
// 如果玩家的动画速度为0已经停止也不应该被击杀
if (this._getAnimator()) {
const runState = this.animator.getState('player_run');
if (runState?.isPlaying && runState.speed === 0) {
return false;
}
}
// 其他情况下,如果在移动就应该被击杀
return true;
}
// 修改清理方法
public cleanup() {
// 停止所有定时器
this.unscheduleAllCallbacks();
// 停止所有 tween
if (this.node) {
tween(this.node).stop();
}
// 停止动画
if (this.animator && this.animator.isValid) {
try {
this.animator.stop();
} catch (error) {
console.warn('Failed to stop animator:', error);
}
}
// 重置状态
this.isMoving = false;
this.isButtonPressed = false;
this.hasPlayedDieAnimation = false;
}
onDestroy() {
try {
this.cleanup();
} catch (error) {
console.warn('Error during WoodenManPlayer cleanup:', error);
}
}
}