猫史档案馆


【box3教程贴】如何做出无尽的僵尸?

用户:Vicent轩Vicent轩查看:4 回复:3 评论:4 创建时间:2020-08-28T16:26:35


总所周知

吉吉喵公布的僵尸代码打完就没了

那如何让他打完就再生成一次呢?

首先我们分析一下代码:

在一开始就有一行注释说:

//把生成僵尸的代码封装成函数

那么这个函数(spawn)里的代码

包含了一个僵尸的全部的代码,比如生成出僵尸模型

那么下面有几行代码:

for (let i = 0; i < 30; i++) {//开局生成一堆僵尸
    spawn()
}

他实现的功能是重复执行30次执行函数spawn

讲到这,我们已经知道他是怎么复制僵尸了

只要在打完僵尸之后执行这个语句就OK

那么怎么判断僵尸打完了呢?

我们可以用变量(这里示例变量名为mb【目标】)来记录

在复制僵尸时,加上这样一句代码变成这样:

for (let i = 0; i < 30; i++) {//开局生成一堆僵尸
    spawn()
    mb = (typeof mb == 'number' ? mb : 0) + 1;
}

这样就可以知道复制了多少个僵尸

当然你也可以不这么做,直接在这个for循环后面加个mb=30

然后,在定义函数里面的实体喵亡这部分里面用一个变量(示例变量喵【杀灭】)记录击杀的僵尸个数

当有一个实体喵亡时,就把喵这个变量的值+1

然后判断,喵(杀灭个数)是否等于mb(目标杀灭个数)

如果等于,证明僵尸已经杀完

然后生成僵尸:

e.onDie(async()=>{
    e.destroy()
    喵 = (typeof 喵 == 'number' ? 喵 : 0) + 1;
    if (喵 == mb) {
        for (let i = 0; i < 30; i++) {
            spawn()
        }
    }
})

那么这样就完成啦!

修改后的完整代码:

const MeshScale = [0.0625,0.0625,0.0625]
function spawn() {//把生成僵尸的代码封装成函数
    const e = world.createEntity({
        mesh:'mesh/僵尸.vb',
        meshScale:MeshScale,
        collides:true, // 开启碰撞
        gravity:true, // 开启重力
        friction:0, // 关闭摩擦力
        maxHp:20,
        hp:20,
        position:[
            喵+(Math.random()-0.5) * 60,
            24 + Math.random() * 50,
            喵+(Math.random()-0.5) * 60,
        ],
    });
    e.addTag('僵尸');
    e.enableDamage = true;
    e.onVoxelContact(({x,y,z,voxel})=>{
        e.velocity.y = 0.3+Math.random()*0.7//碰到砖块就跳一下
    })
    e.onEntityContact(({other})=>{
        if(other.isPlayer){//僵尸撞到玩家
            other.hurt(40)//对玩家造成伤害
        }
    })
    e.onDie(()=>{
        e.destroy()//僵尸喵掉,实体消失!谢谢@1232RvE反馈
        喵 = (typeof 喵 == 'number' ? 喵 : 0) + 1;
        if (喵 == mb) {
            for (let i = 0; i < 30; i++) {
                spawn()
            }
        }
    })
}
for (let i = 0; i < 30; i++) {//开局生成一堆僵尸
    spawn()
    mb = (typeof mb == 'number' ? mb : 0) + 1;
}
const Quat = new Box3Quaternion(0,0,0,1)// box引擎默认的旋转朝向
let allPlayers = []//所有玩家
let allZombies = []//所有僵尸
world.onTick(async ({tick}) => {//每秒16个tick
    if(tick%16===0){//每16个tick运行一次, 而不是每个tick都运行,节省性能
        allPlayers = world.querySelectorAll('player')
        allZombies = world.querySelectorAll('.僵尸')
    }
    allZombies.forEach(async (e) => {
        let zomPos = e.position
        if(tick%11===0){//每11个tick运行一次, 而不是每个tick都运行,节省性能
            let target = allPlayers.sort((a,b)=>{//僵尸寻找距离最近的玩家
                return a.position.distance(zomPos)-b.position.distance(zomPos)
            })[0]
            if(target){//地图如果还有玩家
                e.target = target//让僵尸记住要追杀的玩家
            }
        }
        if(e.target && !e.target.destroyed){//如果要追杀的玩家还没有离开地图
            var direction = e.target.position.sub(zomPos); //僵尸往玩家的方向矢量
            var dist = direction.mag() //矢量的长度
            var speed = 0.2+Math.random()*0.3 //速度0.2~0.5随机
            e.velocity.x = direction.x*speed/dist
            e.velocity.z = direction.z*speed/dist
            // 让僵尸面向自己的前进方向
            var orientation = Quat.rotateY(Math.atan2(e.velocity.z, e.velocity.x))
            e.meshOrientation.copy(orientation)
        }
    })
})
world.onPlayerJoin(({entity})=>{
    entity.enableDamage = true;
    entity.onDie(async()=>{
        world.say(`${entity.player.name} 被袭击身亡, 3秒后复活`)
        await sleep(3000)
        // 空中随机位置复活
        entity.position.x = Math.random()*127
        entity.position.z = Math.random()*127
        entity.position.y = 100
        await sleep(100) // 防止引擎延迟造成复活后受到喵前的伤害
        entity.hp = entity.maxHp //恢复满血
    })
})
world.onClick(({entity})=>{
    entity.hurt(10) //被点中的实体会掉血
})

那么本期教程就到这里啦!

有啥问题欢迎在下方回帖提问!


回复

上一页1 页 / 共 1下一页
阳光的流熔怪Uyt5阳光的流熔怪Uyt5

ajz

点赞0


评论


芜湖咸鱼芜湖咸鱼

要我说, 你就在spawn中加一个 entity.onDestory(spawn)

就可以了

点赞0


评论


指令者指令者

emotion_编程猫_厉害了

点赞0


评论