群れの実装。壁を入れたらうまく動かない・・・
群れを実装する。
@author SIBA
package
{
import flash.display.Sprite;
import flash.events.Event;
[SWF(width=800, height=600, backgroundColor=0xAADDFF)]
/**
* 群れを実装する。
* @author SIBA
*/
public class Main02 extends Sprite
{
// ----------------------------
// メンバ変数
// ----------------------------
private var vehicles:Vector.<Vehicle> = new Vector.<Vehicle>();
// ----------------------------
// 初期化
// ----------------------------
public function Main02()
{
for (var i:int=0; i<20; i++)
{
var vehicle:Vehicle = new Vehicle();
vehicle.x = Math.random()*800;
vehicle.y = Math.random()*600;
vehicle.rotation = Math.random()*360;
addChild(vehicle);
vehicles.push(vehicle);
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
// ----------------------------
// イベント
// ----------------------------
private function onEnterFrame(event:Event):void
{
for each (var vehicle:Vehicle in vehicles)
{
vehicle.move(vehicles);
}
}
}
}
import __AS3__.vec.Vector;
import flash.display.Sprite;
import flash.text.engine.GraphicElement;
import flash.display.Graphics;
import flash.geom.Point;
// ------------------------------------
// 内部クラス
// ------------------------------------
/**
* ビーグル。
* @author SIBA
*/
class Vehicle extends Sprite
{
// --------------------------------
// 定数
// --------------------------------
private const SEPARATION_VIEW_AREA:Number = 96;
private const ALIGNMENT_VIEW_AREA:Number = 128;
private const COHESION_VIEW_AREA:Number = 128;
private const VIEW_AREA:Number = 50;
private const MAX_TURN_THETA:Number = 10;
private const MAX_FOURCE:Number = 5;
private const VIEW_AREA_THETA:Number = Math.PI/2;
// --------------------------------
// メンバ変数
// --------------------------------
private var nearVehicles:Vector.<Vehicle> = new Vector.<Vehicle>();
private var nearVehicle:Vehicle = null;
private var velocity:Number = MAX_FOURCE;
private var isHitWall:int = 10;
// --------------------------------
// 初期化
// --------------------------------
public function Vehicle():void
{
initDesign();
}
private function initDesign():void
{
const g:Graphics = graphics;
g.beginFill(0xFF5555);
g.moveTo(-25, -20);
g.lineTo(25, 0);
g.lineTo(-25, 20);
g.lineTo(-5, 0);
g.lineTo(-25, -20);
g.endFill();
}
// --------------------------------
// パブリックメソッド
// --------------------------------
public function move(vehicles:Vector.<Vehicle>):void
{
velocity = MAX_FOURCE;
if (isHitWall >= 50)
{
calcNearVehicle(vehicles, COHESION_VIEW_AREA);
cohesion();
calcNearVehicle(vehicles, ALIGNMENT_VIEW_AREA);
alignment();
calcNearVehicle(vehicles, SEPARATION_VIEW_AREA);
separation();
}
hitWall();
x += velocity * Math.cos(rotation/180 * Math.PI);
y += velocity * Math.sin(rotation/180 * Math.PI);
isHitWall++;
}
// --------------------------------
// 内部メソッド
// --------------------------------
private function cohesion():void
{
if (nearVehicles.length == 0) return;
var aveX:Number = 0;
var aveY:Number = 0;
for each (var vehicle:Vehicle in nearVehicles)
{
aveX += vehicle.x;
aveY += vehicle.y;
}
aveX += x;
aveY += y;
aveX /= nearVehicles.length + 1;
aveY /= nearVehicles.length + 1;
var tempRotation:Number = Math.atan2(aveY - y, aveX - x)/Math.PI * 180;
tempRotation -= rotation;
if (tempRotation > 180) tempRotation -= 360;
if (tempRotation < -180) tempRotation += 360;
tempRotation /= 10;
if (Math.abs(tempRotation) >= MAX_TURN_THETA) tempRotation = tempRotation < 0? -MAX_TURN_THETA : MAX_TURN_THETA;
rotation += tempRotation;
}
private function alignment():void
{
if (nearVehicles.length == 0) return;
var aveRotation:Number = 0;
for each (var vehicle:Vehicle in nearVehicles)
{
aveRotation += vehicle.rotation;
}
aveRotation /= nearVehicles.length;
var tempRotation:Number = aveRotation;
tempRotation -= rotation;
if (tempRotation > 180) tempRotation -= 360;
if (tempRotation < -180) tempRotation += 360;
tempRotation /= 10;
if (Math.abs(tempRotation) >= MAX_TURN_THETA) tempRotation = tempRotation < 0? -MAX_TURN_THETA : MAX_TURN_THETA;
rotation += tempRotation;
}
private function separation():void
{
if (nearVehicle == null) return;
var tempRotation:Number = Math.atan2(nearVehicle.y - y, nearVehicle.x - x)/Math.PI * 180;
tempRotation -= rotation;
if (tempRotation > 180) tempRotation -= 360;
if (tempRotation < -180) tempRotation += 360;
if (Math.abs(tempRotation) >= MAX_TURN_THETA) tempRotation = tempRotation < 0? -MAX_TURN_THETA : MAX_TURN_THETA;
if (nearVehicle.hitTestObject(this)) rotation -= tempRotation;
}
private function hitWall():void
{
if (x < 0)
{
x = 0;
if (rotation > 0) rotation = 80;
else rotation = -80;
isHitWall = 0;
}
else if (x > 800)
{
x = 800;
if (rotation > 0) rotation = 100;
else rotation = -100;
isHitWall = 0;
}
if (y < 0)
{
y = 0;
rotation *= -1;
isHitWall = 0;
}
else if (y > 600)
{
y = 600;
rotation *= -1;
isHitWall = 0;
}
}
private function calcNearVehicle(vehicles:Vector.<Vehicle>, viewArea:Number):void
{
nearVehicles.splice(0, nearVehicles.length);
var nearDistance:Number = 0;
for each (var vehicle:Vehicle in vehicles)
{
if (vehicle == this) continue;
var viewRotation:Number = Math.atan2(vehicle.y-y, vehicle.x-x) - rotation/180*Math.PI;
if (viewRotation > Math.PI) viewRotation -= 2*Math.PI;
if (viewRotation < -Math.PI) viewRotation += 2*Math.PI;
if (viewRotation < -Math.PI + VIEW_AREA_THETA || viewRotation > Math.PI - VIEW_AREA_THETA) continue;
var distance:Number = (x - vehicle.x) * (x - vehicle.x) + (y - vehicle.y) * (y - vehicle.y);
if (nearDistance == 0 || nearDistance > distance)
{
nearDistance = distance;
nearVehicle = vehicle;
}
if (distance < viewArea * viewArea)
{
nearVehicles.push(vehicle);
}
}
}
}