flash on 2009-9-23

by yd_niku
Programming Game AI by Exampleの写経です
@see http://www.oreilly.co.jp/books/9784873113395/
♥0 | Line 214 | Modified 2009-09-24 21:07:10 | MIT License
play

ActionScript3 source code

/**
 * Copyright yd_niku ( http://wonderfl.net/user/yd_niku )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/lQVc
 */

// Programming Game AI by Exampleの写経です
// @see http://www.oreilly.co.jp/books/9784873113395/
package {

    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.utils.*;
    
    [SWF(frameRate=60)]
    public class FlashTest extends Sprite {
        private var _time:Number = 0;
        private var _elements:Vector.<BaseGameEntity> = new Vector.<BaseGameEntity>();
        public function FlashTest() {
            var world:GameWorld = new GameWorld();
            /*
            world:GameWorld,
            position:Vector3D, rotation:Number, velocity:Vector3D, mass:Number,
            maxForce:Number, maxSpeed:Number, maxTurnRate:Number, scale:Number
            */
            var vehicle:Vehicle = new Vehicle(
                world, new Vector3D(100, 100), 30, new Vector3D(5,4), 100,
                100, 100, 10, 1
            );
            _elements.push( vehicle );
            addChild( vehicle );
            addEventListener( Event.ENTER_FRAME, enterframe );
            _time = getTimer();
        }
        private function enterframe ( e:Event ):void {
            var currentTime:Number = getTimer();
            var timeElasped:Number = currentTime - _time;
            timeElasped *= 0.05;
            
            for each( var element:BaseGameEntity in _elements ) {
                element.update(timeElasped);
                element.render();
            }
            _time = currentTime;
        }
    }
}

import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.errors.*;

class Vector2DUtil {
    // bがaに対して時計回り方向にあるようなら正の値、
    // 反時計回り方向にあるなら負の値を返す
    public static function sign( a:Vector3D, b:Vector3D ):int {
        var cross:Vector3D = a.crossProduct( b);
        return cross.z == 0 ? 0: cross.z > 0 ? -1 : 1;
    }
    // 垂直なベクトルを返す
    public static function perp( a:Vector3D ):Vector3D {
        return new Vector3D( a.y, a.x );
    }
}
class BaseGameEntity extends Sprite {
    private static var _nextId:int = 0;
    private static function get nextId():int { return _nextId++; }
    
    private var _id:int;
    public function get id():int { return _id; }
    
    public static const DEFAULT_ENTITY_TYPE:int = -1;
    private var _entityType:int;
    public function get entityType():int{ return _entityType; }
    public function set entityType( value:int):void { _entityType= value; }
    
    private var _bTag:Boolean = false;
    public function get isTagged():Boolean { return _bTag; }
    public function tag():void { _bTag = true; }
    public function unTag():void { _bTag = false; }
    
    protected var _position:Vector3D;
    public function get position():Vector3D { return _position; }
    public function set position( value:Vector3D ):void { _position = value; }
    
    protected var _scale:Vector3D= new Vector3D(1.0,1.0, 0);
    public function get scale():Vector3D { return _scale; }
    public function set scale( value:Vector3D ):void {
        _radius *= Math.max( value.x, value.y )/Math.max( _scale.x, _scale.y );
        _scale= value;
    }
    public function set scaleByNumber( value:Number ):void {
        _radius *= ( value/Math.max(_scale.x, _scale.y) );
        _scale.x = _scale.y = value;
    }
    
    protected var _radius:Number = 0.0;
    public function get radius():Number { return _radius; }
    public function set radius( value:Number ):void { _radius= value; }
    
    private function setId( $id:int ):void {
        _id = $id;
    }
    public function BaseGameEntity( entityType:int, position:Vector3D = null, radius:Number=0 ) {
        super();
        setId( nextId );
        _entityType = entityType;
        _position = position || new Vector3D();
        _radius = radius;
        render();
    }
    public function update( timeElapsed:Number ):void { throw new IllegalOperationError("You must override to 'update' method."); }

    public function render():void { throw new IllegalOperationError("You must override to 'render' method."); }
    
    //virtual bool HandleMessage(const Telegram& msg){return false;}
  
    ////entities should be able to read/write their data to a stream
    //virtual void Write(std::ostream&  os)const{}
    //virtual void Read (std::ifstream& is){}
  
    //public function update():void { throw new IllegalOperationError("You must override to 'update' method."); }
}

class MovingEntity extends BaseGameEntity {
    protected var _velocity:Vector3D;
    public function get velocity():Vector3D{ return _velocity; }
    public function set velocity( value:Vector3D) :void { _velocity = value; }
    
    public function get isSpeedMaxOut():Boolean { return _maxSpeed*_maxSpeed >= _velocity.lengthSquared; }
    public function get speed():Number{ return _velocity.length; }
    public function get speedSqrt():Number{ return _velocity.lengthSquared; }

    protected var _heading:Vector3D;
    public function get heading():Vector3D { return _heading; }
    public function set heading( value:Vector3D ) :void {
        if( ( value.lengthSquared - 1.0 ) < 0.00001 ) return;
        _heading= value;
        _side = Vector2DUtil.perp( _heading );
    }
    
    protected var _side:Vector3D;
    public function get side():Vector3D{ return _side; }
    
    protected var _mass:Number;
    public function get mass():Number{ return _mass; }
    
    protected var _maxSpeed:Number;
    public function get maxSpeed():Number{ return _maxSpeed; }
    public function set maxSpeed( value:Number) :void { _maxSpeed= value; }
    
    protected var _maxForce:Number;
    public function get maxForce():Number{ return _maxForce; }
    public function set maxForce( value:Number) :void { _maxForce= value; }
    
    protected var _maxTurnRate:Number;
    public function get maxTurnRate():Number{ return _maxTurnRate; }
    public function set maxTurnRate( value:Number) :void { _maxTurnRate= value; }
    
    public function rotateHeadingToFacePosition( target:Vector3D ):Boolean {
        var toTarget:Vector3D = target.subtract( _position );
        toTarget.normalize();

        var angle:Number = Math.acos( _heading.dotProduct(toTarget) );

        if (angle < 0.00001) return true;

        if (angle > _maxTurnRate ) angle = _maxTurnRate;
  
	var rotationMatrix:Matrix3D = new Matrix3D();
  
        //notice how the direction of rotation has to be determined when creating
        //the rotation matrix
	rotationMatrix.appendRotation( angle * Vector2DUtil.sign( _heading, toTarget ), Vector3D.Z_AXIS );	
        
        _heading = rotationMatrix.transformVector( _heading );
        _velocity = rotationMatrix.transformVector( _velocity );

        //finally recreate m_vSide
        _side = Vector2DUtil.perp( _heading );

        return false;
    }

    public function MovingEntity(
        pos:Vector3D, radius:Number, velocity:Vector3D, 
        maxSpeed:Number, heading:Vector3D, mass:Number, scale:Vector3D,
        maxTurnRate:Number, maxForce:Number
    ){
        super( 0, pos, radius );
        _velocity= velocity;
        _heading= heading;
        _mass = mass;
        _scale = scale;
        _side = Vector2DUtil.perp( _heading );
        
        _maxSpeed= maxSpeed;
        _maxForce= maxForce;
        _maxTurnRate = maxTurnRate;
    }
}
class GameWorld {}
class SteeringBehavior {
    private var _vehicle:Vehicle;
    public function SteeringBehavior( agent:Vehicle ) {
        _vehicle = agent;
    }
    public function calcurate():Vector3D { return new Vector3D(-5, -3, 0); }    
}
class Vehicle extends MovingEntity {
    private var _world:GameWorld;
    private var _steering:SteeringBehavior;
    //private var _headingSmoother;
    
    private var _smoothHeading:Vector3D = new Vector3D(); ;
    public function get smoothHeading():Vector3D{ return _smoothHeading; }
   
    private var _smoothHeadingOn:Boolean = false;
    public function get isSmoothingOn():Boolean { return _smoothHeadingOn; }
    public function smoothingOn():void { _smoothHeadingOn = true; }
    public function smoothingOff():void { _smoothHeadingOn = false; }
    public function toggleSmoothing():void { _smoothHeadingOn = !_smoothHeadingOn; }
    
    private var _timeElapsed:Number = 0.0;
    public function get timeElapsed():Number { return _timeElapsed; }
   
    public function Vehicle(
        world:GameWorld,
        position:Vector3D, rotation:Number, velocity:Vector3D, mass:Number,
        maxForce:Number, maxSpeed:Number, maxTurnRate:Number, scale:Number
     ) {
        super( position, scale, velocity, maxSpeed,
                  new Vector3D( Math.sin(rotation),-Math.cos(rotation)),
                  mass, new Vector3D(scale,scale), maxTurnRate, maxForce );
        _world = world;
        
        _steering = new SteeringBehavior(this);
        
    }
    private function drawBody():void{
        graphics.beginFill( 0x0000CC );
        graphics.drawCircle( 0, 0, 20 );
        graphics.endFill();
    }
    
    public function initializeBuffer():void {}
    public override function update( $timeElapsed:Number ):void {
        _timeElapsed = $timeElapsed;
        
        var oldPosition:Vector3D = _position.clone();
  
        var steeringForce:Vector3D = _steering.calcurate();
        steeringForce.scaleBy( _timeElapsed/_mass );
        
        _velocity.incrementBy( steeringForce );
        
        var limit :Number = Math.min( _maxSpeed, _velocity.length );
        _velocity.normalize();
        _velocity.scaleBy( limit );
        
        var addPos:Vector3D = _velocity.clone();
        addPos.scaleBy( _timeElapsed );
        _position.incrementBy( addPos );
        
        if( _velocity.lengthSquared < 0.0000001 ) {
            var newHeading:Vector3D = _velocity.clone();
            newHeading.normalize();
            _heading = newHeading;
            _side = Vector2DUtil.perp( _heading );
        }
        /*
  //EnforceNonPenetrationConstraint(this, World()->Agents());

  //treat the screen as a toroid
  WrapAround( position, world.cxClient(), world.cyClient());

  //update the vehicle's current cell if space partitioning is turned on
  if ( _steering.isSpacePartitioningOn() )
  {
    world.cellSpace().UpdateEntity(this, oldPosition );
  }

  if (isSmoothingOn())
  {
    _smoothedHeading = _headingSmoother.update(Heading());
  }*/
    }
    public override function render():void {
        this.x = _position.x;
        this.y = _position.y;
        this.scaleX = _scale.x;
        this.scaleY = _scale.y;
        
        
        this.graphics.clear();
        
        drawBody();
        
        if( _velocity) {
            graphics.moveTo(0,0);
            graphics.lineStyle(0, 0xFF0000 );
            graphics.lineTo( _velocity.x, _velocity.y );
        }
    }
}

Forked