猫史档案馆


🧬【源代码全公开!】圈地之王开发接力挑战

用户:lingyi_objlingyi_obj查看:1 回复:1 评论:1 创建时间:2022-02-01T11:28:04


《圈地之王》

全图没加方块

也无模型

 

究竟怎么做出来的呢?

emotion_编程猫_紧张

下面将代码全部揭秘

全图没加方块

也无模型

 

究竟怎么做出来的呢?

emotion_编程猫_紧张

下面将代码全部揭秘

const MeshScale = [1 / 16, 1 / 16, 1 / 16] //正常的模型缩放比例 const Quat = new Box3Quaternion(0, 0, 0, 1) //默认的旋转状态 const RED = new Box3RGBColor(10, 2, 2) //发光的红色 world.onPress(async ({ entity, button }) => {

 

    if (button === Box3ButtonType.ACTION0) {         const d = entity.player.facingDirection //玩家的朝向         const knife = world.createEntity({             meshScale: MeshScale,             collides: true, // 开启碰撞             gravity: false, // 不受重力影响             position: entity.position, // 在玩家的位置生成飞刀             velocity: d.scale(2), // 飞刀的初速度是玩家朝向向量的2倍             meshOrientation: Quat.rotateY(Math.atan2(d.z, d.x)), // 刀头指向玩家的朝向             particleRate: 20, //每秒发出80个粒子             particleLifetime: 2, //每个粒子存活2秒             particleSize: [2, 2, 2, 2, 2], //粒子在5个阶段的大小都是2             particleColor: [RED, RED, RED, RED, RED], //粒子在5个阶段的颜色都是红色             // particleTarget: entity,             particleVelocity: d.scale(-2),             bounds: [0.2, 0.2, 0.2],// 子弹实体0.2个方块大小         })         knife.id = entity.player.userKey //将小刀的id设置成玩家userKey, 便于碰撞过滤器识别         knife.onEntityContact(({ other }) => {//每当飞刀碰到另一个实体             other.hurt(10)//被碰实体受10点伤害         })         await sleep(2000)//等2秒后         knife.destroy()//清除飞刀, 防止飞刀数量太多超过服务器负载     }

 

})

 

world.onPlayerJoin(({ entity }) => { //当玩家进入地图时     if (entity.player.name === '搬砖喵' || entity.player.name === '吉吉喵') {         entity.addTag('ghost') //本喵不受攻击     }     entity.enableDamage = true //允许这个玩家受伤     entity.id = entity.player.userKey//把userKey作为玩家的id     world.addCollisionFilter('#' + entity.id, '#' + entity.id)//让id跟玩家id一样的实体不会相互碰撞, 比如玩家的飞刀不会碰到玩家, 自己的飞刀之间也不会碰撞 }) world.addCollisionFilter('.ghost', '*')

 

world.onPlayerLeave(({ entity }) => { //当玩家离开地图时     world.removeCollisionFilter('#' + entity.id, '#' + entity.id)//取消这个玩家的碰撞过滤器 })

 

world.onDie(async ({ entity }) => {     await sleep(3000)     entity.hp = entity.maxHp //复活 }) const SECONDS_PER_TICK = 1000 / 128;  const ROUND_TIME = 200 * SECONDS_PER_TICK;//每局游戏时长 const MIN_PLAYERS = 2;//玩家数量下限 const GRID_X = 128; const GRID_Z = 128;

 

const TEAMS = [     { r: 1, g: 0, b: 0, v: voxels.id('red_light'),      n: '红队',       score: 0, },     { r: 0, g: 1, b: 0, v: voxels.id('green_light'),    n: '绿队',     score: 0, },     { r: 0, g: 0, b: 1, v: voxels.id('blue_light'),     n: '蓝队',      score: 0, },     { r: 1, g: 0, b: 1, v: voxels.id('purple'),         n: '紫队',   score: 0, },     { r: 0, g: 1, b: 1, v: voxels.id('indigo_light'),   n: '靛蓝队',      score: 0, },     { r: 1, g: 1, b: 0, v: voxels.id('yellow_light'),   n: '黄队',    score: 0, }, ];

 

// 辅助函数,用于随机打乱一个数组 function shuffle (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; }

 

async function startGame () {     // 将地面初始化,全部变成不锈钢     for (let j = 0; j < GRID_Z; ++j) {         for (let i = 0; i < GRID_X; ++i) {             voxels.setVoxel(i, 8, j, 'stainless_steel');         }     }          // 等待玩家进入     while (world.querySelectorAll('player').length < MIN_PLAYERS) {         world.say('等待其他玩家加入...');         await sleep(1000);         world.say('2个玩家立即开始');         await world.nextPlayerJoin();     }

 

    // 足够玩家加入后,就开始倒计时     for (let i = 3; i > 0; --i) {         world.say(i + '...');         await sleep(1000);     }     world.say('去圈地吧!看谁是圈地之王?');          // 每局都随机打乱队伍     const players = shuffle(world.querySelectorAll('player'));     shuffle(TEAMS);          // 设置玩家的颜色和初始位置     function setTeam (p, t) {         p.player.color.r = t.r;         p.player.color.g = t.g;         p.player.color.b = t.b;         p.position.x = Math.random() * GRID_X;         p.position.y = 30;         p.position.z = Math.random() * GRID_Z;     }

 

    // 获得初始团队     const teams = players.map((p, i) => {         const t = TEAMS[i % TEAMS.length]         setTeam(p, t);         return t;     })          //当玩家接触到地面任意方块时,更新该方块的颜色     const contactHandler = world.onVoxelContact(({ entity, x, y, z }) => {         const idx = players.indexOf(entity);         if (idx < 0) {             return;         }         const t = teams[idx];         voxels.setVoxelId(x, y, z, t.v);     });          // 新玩家加入,会被随机分配到一个队伍     const joinHandler = world.onPlayerJoin(({entity}) => {         const t = TEAMS[(Math.random() * teams.length) | 0];         setTeam(entity, t);         teams.push(t);         players.push(entity)     });          // 每局游戏会在计时到达时结束。     const endTick = world.currentTick + ROUND_TIME;          // 检测游戏是否进行中     function gameInProgress () {         let numActivePlayers = 0;         for (let i = 0; i < players.length; ++i) {             if (!players[i].destroyed) {                 numActivePlayers += 1;             }         }         return world.currentTick < endTick && numActivePlayers >= MIN_PLAYERS;     }          // 通过深度优先搜索,将圈起来的地自动填色     const visited = new Uint8Array(GRID_X * GRID_Z)     const toVisit = []     function mark (i, j, team) {         const idx = i + j * GRID_X;         if (i < 0 || i >= GRID_X ||             j < 0 || j >= GRID_Z ||             visited[idx] ||             voxels.getVoxel(i, 8, j) === team) {             return;         }         visited[idx] = true;         toVisit.push(i, j);     }     function fillHoles (team) {         visited.fill(0);         for (let i = 0; i < Math.max(GRID_X, GRID_Z); ++i) {             mark(i, 0, team);//更正了,将8改成了0             mark(0, i, team);             mark(GRID_X - 1, i, team);             mark(i, GRID_Z - 1, team);         }                  while (toVisit.length > 0) {             const z = toVisit.pop() | 0;             const x = toVisit.pop() | 0;             mark(x - 1, z, team);             mark(x + 1, z, team);             mark(x, z - 1, team);             mark(x, z + 1, team);         }                  let score = 0;         for (let j = 0; j < GRID_Z; ++j) {             for (let i = 0; i < GRID_X; ++i) {                 const idx = i + j * GRID_X;                 if (!visited[idx]) {                     voxels.setVoxelId(i, 8, j, team);                     score += 1;                 }             }         }         return score;     }          // 当游戏运行时     while (gameInProgress()) {         // 等待 1 Tick         await world.nextTick();                  // 计算各队伍的分数         for (let i = 0; i < TEAMS.length; ++i) {             const c = TEAMS[i].score = fillHoles(TEAMS[i].v);                          // 如果有团队圈完全场,那么直接胜出             if (c >= GRID_X * GRID_Z) {                 break;             }         }     }          // 清除事件处理器     contactHandler.cancel();     joinHandler.cancel();

 

    // 重置玩家颜色     for (let i = 0; i < players.length; ++i) {         const c = players[i].player.color;         c.r = c.g = c.b = 1;     }     world.say('本局游戏结束!');     await sleep(5000);          // 宣布获胜队伍     TEAMS.sort((a, b) => b.score - a.score);     world.say(`恭喜 ${TEAMS[0].n} 成为圈地之王!!`);     await sleep(10000); }

 

// 无限循环游戏 async function gameLoop () {     while (true) {         await startGame();         } } gameLoop();

 


回复

上一页1 页 / 共 1下一页
蓝buff蓝buff

发官方帖子干嘛(抄代码

点赞0


评论