squidGame/tgx-games-client/assets/level1/Script/WoodenManGame.ts

283 lines
9.1 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, Prefab, Label, Animation, instantiate, Vec3, tween, macro } from 'cc';
import { WoodenManPlayer } from './WoodenManPlayer';
const { ccclass, property } = _decorator;
@ccclass('WoodenManGame')
export class WoodenManGame extends Component {
@property(Prefab)
rolePrefab: Prefab = null; // 角色预制体
@property(Node)
dollNode: Node = null; // 木头人节点
@property(Label)
aliveCountLabel: Label = null; // 存活人数显示
@property(Node)
playersNode: Node = null; // 存放所有玩家的节点
@property(Node)
localPlayerNode: Node = null; // 本地玩家节点引用,从场景中获取
@property
private turnAnimationDuration: number = 1.0; // 转身动画持续时间
@property
private turnWarningDuration: number = 0.5; // 转身前警告时间
private readonly TURN_BACK_DELAY = 5; // 转回正面的延迟时间
// 游戏配置
private readonly MIN_QUALIFIED = 20; // 最少晋级人数
private readonly INITIAL_PLAYERS = 36; // 初始玩家数
private aiPlayers: Node[] = []; // AI玩家节点列表
private playerNodes: Map<number, Node> = new Map(); // 所有玩家节点映射
async start() {
await this.initPlayers();
this.scheduleDollTurn(); // 开始娃娃转身定时器
}
private async initPlayers() {
// 初始化本地玩家
if (this.localPlayerNode) {
const playerComp = this.localPlayerNode.addComponent(WoodenManPlayer);
playerComp.init(0, true); // 设置为本地玩家
this.playerNodes.set(0, this.localPlayerNode);
}
// 创建AI玩家
for (let i = 1; i < this.INITIAL_PLAYERS; i++) {
const aiPlayer = await this.createPlayer(i);
this.playerNodes.set(i, aiPlayer);
this.aiPlayers.push(aiPlayer);
}
this.updateAliveCount();
}
private async createPlayer(id: number) {
// 随机位置:起点区域
const x = Math.random() * 15 - 7;
const z = 50 + Math.random() * 5; // 50-55随机
if (this.rolePrefab) {
const role = instantiate(this.rolePrefab);
this.playersNode.addChild(role);
// 设置位置和朝向(面向-Z方向
role.setPosition(new Vec3(x, 0, z));
role.setRotationFromEuler(0, 180, 0);
// 添加 WoodenManPlayer 组件
const playerComp = role.addComponent(WoodenManPlayer);
playerComp.init(id, false);
return role;
}
return null;
}
// 更新存活人数显示
private updateAliveCount() {
let aliveCount = 0;
this.playerNodes.forEach((node) => {
const player = node.getComponent(WoodenManPlayer);
if (player && player.isAlive()) {
aliveCount++;
}
});
this.aliveCountLabel.string = `存活: ${aliveCount}/${this.INITIAL_PLAYERS}`;
}
private scheduleDollTurn() {
const scheduleNextTurn = () => {
// 随机 5-8 秒后转身
const nextTurnDelay = Math.random() * 3 + 3;
this.scheduleOnce(() => {
this.executeTurnBackPhase();
}, nextTurnDelay);
};
// 开始第一次转身循环
scheduleNextTurn();
}
// 执行转身(背对玩家)
private executeTurnBackPhase() {
// 播放转身动画
this.playDollTurnAnimation(() => {
// 触发AI决策
this.aiPlayers.forEach(aiNode => {
const playerComp = aiNode.getComponent(WoodenManPlayer);
if (!playerComp || !playerComp.isAlive() || playerComp.isPassed()) return;
// 在木头人转身后随机延迟开始移动
const startDelay = Math.random() * 0.3 + 0.2; // 0.2-0.5秒延迟
this.scheduleOnce(() => {
if (playerComp.isAlive()) {
playerComp.startMoving();
}
}, startDelay);
});
this.aiPlayers.forEach(aiNode => {
const playerComp = aiNode.getComponent(WoodenManPlayer);
if (!playerComp || !playerComp.isAlive()) return;
const stopDelay = this.TURN_BACK_DELAY + Math.random() * 2 - 1; // 范围改为[-1,1]秒,负值表示转身后触发
this.scheduleOnce(() => {
if (playerComp.isAlive() && playerComp.isMoving) {
playerComp.stopMoving();
}
}, stopDelay);
;
});
this.scheduleOnce(() => {
this.executeTurningPhase();
}, this.TURN_BACK_DELAY);
});
}
// 执行转回(面向玩家)
private executeTurningPhase() {
this.playDollTurnAnimation(() => {
// 检查并处理被抓到的玩家
this.playerNodes.forEach((playerNode, id) => {
const playerComp = playerNode.getComponent(WoodenManPlayer);
// 只检查存活的玩家,跳过已死亡和已到达终点的玩家
if (!playerComp || !playerComp.isAlive()) return;
if (playerComp.isMoving) {
this.killPlayer(playerComp, playerNode);
}
});
});
this.scheduleDollTurn();
}
// 检查游戏是否结束
private checkGameEnd(): boolean {
let qualifiedCount = 0;
this.playerNodes.forEach((playerNode) => {
const playerComp = playerNode.getComponent(WoodenManPlayer);
if (playerComp && playerComp.isPassed()) {
qualifiedCount++;
}
});
return qualifiedCount >= this.MIN_QUALIFIED;
}
// 游戏主循环
update(dt: number) {
// 检查游戏结束条件
if (this.checkGameEnd()) {
this.endGame();
}
}
private endGame() {
// 淘汰未晋级玩家
this.playerNodes.forEach((playerNode) => {
const playerComp = playerNode.getComponent(WoodenManPlayer);
if (playerComp && !playerComp.isPassed()) {
playerComp.setAlive(false);
}
});
// 这里可以触发游戏结束事件
this.node.emit('gameOver');
}
// 获取游戏状态
// 木头人转身动画
private playDollTurnAnimation(callback: () => void) {
this.scheduleOnce(() => {
const currentRotation = this.dollNode.eulerAngles.clone();
const targetRotation = new Vec3(
currentRotation.x,
currentRotation.y + 180,
currentRotation.z
);
tween(this.dollNode)
.to(this.turnAnimationDuration, { eulerAngles: targetRotation }, {
easing: 'quadOut',
onStart: () => {
this.node.parent?.emit('dollTurnStart');
},
onComplete: () => {
this.node.parent?.emit('dollTurnComplete');
if (callback) callback();
}
})
.start();
}, this.turnWarningDuration);
}
// 玩家死亡效果
private killPlayer(playerComp: WoodenManPlayer, playerNode: Node) {
if (!playerComp.isAlive()) return; // 防止重复处理
playerComp.setAlive(false);
this.updateAliveCount(); // 更新存活人数显示
// 播放死亡动画
playerComp.playDieAnimation(() => {
playerComp.stopMoving();
});
}
// 添加到 WoodenManGame 类中
public playerStartMoving(playerId: number) {
const playerNode = this.playerNodes.get(playerId);
if (!playerNode) return;
const playerComp = playerNode.getComponent(WoodenManPlayer);
if (!playerComp || !playerComp.isAlive()) return;
// 持续移动
this.schedule(() => {
if (!playerComp.isAlive()) {
// 如果玩家死亡,停止移动
this.playerStopMoving(playerId);
return;
}
// 检查是否到达终点
if (playerNode.position.z <= -50) {
playerComp.setPassed(true); // 假设WoodenManPlayer有setPassed方法
this.playerStopMoving(playerId);
// AI到达终点后转身
if (playerId !== 0) {
playerNode.setRotationFromEuler(0, 0, 0);
}
return;
}
}, 0, macro.REPEAT_FOREVER, 0);
}
public playerStopMoving(playerId: number) {
// 停止该玩家的移动调度
this.unschedule(this.playerStartMoving);
const playerNode = this.playerNodes.get(playerId);
if (playerNode) {
const playerComp = playerNode.getComponent(WoodenManPlayer);
if (playerComp) {
playerComp.stopMoving();
}
}
}
}