squidGame/tgx-games-client/assets/module_arean/scripts/common/RoleManager.ts

253 lines
9.8 KiB
TypeScript
Raw Permalink 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, Vec3, Prefab, instantiate, Label, Color, tween, SkeletalAnimation } from 'cc';
import { resLoader } from '../../../core_tgx/base/utils/ResLoader';
import { ModuleDef } from '../../../scripts/ModuleDef';
import { UserMgr } from 'db://assets/module_basic/scripts/UserMgr';
const { ccclass, property } = _decorator;
@ccclass('RoleManager')
export class RoleManager extends Component {
@property
private readonly maxPlayerCount: number = 36; // 人数上限
currentPlayerCount: number = 0; // 当前人数
private roles: Node[] = []; // 存储角色节点
@property
private readonly minRoleId: number = 1; // 最小角色ID
@property
private readonly maxRoleId: number = 5; // 最大角色ID
@property({ type: Label })
public playerCountLabel: Label; // 显示人数的Label
@property({ type: Node })
public roleManagerNode: Node; // RoleManager 的节点
private innerCirclePositions: Vec3[] = []; // 存储内圈角色位置
private outerCirclePositions: Vec3[] = []; // 存储外圈角色位置
start() {
try {
// 确保 roles 数组存在
if (!this.roles) {
this.roles = [];
}
this.initializeRolePositions();
this.schedule(() => {
this.createPlayer();
return Math.random() * 0.9 + 0.1;
}, 0.1);
} catch (error) {
console.error('Error in RoleManager start:', error);
this.unscheduleAllCallbacks(); // 出错时确保清理定时器
}
}
private initializeRolePositions() {
const innerRadius = 4.5; // 内圈半径
const outerRadius = 6; // 外圈半径
const innerCount = 20; // 内圈角色数量
const outerCount = 16; // 外圈角色数量
// 生成内圈位置
const innerAngleStep = 360 / innerCount;
for (let i = 0; i < innerCount; i++) {
const angle = i * innerAngleStep;
const angleInRadians = angle * Math.PI / 180;
const x = Math.sin(angleInRadians) * innerRadius;
const z = Math.cos(angleInRadians) * innerRadius;
this.innerCirclePositions.push(new Vec3(x, 0, z));
}
// 生成外圈位置
const outerAngleStep = 360 / outerCount;
for (let i = 0; i < outerCount; i++) {
const angle = i * outerAngleStep;
const angleInRadians = angle * Math.PI / 180;
const x = Math.sin(angleInRadians) * outerRadius;
const z = Math.cos(angleInRadians) * outerRadius;
this.outerCirclePositions.push(new Vec3(x, 0, z));
}
}
private createPlayer() {
if (this.currentPlayerCount < this.maxPlayerCount) {
this.currentPlayerCount++;
this.animateNumber(this.currentPlayerCount, 0.8); // 动画更新人数
this.createRole(); // 创建角色
if (this.currentPlayerCount >= this.maxPlayerCount) {
{
this.scheduleOnce(() => {
this.clearRoles(); // 清除角色
this.currentPlayerCount = 0;
this.animateNumber(this.currentPlayerCount, 0.8); // 动画更新人数 // 清零
}, 10);
}
}
}
}
private createRole() {
// 确保 roles 数组存在
if (!this.roles) {
this.roles = [];
}
// 随机选择内圈或外圈位置
const isInnerCircle = Math.random() < 0.5; // 50% 概率选择内圈
const positions = isInnerCircle ? this.innerCirclePositions : this.outerCirclePositions;
// 随机选择一个未使用的位置
const availablePositions = positions.filter(pos =>
!this.roles.some(role => Vec3.equals(role.position, pos))
);
if (availablePositions.length === 0) return;
const randomIndex = Math.floor(Math.random() * availablePositions.length);
const position = availablePositions[randomIndex];
// 随机角色ID1-5
const roleId = Math.floor(Math.random() * (this.maxRoleId - this.minRoleId + 1)) + this.minRoleId;
const roleIdStr = ('000' + roleId).slice(-3);
resLoader.load(ModuleDef.Arean, `common/role/Character${roleIdStr}`, (err: Error | null, prefab: Prefab) => {
if (!err && prefab) {
try {
const role = instantiate(prefab);
if (role && this.node && this.node.isValid) {
role.setParent(this.node);
role.setPosition(position);
this.roles.push(role);
// 获取动画组件
const skelAnim = role.getComponentInChildren(SkeletalAnimation);
//skelAnim.crossFade("player_jump1", 0.5);
skelAnim.crossFade("player_idle1", 0.5);
skelAnim.once(SkeletalAnimation.EventType.FINISHED, () => { skelAnim.crossFade("player_idle1", 0.5); }, this);
// 计算朝向中心点的方向
const forward = new Vec3();
Vec3.subtract(forward, new Vec3(0, 0, 0), position);
forward.normalize();
// 设置角色朝向
const euler = new Vec3(0, Math.atan2(forward.x, forward.z) * 180 / Math.PI, 0);
role.eulerAngles = euler;
// 添加角色名字NameLabel
const nameLabel = role.getChildByName("NameLabel");
if (nameLabel) {
const labelComponent = nameLabel.getComponent(Label);
if (labelComponent) {
labelComponent.string = `player${this.currentPlayerCount}`;
labelComponent.color = new Color(255, 255, 255, 255);
}
}
}
} catch (error) {
console.error('Error creating role:', error);
}
}
});
}
private clearRoles() {
// 移除所有角色前先停止它们的动画和 tween
this.roles.forEach(role => {
if (!role || !role.isValid) return;
try {
// 停止 tween
tween(role).stop();
// 停止动画
const skelAnim = role.getComponentInChildren(SkeletalAnimation);
if (skelAnim && skelAnim.isValid) {
skelAnim.stop();
}
role.destroy();
} catch (error) {
console.error('Error cleaning up role:', error);
}
});
this.roles = [];
}
private animateNumber(targetCount: number, duration: number) {
try {
const startCount = parseInt(this.playerCountLabel.string.split('/')[0]);
const tweenObj = { value: startCount };
// 停止之前的 tween
tween(tweenObj).stop();
tween(tweenObj)
.to(duration, { value: targetCount }, {
onUpdate: () => {
if (this.playerCountLabel && this.playerCountLabel.isValid) {
this.playerCountLabel.string = `${Math.round(tweenObj.value)}/${this.maxPlayerCount}`;
}
},
onComplete: () => {
if (this.playerCountLabel && this.playerCountLabel.isValid) {
this.playerCountLabel.string = `${targetCount}/${this.maxPlayerCount}`;
}
}
})
.start();
} catch (error) {
console.error('Error in animateNumber:', error);
// 出错时直接设置最终值
if (this.playerCountLabel && this.playerCountLabel.isValid) {
this.playerCountLabel.string = `${targetCount}/${this.maxPlayerCount}`;
}
}
}
onDestroy() {
try {
// 停止所有定时器
this.unscheduleAllCallbacks();
// 确保 roles 数组存在且有效
if (this.roles) {
this.roles.forEach(role => {
if (role && role.isValid) {
try {
// 停止 tween
tween(role).stop();
// 停止动画
const skelAnim = role.getComponentInChildren(SkeletalAnimation);
if (skelAnim && skelAnim.isValid) {
skelAnim.stop();
}
// 停止名字标签的 tween
const nameLabel = role.getChildByName("NameLabel");
if (nameLabel && nameLabel.isValid) {
tween(nameLabel).stop();
}
role.destroy();
} catch (error) {
console.error('Error cleaning up role:', error);
}
}
});
}
this.roles = [];
// 停止计数器动画
if (this.playerCountLabel && this.playerCountLabel.isValid) {
tween(this.playerCountLabel.node).stop();
}
} catch (error) {
console.error('Error in RoleManager onDestroy:', error);
}
}
}