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]; // 随机角色ID(1-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); } } }