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

318 lines
9.8 KiB
TypeScript
Raw Normal View History

2025-02-21 10:45:46 +08:00
import { _decorator, Component, Node, Prefab, Label, Animation, instantiate, Vec3, tween } from 'cc';
import { WoodenManPlayer } from './WoodenManPlayer';
import { ModuleDef } from '../../scripts/ModuleDef';
import { resLoader } from '../../core_tgx/base/utils/ResLoader';
const { ccclass, property } = _decorator;
// 玩家状态
enum PlayerState {
ALIVE, // 存活
DEAD, // 死亡
QUALIFIED // 已晋级
}
// 游戏阶段
export enum GamePhase {
CHOOSE, // 选择阶段
MOVING, // 前进阶段
ROUND_END, // 回合结束
GAME_OVER // 游戏结束
}
// 玩家数据
interface PlayerData {
id: number;
position: number; // 当前位置
state: PlayerState;
selectedSteps: number; // 选择的步数
}
@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; // 存放所有玩家的节点
// 游戏配置
private readonly TOTAL_ROUNDS = 15; // 总回合数
private readonly ROUND_TIME = 20; // 每回合时间(秒)
private readonly TOTAL_DISTANCE = 12; // 终点距离(米)
private readonly MIN_QUALIFIED = 20; // 最少晋级人数
private readonly INITIAL_PLAYERS = 36; // 初始玩家数
private readonly STEP_OPTIONS = [1, 2, 3, 4, 5, 6]; // 可选步数
// 游戏状态
private currentRound = 0;
private currentPhase = GamePhase.CHOOSE;
private remainingTime = 0;
private dollTurnTime = 0; // 娃娃回头时间
private players: Map<number, PlayerData> = new Map();
private aiPlayers: Node[] = []; // AI玩家节点列表
private playerNodes: Map<number, Node> = new Map(); // 所有玩家节点映射
async start() {
await this.initPlayers();
this.initGame();
}
private async initPlayers() {
// 创建本地玩家
const localPlayer = await this.createPlayer(0, true);
this.playerNodes.set(0, localPlayer);
// 创建AI玩家
for (let i = 1; i < this.INITIAL_PLAYERS; i++) {
const aiPlayer = await this.createPlayer(i, false);
this.playerNodes.set(i, aiPlayer);
this.aiPlayers.push(aiPlayer);
}
this.updateAliveCount();
}
private async createPlayer(id: number, isLocal: boolean) {
// 随机位置:以起点为中心,随机分布
const x = Math.random() * 10 - 5; // -5到5
const z = isLocal ? 0 : Math.random() * 4 - 2; // 本地玩家在起点AI随机分布
// 随机角色ID1-5
const roleId = Math.floor(Math.random() * 5) + 1;
const roleIdStr = ('000' + roleId).slice(-3);
const prefab: Prefab = await new Promise<Prefab>((resolve) => {
resLoader.get(`common/role/Character${roleIdStr}`, Prefab, ModuleDef.Arean);
});
if (prefab) {
const role = instantiate(prefab);
this.playersNode.addChild(role);
role.setPosition(new Vec3(x, 0, z));
role.setRotationFromEuler(0, 180, 0);
// 添加玩家组件
const playerComp = role.addComponent(WoodenManPlayer);
playerComp.init(id, isLocal);
return role;
}
return null;
}
// 更新存活人数显示
private updateAliveCount() {
const aliveCount = Array.from(this.players.values())
.filter(p => p.state === PlayerState.ALIVE).length;
this.aliveCountLabel.string = `存活: ${aliveCount}/${this.INITIAL_PLAYERS}`;
}
private initGame() {
// 初始化玩家
for (let i = 0; i < this.INITIAL_PLAYERS; i++) {
this.players.set(i, {
id: i,
position: 0,
state: PlayerState.ALIVE,
selectedSteps: 0
});
}
this.startNewRound();
}
private startNewRound() {
this.currentRound++;
this.remainingTime = this.ROUND_TIME;
this.currentPhase = GamePhase.CHOOSE;
this.dollTurnTime = Math.floor(Math.random() * 6) + 1; // 1-6秒随机
// 重置所有存活玩家的选择
this.players.forEach(player => {
if (player.state === PlayerState.ALIVE) {
player.selectedSteps = 0;
}
});
}
// 玩家选择步数
public playerChooseSteps(playerId: number, steps: number) {
if (this.currentPhase !== GamePhase.CHOOSE) return;
const player = this.players.get(playerId);
if (!player || player.state !== PlayerState.ALIVE) return;
if (this.STEP_OPTIONS.indexOf(steps) !== -1) {
player.selectedSteps = steps;
}
}
// 执行移动阶段
private executeMovingPhase() {
this.currentPhase = GamePhase.MOVING;
// 播放木头人转身动画
this.playDollTurnAnimation(() => {
this.players.forEach((player, id) => {
if (player.state !== PlayerState.ALIVE) return;
const steps = player.selectedSteps || 1;
const playerNode = this.playerNodes.get(id);
if (steps > this.dollTurnTime) {
// 被抓到,播放死亡动画
this.killPlayer(player, playerNode);
} else {
// 移动玩家
this.movePlayer(player, playerNode, steps);
}
});
this.updateAliveCount();
});
}
// 木头人转身动画
private playDollTurnAnimation(callback: () => void) {
const duration = 1.0; // 转身动画持续时间
const currentRotation = this.dollNode.eulerAngles.clone();
const targetRotation = new Vec3(currentRotation.x, currentRotation.y + 180, currentRotation.z);
// 使用 tween 实现平滑旋转
tween(this.dollNode)
.to(duration, { eulerAngles: targetRotation })
.call(callback)
.start();
}
// 玩家死亡效果
private killPlayer(player: PlayerData, playerNode: Node) {
player.state = PlayerState.DEAD;
// 获取玩家组件
const playerComp = playerNode.getComponent(WoodenManPlayer);
if (playerComp) {
playerComp.setAlive(false);
// 播放死亡动画,动画结束后重置位置
playerComp.playDieAnimation(() => {
player.position = 0;
// 重置到起点
playerNode.setPosition(new Vec3(
Math.random() * 10 - 5,
0,
0
));
});
}
}
// 玩家移动效果
private movePlayer(player: PlayerData, playerNode: Node, steps: number) {
const targetPos = new Vec3(
playerNode.position.x,
0,
player.position + steps
);
// 使用 tween 实现平滑移动
tween(playerNode)
.to(steps, { position: targetPos })
.start();
player.position += steps;
if (player.position >= this.TOTAL_DISTANCE) {
player.state = PlayerState.QUALIFIED;
player.position = this.TOTAL_DISTANCE;
// 播放胜利动画
const anim = playerNode.getComponent(Animation);
anim.play('victory');
}
}
// AI决策
private updateAIDecisions() {
if (this.currentPhase !== GamePhase.CHOOSE) return;
this.aiPlayers.forEach(aiNode => {
const playerComp = aiNode.getComponent(WoodenManPlayer);
if (!playerComp || !playerComp.isAlive()) return;
// 简单AI逻辑随机选择1-3步
const steps = Math.floor(Math.random() * 3) + 1;
this.playerChooseSteps(playerComp.getId(), steps);
});
}
// 检查游戏是否结束
private checkGameEnd(): boolean {
let qualifiedCount = 0;
this.players.forEach(player => {
if (player.state === PlayerState.QUALIFIED) {
qualifiedCount++;
}
});
return qualifiedCount >= this.MIN_QUALIFIED || this.currentRound >= this.TOTAL_ROUNDS;
}
// 游戏主循环
update(dt: number) {
if (this.currentPhase === GamePhase.GAME_OVER) return;
this.remainingTime -= dt;
if (this.currentPhase === GamePhase.CHOOSE && this.remainingTime <= 0) {
this.executeMovingPhase();
}
if (this.currentPhase === GamePhase.MOVING) {
// 移动阶段结束后
this.currentPhase = GamePhase.ROUND_END;
if (this.checkGameEnd()) {
this.endGame();
} else {
this.startNewRound();
}
}
// 更新AI决策
this.updateAIDecisions();
}
private endGame() {
this.currentPhase = GamePhase.GAME_OVER;
// 淘汰未晋级玩家
this.players.forEach(player => {
if (player.state !== PlayerState.QUALIFIED) {
player.state = PlayerState.DEAD;
}
});
// 这里可以触发游戏结束事件
this.node.emit('gameOver');
}
// 获取游戏状态
public getGameState() {
return {
currentRound: this.currentRound,
currentPhase: this.currentPhase,
remainingTime: this.remainingTime,
players: Array.from(this.players.values())
};
}
public getCurrentPhase(): GamePhase {
return this.currentPhase;
}
}