猫史档案馆


《怪物待机、跟踪、攻击》

用户:残梦殇残梦殇查看:0 回复:6 评论:0 创建时间:2024-01-30T11:33:08


const Quat = new GameQuaternion(0, 0, 0, 1)

class Animal {
    /**
     * 需要参数提示可以这样
     * @param {GameEntity} entity 绑定的实体
     */
    constructor(entity) {
        this.entity = entity

        this.entity.collides = true
        this.entity.gravity = true
        this.entity.addTag('animal')

        this.init()
        this.onInit()

        // 每一帧、动起来
        this.interval = setInterval(() => {
            this.tick++
            this.onTick()
        }, 60)

        this.entity.onDie(({ attacker }) => {
            this.onDie(attacker)
        })
    }

    init() {
        this.rot = 0 // 旋转值
        this.rotSpeed = 1 // 旋转速度

        this.tick = 0 // 帧循环的计数器
        this.rotTick = 0 // 用来判定是否 改变旋转方向

        this.walkSpeed = 0.1 // 巡逻速度
        this.speedTick = 0 // 用来判定是否 改变巡逻速度

        this.inIdle = false // 是否正在待机
        this.beDead = false // 是否被打喵了

        // 子类可重新赋值的字段
        this.selfQuat = Quat // 模型对应的默认旋转四元数
        this.findRange = 10 // 寻找半径
        this.traceSpeed = 0.5 // 追踪速度
        this.canFly = false
    }

    // 供子类重写
    onInit() { }

    async onDie(attacker) {
        this.beDead = true
        clearInterval(this.interval)
        world.say(`${attacker.player.name} 打喵了 ${this.entity.id}`)
        await sleep(2000)
        this.entity.destroy()
        this.entity = null
    }

    onTick() {
        if (this.beDead) return
        // 现在有人靠近它的领域,它需要主动跟踪。首先寻找附近是否有人
        const players = this.getNearbyPlayers(this.findRange)
        if (players.length > 0) {
            if (this.inIdle) {
                this.inIdle = false
                this.turnToFight()
            }
            this.moveToTarget(players[0].position)
            return true
        } else {
            if (!this.inIdle) {
                this.inIdle = true
                this.turnToIdle()
            }
            this.animateNoAim()
            return false
        }
    }

    // 将要转变为待机状态
    turnToIdle() { console.log(' 转变为idle状态') }

    // 转变为攻击状态
    turnToFight() { console.log(' 转变为攻击状态') }

    // 无目标时,巡逻的移动表现
    animateNoAim() {
        if (this.tick >= this.rotTick) {
            this.rotSpeed = Math.PI * (Math.random() - 0.5) * 0.25
            this.rotTick = this.tick + this.randomRange(2, 4) * 16
        }
        if (this.tick >= this.speedTick) {
            this.walkSpeed = Math.random() * 0.3
            this.speedTick = this.tick + this.randomRange(3, 5) * 16
        }

        this.rot += this.rotSpeed * this.walkSpeed
        const 喵 = Math.cos(this.rot) * this.walkSpeed
        const vz = Math.sin(this.rot) * this.walkSpeed
        this.entity.velocity.x = 喵
        this.entity.velocity.z = vz
        this.entity.meshOrientation = this.selfQuat.rotateY(Math.atan2(vz, 喵))
    }

    // 向某个位置移动
    moveToTarget(pos) {
        const vel = pos.sub(this.entity.position).normalize()
        if (!this.canFly) {
            vel.y = 0
        }
        this.entity.velocity.x = vel.x * this.traceSpeed
        this.entity.velocity.y = vel.y * this.traceSpeed
        this.entity.velocity.z = vel.z * this.traceSpeed

        const ori = this.getOrientationByVector(this.selfQuat, vel)
        this.entity.meshOrientation = this.entity.meshOrientation.slerp(ori, 0.24)
    }

    // 获取附近的人,按距离排序,越近的优先
    getNearbyPlayers(range) {
        let players = world.querySelectorAll('player')
        const pos = this.entity.position
        players = players.filter(e => e.position.distance(pos) < range)
        players.sort((a, b) => { return a.position.distance(pos) - b.position.distance(pos) })
        return players
    }

    // 区域内随机,左闭右开 
    randomRange(start, end) {
        return start + (end - start) * Math.random()
    }

    // 通过向量计算角度
    getOrientationByVector(quat, vector3) {
        const src = vector3
        let dx = src.x
        let dy = src.y
        let dz = src.z
        let dist = Math.sqrt(dx * dx + dz * dz)
        const rotx = Math.atan2(dy, dist)
        return quat.rotateX(rotx).rotateY(Math.atan2(dz, dx))
    }
}

class CrazyAnimal extends Animal {
    onInit() {
        // 继承了CrazyAnimal的子类的onInit中,需调用super.onInit(),否则这里的设置都会失效
        this.entity.enableDamage = true

        this.attacking = false // 是否正在攻击

        this.skillCount = 1 // 招式的个数
    }

    // 继承并重写Animal的帧更新函数、附加咬人功能
    onTick() {
        const result = super.onTick()
        result && this.useSkill()
    }

    // 随机选择技能释放
    async useSkill() {
        if (this.attacking) return
        this.entity.say('我要出招了!')

        // ~~ 相当于向下取整
        let randomIndex = ~~this.randomRange(0, this.skillCount)

        if (!this['skill_' + randomIndex]) return

        this.attacking = true

        await this['skill_' + randomIndex]()

        // 技能cd 3秒
        await sleep(3 * 1000)
        this.attacking = false
    }
}

class Rabbit extends Animal {
    onInit() {
        this.traceSpeed = 0.8
    }

    // 将要转变为待机状态
    turnToIdle() {
        this.entity.say('啦啦啦啦~')
        // 如果实体有动画 可以在这里切换成待机动画
        // this.entity.motion.setDefaultMotionByName('idle')
    }

    // 转变为攻击状态
    turnToFight() {
        this.entity.say('嗷呜~')
        // 如果实体有动画 可以在这里切换成走路动画
        // this.entity.motion.setDefaultMotionByName('walk')
    }
}

class Bird extends Animal {
    onInit() {
        this.entity.gravity = false

        this.selfQuat = Quat.rotateY(-Math.PI / 2) // 模型对应的默认旋转四元数
        this.canFly = true
    }
}

class Dog extends CrazyAnimal {
    onInit() {
        super.onInit()
        this.selfQuat = Quat.rotateY(-Math.PI / 2) // 模型对应的默认旋转四元数
        this.findRange = 40
        this.skillCount = 1 // 招式的个数
    }

    skill_0() {
        this.entity.say(this.entity.id + ': 我要咬你一口!')
        this.entity.position.y += 2
        // 让最近的人 受伤
        const entitys = this.getNearbyPlayers(4)
        if (entitys.length > 0) {
            entitys[0].hurt(10)
        }
    }
}

class DogPlus extends Dog {
    onInit() {
        super.onInit()
        this.skillCount = 2 // 招式的个数
    }

    async skill_1() {
        this.entity.say(this.entity.id + ': 我要变大了!')
        this.entity.meshScale = this.entity.meshScale.scale(2)
        await sleep(2000)
        this.entity.meshScale = this.entity.meshScale.scale(0.5)
    }
}

// 需确保有如此命名的实体在地图中
const rabbit = world.querySelector('#新年兔子房-1')
new Rabbit(rabbit)

const bird = world.querySelector('#愤怒的小鸟-1')
new Bird(bird)

const dog = world.querySelector('#大嘴狗-1')
new Dog(dog)

const dogPlus = world.querySelector('#大嘴狗-2')
new DogPlus(dogPlus)

// 让动物们之间不碰撞 喵tag过滤
world.addCollisionFilter('.animal', '.animal')

world.onPlayerJoin(({ entity }) => {
    // 人物可被攻击
    entity.enableDamage = true

    entity.player.onPress(({ raycast, button }) => {
        if (button != GameButtonType.ACTION0) return
        if (raycast.hitEntity && raycast.hitEntity.hasTag('animal') && raycast.distance < 20) {
            raycast.hitEntity.hurt(10, { attacker: entity })
        }
    })
})


回复

上一页1 页 / 共 1下一页
岓

能教教替换方块的代码吗

点赞0


评论


dy=f’(x)*dxdy=f’(x)*dx

牛牛牛

点赞0


评论


飞熊jsrt飞熊jsrt

还是我,天花板

点赞0


评论


DRboxesDRboxes

吉吉喵:。。。

点赞0


评论


一盘番茄炒蛋一盘番茄炒蛋

收藏收藏

点赞0


评论


yyds二营长yyds二营长

))

点赞0


评论