用户:
残梦殇查看: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 })
}
})
})