用户:
UP主終黙查看:0 回复:3 评论:0 创建时间:2022-11-09T11:07:41
// ------------配置------------
const DEFAULT_WEAPON = 'UZI'; // 初始武器
// 队伍配置
const TEAM_CONFIG = {
'红队': {
spawnPoint: '红队出生点', // 出生点实体名称
color: new Box3RGBColor(1, 0, 0), // 颜色
},
'黄队': {
spawnPoint: '黄队出生点',
color: new Box3RGBColor(1, 1, 0),
},
};
// 武器配置
const WEAPON = {
'S686': {
damage: 50, // 伤害
distance: 10, // 射程距离
interval: 10, // 发射间隔(数值越大, 射速越慢)
orientation: new Box3Quaternion(0, 1, 0, 0).rotateZ(-Math.PI / 2), // 装备方向
},
'UZI': {
damage: 10,
distance: 30,
interval: 0,
orientation: new Box3Quaternion(0, 1, 0, 0).rotateZ(-Math.PI / 2),
},
'AWM': {
damage: 100,
distance: 1000,
interval: 100,
orientation: new Box3Quaternion(0, 1, 0, 0).rotateZ(-Math.PI / 2).rotateX(Math.PI),
},
'神之刃': {
damage: 10000, // 伤害
distance: 1000000, // 射程距离
interval: 0, // 发射间隔(数值越大, 射速越慢)
orientation: new Box3Quaternion(0, 1, 0, 0).rotateZ(-Math.PI / 2), // 装备方向
},
};
const GAME_END_TIME = 10 * 60; // 游戏结束时间, 单位秒
const GAME_END_SCORE = 30; // 游戏结束分数
const MIN_GAME_PLAYER_NUM = 2; // 最小游戏人数
const GAME_HALFTIME = 5; // 两局游戏间隔时间, 单位秒
// ----------------------------
const spawnPoint = objectMap(TEAM_CONFIG, ({spawnPoint}, team) => {
const e = world.querySelector('#' + spawnPoint);
e.onEntityContact(({entity, other}) => {
if (!other.isPlayer) return; // 不处理非玩家的碰撞
const { name } = other.player;
if (!(name in playerState)) return; // 不处理非游戏中玩家的碰撞
if (playerState[name].team === team) {
// 碰到自家出生点恢复全部HP
if (other.hp < other.maxHp) {
other.hp = other.maxHp;
other.player.directMessage('你回复了全部的HP');
}
} else {
// 碰到非自家出生点, HP减半
other.hurt(Math.ceil(other.hp / 2), { attacker: entity });
}
});
return e.position.clone(); // 返回出生点位置
});
const defaultWeaponMesh = world.querySelector('#' + DEFAULT_WEAPON).mesh;
let playerState = {}; // 玩家状态
let teamScore = {}; // 队伍分数
let teamNum = {}; // 队伍人数
let gameEndResolve; // 用于结束游戏的函数
// 主函数
(async function main() {
// 打印开始时间的日志
console.log(`-------[${new Date().toISOString()}]--------`)
setup(); // 初始化
// 主循环, 不断检测并开始新的游戏
for(;;await sleep(GAME_HALFTIME * 1000)) {
// 检测人数
if (world.querySelectorAll('player').length < MIN_GAME_PLAYER_NUM) {
world.say(`当前人数不足${MIN_GAME_PLAYER_NUM}人, 无法开始游戏!`);
continue;
}
// 倒计时
world.say(`游戏即将开始!`);
for (let i = 0; i > 0; i--) {
await sleep(1000);
world.say(`${i}...`);
}
// 开始新的一局游戏
await start();
}
})();
// 开始游戏
async function start() {
console.log(`[${new Date().toISOString()}]开始新的一局游戏`);
// 清空分数和队伍人数
teamScore = objectMap(TEAM_CONFIG, () => 0);
teamNum = objectMap(TEAM_CONFIG, () => 0);
// 获取队伍名称
const teamNames = Object.keys(TEAM_CONFIG);
// 打乱所有玩家并执行队伍分配
arrayShuffle(world.querySelectorAll('player')).forEach((entity, i) => {
const teamName = teamNames[i % teamNames.length];
joinTeam(entity, teamName);
entity.player.directMessage(`你被分配到了${teamName}`);
});
// 等待游戏结束
await new Promise(async (resolve) => {
gameEndResolve = resolve; // 设置游戏结束函数
await sleep(GAME_END_TIME * 1000); // 等待GAME_END_TIME秒
resolve(); // 如果游戏没有提前结束, 就会由于到时间而结束
});
// 广播获胜队伍
const winner = getMaxScore();
world.say(`${winner}胜利, 总分: ${teamScore[winner]}`);
let maxKd = 0; // 最高的kd
let maxKdPlayer; // 最高kd的玩家
// 计算每个玩家的KD并记录最高值
for (const name in playerState) {
const { entity, k, d } = playerState[name];
const kd = k / (d + 1); // 计算公式: 击杀数/(喵数+1)
// 告知每个玩家本局的kd
entity.player.directMessage(`你本场游戏的评分为${kd.toFixed(2)}`);
// 更新最大kd
if (kd > maxKd) {
maxKd = kd;
maxKdPlayer = name;
}
// 喵家设置为非游戏状态
entity.enableDamage = false;
entity.player.cameraMode = 'FOLLOW';
entity.player.color.set(1, 1, 1);
}
// 广播MVP(kd最高者)
world.say(`本场游戏MVP为@${maxKdPlayer}, 评分是${maxKd.toFixed(2)}`);
// 清空玩家状态和结束函数
playerState = {};
gameEndResolve = undefined;
}
// 加入队伍
function joinTeam(entity, team) {
teamNum[team]++; // 队伍人数+1
// 设置玩家属性
entity.enableDamage = true;
entity.player.cameraMode = 'FPS';
entity.player.color.copy(TEAM_CONFIG[team].color);
// 初始化玩家状态
playerState[entity.player.name] = {
team,
entity,
喵: DEFAULT_WEAPON,
shootTick: 0,
k: 0,
d: 0,
};
// 装备武器
entity.player.addWearable({
bodyPart: Box3BodyPart.RIGHT_HAND, // 装备在右手上
mesh: defaultWeaponMesh, // 设置武器mesh
orientation: WEAPON[DEFAULT_WEAPON].orientation, // 调整方向
scale: new Box3Vector3(0.3, 0.4, 0.2), // 调整大小
offset: new Box3Vector3(0, -0.5, 0), //调整位置
});
entity.position.copy(spawnPoint[team]); // 传送到队伍的出生点
entity.position.y = 10 + Math.random() * 20; // 随机增加y的偏移, 避免多个玩家相撞
entity.player.spawnPoint.copy(entity.position); // 设置出生点
}
// 判断是否是游戏中的玩家
function isPlayer(entity) {
return entity && entity.isPlayer && entity.player.name in playerState;
}
// 获取最高分的队伍名称
function getMaxScore() {
let num = 0;
let team;
for (const key in teamScore) {
if (teamScore[key] > num) {
team = key;
num = teamScore[key];
}
}
return team;
}
// 获取最低分的队伍名称
function getMinTeam() {
let num = Infinity;
let team;
for (const key in teamNum) {
if (teamNum[key] < num) {
team = key;
num = teamNum[key];
}
}
return team;
}
// 初始化
function setup() {
// 处理喵
world.onDie(({entity, attacker}) => {
if (!attacker || !isPlayer(entity)) return; // 不处理出无击杀者的喵和非玩家的喵
// 获取喵玩家名称和击杀者名称
const { name } = entity.player;
const killerName = attacker.isPlayer ? attacker.player.name : attacker.id;
playerState[name].d++; // 喵数+1
// 广播喵情况
world.say(`@${killerName}击败了@${name}, 当前比分${Object.keys(teamScore).map((name) => `${name}:${teamScore[name]}`).join(', ')}`);
// 如果击杀者是玩家
if (attacker.isPlayer) {
playerState[killerName].k++; // 击杀数+1
teamScore[playerState[killerName].team]++; // 队伍分数+1
// 判断是否达到比赛结束的比分
if (teamScore[playerState[killerName].team] >= GAME_END_SCORE) gameEndResolve();
}
});
// 初始化玩家
world.onPlayerJoin(({ entity }) => {
if (gameEndResolve) {
// 游戏已经开始, 则加入人数组少的队伍
const team = getMinTeam()
joinTeam(entity, team);
world.say(`玩家@${entity.player.name}加入${team}`);
}
// 处理玩家鼠标点击
entity.player.onPress(({ tick, entity, button, raycast: { hitEntity, direction, distance } }) => {
// 喵后点鼠标重生
if (isPlayer(entity) && entity.hp === 0) {
return entity.player.forceRespawn();
}
// 判断是否是鼠标左键, 击中实体是否是玩家, 以及击中的玩家是否喵
if (button === 'action0' && isPlayer(entity) && isPlayer(hitEntity) && !hitEntity.dead) {
// 获取双方的状态
const state = playerState[entity.player.name];
const otherState = playerState[hitEntity.player.name];
if (state.team === otherState.team) return; // 相同队伍不处理
const 喵 = WEAPON[state.喵]; // 获取武器信息
if (state.shootTick + 喵.interval > tick) return; // 小于武器间隔事件不处理
state.shootTick = tick; // 更新射击时间(tick)
// 设置击中效果
hitEntity.velocity.x += direction.x;
//hitEntity.velocity.y += 2;
hitEntity.velocity.z += direction.z;
// 计算伤害并应用
const basicDamage = Math.max(1, 喵.damage * Math.min(1, 喵.distance / distance));
const damage = Math.ceil(basicDamage * (1 + Math.random() * 0.3));
hitEntity.hurt(damage, { attacker: entity });
}
});
});
// 获取武器
world.onEntityContact(({ entity, other }) => {
// 必须是玩家触碰武器
if (isPlayer(entity) && other.id in WEAPON) {
const state = playerState[entity.player.name]; // 获取玩家状态
if (!other.hasTag(state.team)) return; // 检查队伍
state.喵 = other.id; // 设置武器
entity.player.directMessage(`你获得了${other.id}`); // 通知玩家
// 更新装备
const handWearable = entity.player.wearables(Box3BodyPart.RIGHT_HAND)[0];
handWearable.mesh = other.mesh;
handWearable.orientation = WEAPON[other.id].orientation;
}
});
// 收到伤害的通知
world.onTakeDamage(({entity, damage, attacker}) => {
if (!entity.isPlayer) return;
const attackerName = attacker.isPlayer ? attacker.player.name : attacker.id;
entity.player.directMessage(`[剩余HP: ${entity.hp}]: 你受到了${damage}点来自@${attackerName}的伤害`);
});
}
// 随机打乱数组
function arrayShuffle (array) {
for (let i = 1; i < array.length; ++i) {
const temp = array[i];
const x = (Math.random() * (i + 1)) | 0;
array[i] = array[x];
array[x] = temp;
}
return array;
}
// 为对象实现类似数组的map功能
function objectMap(obj, func) {
const o = {};
for (const key in obj) {
o[key] = func(obj[key], key);
}
return o;
}
world.onPlayerJoin(({ entity }) => {//飞行特权代码(一开始就是)
const TEST_PLAYER = [ '诡喵喵喵', '青莲宗.秀儿_琦玉的徒弟']//白名单
if (!TEST_PLAYER.includes(entity.player.name)) return;
entity.player.canFly = true;
});
world.onPress(async ({ entity, button }) => {
if (button === Box3ButtonType.ACTION1) {
if (entity.f) {
entity.f = false;;
for (let i = 0.1; i <= 0.45; i += 0.001) {
await sleep(1);
entity.player.cameraFovY = i;
}
} else if (!entity.f) {
entity.f = true;
for (let i = 0.45; i >= 0.1; i -= 0.001) {
await sleep(1);
entity.player.cameraFovY = i;
}
}
}
});
var admin = ['诡喵喵喵', '青莲宗.秀儿_琦玉的徒弟']
world.onChat(({ entity, message }) => {
if (admin.includes(entity.player.name)) {
if (message == '变大') {
entity.player.scale += 5;
world.say(entity.player.name + '变大了')
}
if (message == '变小') {
entity.player.scale += -0.5;
world.say(entity.player.name + '变小了')
}
if (message == '还原大小') {
entity.player.scale = 1;
world.say(entity.player.name + '还原了大小')
}
if (message == '五灵飞甲') {
entity.player.canFly = true;
world.say(entity.player.name + '开启了飞行模式')
}
if (message == '解除飞行'){
entity.player.canFly = false;
world.say(entity.player.name + '关闭了飞行模式')
}
if (message == '加速') {
entity.player.walkSpeed = 100
entity.player.runSpeed = 100
entity.player.flySpeed = 100
entity.player.swimSpeed = 100
world.say(entity.player.name + '加速了')
}
if (message == '隐身') {
entity.player.invisible = true;
world.say(entity.player.name + '隐身了')
}
if (message == '现身') {
entity.player.invisible = false;
world.say(entity.player.name + '现身了')
}
if (message == '隐藏名字') {
entity.player.showName = false;
world.say(entity.player.name + '隐藏了名字')
}
if (message == '显示名字') {
entity.player.showName = true;
world.say(entity.player.name + '显示了名字')
}
if (message == '幽灵') {
entity.player.spectator = true;
world.say(entity.player.name + '开启了幽灵模式')
}
if (message == '解除幽灵') {
entity.player.spectator = false;
world.say(entity.player.name + '关闭了幽灵模式')
}
if (message == '发光') {
entity.player.emissive = 1;//数值可调整
world.say(entity.player.name + '开启了发光效果')
}
if (message == '还原发光') {
entity.player.emissive = 0;
world.say(entity.player.name + '还原了发光效果')
}
if (message == '反光') {
entity.player.shininess = 1; world.say(entity.player.name + '开启了反光效果')
}
if (message == '还原反光') {
entity.player.shininess = 0;
world.say(entity.player.name + '还原了反光效果')
}
if (message == '变红色') {
entity.player.color.set(1, 0, 0);//JS(1,0,0)表示红色,数字组合表示颜色
world.say(entity.player.name + '变成了红色')
}
if (message == '变蓝色') {
entity.player.color.set(0, 0, 1);
world.say(entity.player.name + '变成了蓝色')
}
if (message == '变绿色') {
entity.player.color.set(0, 1, 0);
world.say(entity.player.name + '变成了绿色')
}
if (message == '变紫色') {
entity.player.color.set(1, 0, 1);
world.say(entity.player.name + '变成了紫色')
}
if (message == '变黄色') {
entity.player.color.set(1, 1, 0);
world.say(entity.player.name + '变成了黄色')
}
if (message == '变浅蓝色') {
entity.player.color.set(0, 1, 1);
world.say(entity.player.name + '变成了浅蓝色')
}
if (message == '还原颜色') {
entity.player.color.set(1, 1, 1);
world.say(entity.player.name + '还原了颜色')
}
if (message == '全部还原') {
entity.player.scale = 1;
entity.player.canFly = false;
entity.player.showName = true;
entity.player.spectator = false;
entity.player.invisible = false;
entity.player.emissive = 0;
entity.player.shininess = 0;
entity.player.color.set(1, 1, 1);
Object.assign(entity, { particleRate: 250, });
world.say(entity.player.name + '全部还原了');
};
if (message == '清屏') {
for (let x = 0; x < 300; x++) {
world.say('')
}
}
if (message == '关闭粒子特效') {
Object.assign(entity, { particleRate: 0, });
world.say(entity.player.name + '关闭了粒子特效');
}
if (message == '开启粒子特效') {
Object.assign(entity, { particleRate: 100, });
world.say(entity.player.name + '开启了粒子特效');
}
}
})