2025-03-01 02:24:46 +08:00
|
|
|
|
import { _decorator, Component, Node, Vec3, Prefab, instantiate, Label, Color, tween, SkeletalAnimation } from 'cc';
|
2025-02-21 10:45:46 +08:00
|
|
|
|
import { resLoader } from '../../../core_tgx/base/utils/ResLoader';
|
|
|
|
|
import { ModuleDef } from '../../../scripts/ModuleDef';
|
2025-03-01 02:24:46 +08:00
|
|
|
|
import { UserMgr } from 'db://assets/module_basic/scripts/UserMgr';
|
2025-02-21 10:45:46 +08:00
|
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
|
|
|
|
@ccclass('RoleManager')
|
|
|
|
|
export class RoleManager extends Component {
|
|
|
|
|
@property
|
2025-03-01 02:24:46 +08:00
|
|
|
|
private readonly maxPlayerCount: number = 36; // 人数上限
|
2025-02-21 10:45:46 +08:00
|
|
|
|
|
2025-03-01 02:24:46 +08:00
|
|
|
|
currentPlayerCount: number = 0; // 当前人数
|
|
|
|
|
private roles: Node[] = []; // 存储角色节点
|
2025-02-21 10:45:46 +08:00
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
private readonly minRoleId: number = 1; // 最小角色ID
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
private readonly maxRoleId: number = 5; // 最大角色ID
|
|
|
|
|
|
2025-03-01 02:24:46 +08:00
|
|
|
|
|
|
|
|
|
@property({ type: Label })
|
|
|
|
|
public playerCountLabel: Label; // 显示人数的Label
|
|
|
|
|
|
|
|
|
|
@property({ type: Node })
|
|
|
|
|
public roleManagerNode: Node; // RoleManager 的节点
|
|
|
|
|
|
|
|
|
|
private innerCirclePositions: Vec3[] = []; // 存储内圈角色位置
|
|
|
|
|
private outerCirclePositions: Vec3[] = []; // 存储外圈角色位置
|
2025-02-21 10:45:46 +08:00
|
|
|
|
start() {
|
2025-03-01 02:24:46 +08:00
|
|
|
|
this.initializeRolePositions();
|
|
|
|
|
this.schedule(() => {
|
|
|
|
|
this.createPlayer();
|
|
|
|
|
// 生成0.1到1秒之间的随机间隔(包含两位小数)
|
|
|
|
|
return Math.random() * 0.9 + 0.1;
|
|
|
|
|
}, 0.1); // 初始延迟0.1秒,后续使用随机间隔
|
2025-02-21 10:45:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-01 02:24:46 +08:00
|
|
|
|
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));
|
|
|
|
|
}
|
2025-02-21 10:45:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-01 02:24:46 +08:00
|
|
|
|
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);
|
2025-02-21 10:45:46 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-01 02:24:46 +08:00
|
|
|
|
private createRole() {
|
|
|
|
|
// 随机选择内圈或外圈位置
|
|
|
|
|
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) {
|
|
|
|
|
const role = instantiate(prefab);
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private clearRoles() {
|
|
|
|
|
// 移除所有角色
|
|
|
|
|
this.roles.forEach(role => {
|
|
|
|
|
role.destroy();
|
|
|
|
|
});
|
|
|
|
|
this.roles = []; // 清空角色数组
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private animateNumber(targetCount: number, duration: number) {
|
|
|
|
|
const startCount = parseInt(this.playerCountLabel.string.split('/')[0]); // 获取当前显示的数字
|
|
|
|
|
const tweenObj = { value: startCount };
|
|
|
|
|
|
|
|
|
|
// this.playerCountLabel.string = `${targetCount}/${this.maxPlayerCount}`;
|
|
|
|
|
|
|
|
|
|
tween(tweenObj)
|
|
|
|
|
.to(duration, { value: targetCount }, {
|
|
|
|
|
onUpdate: () => {
|
|
|
|
|
this.playerCountLabel.string = `${Math.round(tweenObj.value)}/${this.maxPlayerCount}`; // 更新显示
|
|
|
|
|
},
|
|
|
|
|
onComplete: () => {
|
|
|
|
|
this.playerCountLabel.string = `${targetCount}/${this.maxPlayerCount}`; // 确保最终值为目标值
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onDestroy() {
|
|
|
|
|
// 停止所有定时器
|
|
|
|
|
this.unscheduleAllCallbacks();
|
|
|
|
|
|
|
|
|
|
// // 停止所有动画
|
|
|
|
|
// this.roles.forEach(role => {
|
|
|
|
|
// const skelAnim = role.getComponentInChildren(SkeletalAnimation);
|
|
|
|
|
// if (skelAnim) {
|
|
|
|
|
// skelAnim.stop(); // 停止动画
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// // 清理角色
|
|
|
|
|
// this.clearRoles();
|
|
|
|
|
|
|
|
|
|
// 停止所有 tween
|
|
|
|
|
tween(this.node).stop();
|
|
|
|
|
}
|
2025-02-21 10:45:46 +08:00
|
|
|
|
}
|