javascript имитирует стаю птиц, используя механизм рендеринга cax и threejs

внешний интерфейс JavaScript WebGL Canvas
javascript имитирует стаю птиц, используя механизм рендеринга cax и threejs

В этой статье я буду использовать интерфейсную технологию для имитации 2D и 3D птичьих стай.Я использую элементы холста для рисования, конечно, также можно использовать css3 или svg.

вся реализацияdemo

Я выбираю threejs для 3D-рендеринга

Механизм рендеринга 2D Я выбираю cax, cax — это движок рендеринга, который мне очень нравится, поддерживает апплет, маленькую игру и рендеринг в веб-браузере. Используйте его для разработки как мини-игр, так и диаграмм (см.wechart),Настоятельно рекомендуется!

2д стая птиц

2d demo

Эти птицы не летают бесцельно, у них, кажется, есть разум, чтобы сформировать группу, группа производила сложные эффекты движения.

Это, казалось бы, сложное поведение является составным поведением, которое обычно делится на следующие

разделение

Прежде всего, предметы не должны максимально сталкиваться с окружающими предметами, они не должны находиться слишком близко друг к другу, и им нужно оставлять для себя небольшое пространство.

сплоченность

Он не может быть слишком далеко от окружающих предметов, слишком далеко и его оттянет назад

выравнивание

Направление их полета не должно быть слишком хаотичным, как правило, они будут лететь в одном направлении, а каждый объект будет сгруппирован в команду

Эти три характеристики разделены, сплочены и выстроены так, чтобы получилась реалистичная птичья стая (группа) с летающими машинами.

Учитывая сложное поведение стаи, нам не нужно знать общий интеллект стаи. Каждой птице нужно только применить эти три характеристики к другим птицам в пределах своего ареала, и колония сформируется естественным образом. Взгляните на следующий код, код не был сильно оптимизирован, мы увидим:

Создавайте птиц, добавляйте в сцену

var birds = Array.from({length:60},(v,i)=>{
  var bird = new Bird()
  stage.add(bird)

  Object.assign(bird,{
    po: new Vector(stage.width*rd(),stage.height*rd())
    ,ve: new Vector(rd() * 20 - 10, rd() * 20 - 10)
    ,ac: new Vector()
  }) 
  return bird
})

this.tick = cax.tick(()=>{
  stage.update()
  birds.forEach(b=>b.update(stage,birds))
})

метод обновления ключа

update(birds){
 // 忽略自己
 birds = birds.filter(o=>this!=o)
 
 // separation
 for(let bird of birds){
   // 过于接近
   if(this.po.distanceTo(bird.po) < Bird.sDist){
     // 减去这个转向力,实现分离
     this.ac.sub(
       bird.po.clone()
       .sub(this.po).normalize()
       .multiplyScalar(Bird.MAX_SPEED)
       .sub(this.ve)
     )
   } 
 }

 // cohesion
 let cohesion =  birds.reduce((param, b)=>{
   if(this.po.distanceTo(b.po) < Bird.cDist){
     param.sum.add(b.po)
     param.count++
   }
   return param
 },{sum:new Vector(),count:0,force:new Vector()})

 if(cohesion.count>0){
   // 先求得平均位置,用平均位置求得期望的目标速度,把算出的转向力累积到加速度上
   this.ac.add(
     cohesion.sum.divideScalar(cohesion.count)
     .sub(this.po).normalize()
     .multiplyScalar(Bird.MAX_SPEED)
     .sub(this.ve)
   )
 }


 // alignment
 let alignment =  birds.reduce((param, b)=>{
   if(this.po.distanceTo(b.po) < Bird.aDist){
     param.sum.add(b.ve)
     param.count++
   }
   return param
 },{sum:new Vector(),count:0,force:new Vector()})

 if(alignment.count>0){
  // 先求得平均速度,用平均速度求得期望的目标速度,把算出的转向力累积到加速度上
   this.ac.add(
     alignment.sum.divideScalar(alignment.count).normalize()
     .multiplyScalar(Bird.MAX_SPEED)
     .sub(this.ve) 
   )
 }
 // 不超过最大转向力和速度
 if(this.ac.length > Bird.MAX_FORCE) this.ac.normalize().multiplyScalar(Bird.MAX_FORCE)
 if(this.ve.length > Bird.MAX_SPEED) this.ve.normalize().multiplyScalar(Bird.MAX_SPEED)
 
 // 让质量大的鸟慢下来
 this.ve.add(this.ac.divideScalar(this.mass))
 this.po.add(this.ve) 
 
 // ...
  
}
 

Это игнорировать себя в первую очередь, и если вы ищете тех птиц, которые находятся слишком близко, добавьте к ускорению рассчитанную рулевую силу. Обратите внимание, что на самом деле существует дополнительное условие для суждения о том, что вы находитесь слишком близко, то есть в поле зрения. Вышеприведенный код не добавляет это условие, но он может имитировать лучше, я не писал =w=, поле зрения птицы обычно составляет 180 градусов, будь то в пределах 180 градусов, выполняется то, чтоthis.ve.dot(this.po.clone().sub(bird.po)) < 0, Настройка поля зрения и других значений приведет к различным эффектам сообщества.

Мы также можем складывать несколько слоев информации для создания более сложных симуляций. Все птицы здесь относятся к классу птиц, и можно добавить объект орла.Если расстояние между птицей и орлом превысит определенный порог, птица немедленно убежит. Чтобы сымитировать это, просто добавьте ко всей системе поведение убегания, что также приведет к увеличению общей силы поворота и скорости птицы.

3D стая птиц

3d demo

Реализация 3д аналогична принципу 2д.Единственно на что нужно обратить внимание это то что объект нужно повернуть в целевом направлении.Это обычно обрабатывается кватернионами.Ключ к коду

 this.rot.setFromQuaternion(
      new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), new THREE.Vector3(this.ve.x, this.ve.y, this.ve.z).normalize())
    )
    
 this.rotation.copy(new THREE.Euler(this.rot.x,this.rot.y,this.rot.z))

Ссылаться на