日常の進捗

主に自分のための,行為とその習慣化の記録

Mod:Coding Challenge #59: Steering Behaviors

f:id:takawo:20171020101412g:plain

操舵するような振る舞い,というのが直訳なのかな.

運転中に車でハンドルを切る時を想像して欲しい(免許持ってないひとはゲームでも良い).移動してる物体がいきなり90度進行方向を変えるみたいなことはできない.慣性に引っ張られながら進行方向を変える舵切りのような動きを実現する方法.

qiita.com

動画や参考リンクではp5.jsで実装していたけど,文字のアウトラインからポイントを抽出するというのはgeomerativeというProcessingの外部ライブラリで出来たので,Processingで書いてみた.p5.jsだとtextboundでとれるぽいのが良い.

コード

import geomerative.*;

RFont font;
RShape shape;
RPoint[] points;
ArrayList<Vehicle> vehicles = new ArrayList<Vehicle>();

void setup() {
  size(960, 540);
  colorMode(HSB, 360, 100, 100, 100);

  RG.init(this);  
  shape = RG.getText("HELLO", "FreeSans.ttf", 250, CENTER);

  RG.setPolygonizer(RG.UNIFORMLENGTH);
  RG.setPolygonizerLength(5);
  points = shape.getPoints();
  for (int i = 0; i < points.length; i++) {
    RPoint rp = points[i];
    Vehicle v = new Vehicle(rp.x, rp.y);
    vehicles.add(v);
  }
}

void draw() {
  background(36, 100, 86);

  translate(width/2, height *2/3);

  for (Vehicle v : vehicles) {
    v.behaviors();
    v.update();
    v.draw();
  }
}

class Vehicle {
  PVector pos;
  PVector vel;
  PVector acc;
  PVector target;
  float r = 8;
  float maxSpeed = 10;
  float maxForce = 1;

  Vehicle(float x, float y) {
    pos = new PVector(random(width)-width/2, random(height)-height*2/3);
    target = new PVector(x, y);
    vel = PVector.random2D();
    acc = new PVector();
  }
  void behaviors() {
    PVector arrive = arrive(target);
    PVector mouse = new PVector(mouseX-width/2, mouseY - height*2/3);
    PVector flee = flee(mouse);

    arrive.mult(1);
    flee.mult(5);

    applyForce(arrive);
    applyForce(flee);
  }
  void applyForce(PVector force) {
    acc.add(force);
  }

  void update() {
    vel.add(acc);
    pos.add(vel);
    acc.mult(0);
  }

  void draw() {
    stroke(236, 51, 37);
    strokeWeight(r);
    point(pos.x, pos.y);
  }

  PVector flee(PVector _target) {
    PVector desired = PVector.sub(_target, pos);
    float d = desired.mag();
    if (d < 50) {
      desired.setMag(maxSpeed);
      desired.mult(-1);
      PVector steer = PVector.sub(desired, vel);
      steer.limit(maxForce);
      return steer;
    } else {
      return new PVector(0, 0);
    }
  }

  PVector arrive(PVector _target) {
    PVector desired = PVector.sub(_target, pos);
    float d = desired.mag();
    float speed = maxSpeed;
    if (d < 100) {
      speed = map(d, 0, 100, 0, maxSpeed);
    }
    desired.setMag(speed);
    PVector steer = PVector.sub(desired, vel);
    steer.limit(maxForce);
    return steer;
  }
}

リファレンス