A Flash Developer Resource Site

Results 1 to 6 of 6

Thread: [F9] Vector class help

  1. #1
    crossconscious
    Join Date
    Sep 2005
    Location
    Belgium
    Posts
    1,188

    [F9] Vector class help

    Hi,

    Never been any good with vectors, but I decided to give it a shot and write a vector class, as part of a simple physics engine. But since I'm no good at it, I'm not sure if it's, well, any good. Could someone please have a look and see if the calculations look right, and if there's anything I could/should have done differently? Thanks.

    PHP Code:
    package com.gamesquid.physicsquid {
        
    // Written by Sven Magnus
        
    public class Vector {
            
    // public variables
            // use these in favour of the getters for slightly better performance
            // however, don't set them directly unless you know what you're doing
            
    public var _x1:Number=0;
            public var 
    _y1:Number=0;
            public var 
    _x2:Number=0;
            public var 
    _y2:Number=0;
            public var 
    _vx:Number=0;
            public var 
    _vy:Number=0;
            public var 
    _length:Number=0;
            public var 
    _angle:Number=0;
            
    // getter functions
            
    public function get x1():Number {
                return 
    this._x1;
            }
            public function 
    get y1():Number {
                return 
    this._y1;
            }
            public function 
    get x2():Number {
                return 
    this._x2;
            }
            public function 
    get y2():Number {
                return 
    this._y2;
            }
            public function 
    get vx():Number {
                return 
    this._vx;
            }
            public function 
    get vy():Number {
                return 
    this._vy;
            }
            public function 
    get length():Number {
                return 
    this._length;
            }
            public function 
    get angle():Number {
                return 
    this._angle;
            }
            public function 
    get degrees():Number {
                return 
    this._angle*180/Math.PI;
            }
            public function 
    get dx():Number {
                return 
    this._vx/this._length;
            }
            public function 
    get dy():Number {
                return 
    this._vy/this._length;
            }
            public function 
    get rx():Number {
                return -
    this._vy;
            }
            public function 
    get ry():Number {
                return 
    this._vx;
            }
            public function 
    get lx():Number {
                return 
    this._vy;
            }
            public function 
    get ly():Number {
                return -
    this._vx;
            }
            public function 
    get normal():Vector {
                return new 
    Vector(this._x1,this._y1,this.dx,this.dy);
            }
            public function 
    get right():Vector {
                return new 
    Vector(this._x1,this._y1,this.rx,this.ry);
            }
            public function 
    get left():Vector {
                return new 
    Vector(this._x1,this._y1,this.lx,this.ly);
            }
            
    // setter functions
            
    public function set x1(value:Number):void {
                
    this._x1=value;
                
    this._vx=this._x2-value;
                
    this._length=Math.sqrt(this._vx*this._vx+this._vy*this._vy);
                
    this._angle=Math.atan2(this._vy,this._vx);
            }
            public function 
    set y1(value:Number):void {
                
    this._y1=value;
                
    this._vy=this._y2-value;
                
    this._length=Math.sqrt(this._vx*this._vx+this._vy*this._vy);
                
    this._angle=Math.atan2(this._vy,this._vx);
            }
            public function 
    set x2(value:Number):void {
                
    this._x2=value;
                
    this._vx=value-this._x1;
                
    this._length=Math.sqrt(this._vx*this._vx+this._vy*this._vy);
                
    this._angle=Math.atan2(this._vy,this._vx);
            }
            public function 
    set y2(value:Number):void {
                
    this._y2=value;
                
    this._vy=value-this._y1;
                
    this._length=Math.sqrt(this._vx*this._vx+this._vy*this._vy);
                
    this._angle=Math.atan2(this._vy,this._vx);
            }
            public function 
    set vx(value:Number):void {
                
    this._vx=value;
                
    this._x2=this._x1+value;
                
    this._length=Math.sqrt(this._vx*this._vx+this._vy*this._vy);
                
    this._angle=Math.atan2(this._vy,this._vx);
            }
            public function 
    set vy(value:Number):void {
                
    this._vy=value;
                
    this._y2=this._y1+value;
                
    this._length=Math.sqrt(this._vx*this._vx+this._vy*this._vy);
                
    this._angle=Math.atan2(this._vy,this._vx);
            }
            public function 
    set angle(value:Number):void {
                
    this._angle=value;
                
    this._vx=this._length*Math.cos(value);
                
    this._vy=this._length*Math.sin(value);
                
    this._x2=this.x1+this._vx;
                
    this._y2=this.y1+this._vy;
            }
            public function 
    set length(value:Number):void {
                
    this._length=value;
                
    this._vx=value*Math.cos(this._angle);
                
    this._vy=value*Math.sin(this._angle);
                
    this._x2=this.x1+this._vx;
                
    this._y2=this.y1+this._vy;
            }
            
    // constructor
            
    public function Vector(x1:Number,y1:Number,vx:Number,vy:Number):void {
                
    this._x1=x1;
                
    this._y1=y1;
                
    this._vx=vx;
                
    this._vy=vy;
                
    this._x2=this._x1+this._vx;
                
    this._y2=this._y1+this._vy;
                
    this._length=Math.sqrt(this._vx*this._vx+this._vy*this._vy);
                
    this._angle=Math.atan2(this._vy,this._vx);
            }
            
    // public functions
            
    public function add(v:Vector):Vector {
                return new 
    Vector(this._x1,this._y1,this._vx+v._vx,this._vy+v._vy);
            }
            public function 
    substract(v:Vector):Vector {
                return new 
    Vector(this._x1,this._y1,this._vx-v._vx,this._vy-v._vy);
            }
            public function 
    dotProduct(v:Vector):Number {
                return 
    this._vx*v._vx+this._vy*v._vy;
            }
            public function 
    project(v:Vector):Vector {
                var 
    dp:Number=this._vx*v._vx+this._vy*v._vy;
                return new 
    Vector(this._x1,this._y1,dp*this.dx,dp*this.dy);
                return new 
    Vector(this._x1,this._y1,dp*this.dx,dp*this.dy);
            }
        }

    EDIT: I realize there's some redundancy in there, some stuff that gets repeated that could have been put in functions - like the calculation of the dotproduct when projecting vectors, or recalculating the angle and length - but I figured it would be a tiny bit faster like this, and it's not like these calculations will ever change, right? Unless I made a mistake with them, that is.
    Last edited by Fall_X; 08-28-2007 at 06:04 PM.

  2. #2
    Senior Member rachil0's Avatar
    Join Date
    Jul 2007
    Location
    Columbus, OH.
    Posts
    465
    Not one to critique another persons code, but I'll offer up my own opinions since you asked. I use vector types in my own codes quite a bit.

    I would pitch length and angle - they are derived quantities and instead of recalculating them every time a x/y component changes, compute them "on demand" through member functions. Also, I think that this class muddies the difference between displacement vectors and position vectors. The way this class defines them, all vectors are displacement vectors with strict start and end points (through the ..1 and ..2 notation).

    To me, it makes more sense to model any vector with just 2 components (or 3 .. when thinking in 3D spaces). A vector just has one .x and one .y member. If you need to model a displacement with explicit start and end points, use 2 position vectors - but I find I rarely need to model something like this. (In my codes, position is always a vector with 2 components, velocity is a vector with 2 components. The displacement / change in position that occurs through an update event is not modeled as a "point1", "point2" structure - its just "position += velocity*timestep".)

    For what it's worth, here's the vector class that I am using in my current project (doom clone). Take whatever you like.

    PHP Code:
    package 
      
    {    
      public class 
    Vector2D
        
    {
        public var 
    Number;
        public var 
    Number;
      
        public function 
    Vector2D (_x Number 0_y Number 0)
          {
          
    set(_x,_y);
          }
      
        public function 
    set (_x Number_y Number) : void
          
    {
          
    _x;
          
    _y;      
          }
      
        public function 
    length () : Number
          
    {
          return 
    Math.sqrt(x*y*y);    
          }
      
        public function 
    lengthSquared() : Number
          
    {
          return 
    x*x+y*y;    
          }
      
        public function 
    scale (Number) : void
          
    {
          
    *= s;
          
    *= s;
          }
      
        public function 
    normalize() : void
          
    {
          
    scale1.0 length() );
          }
      
        public function 
    add (arg Vector2D) : void
          
    {
          
    += arg.x;
          
    += arg.y;    
          }
      
        public function 
    subtract(arg Vector2D) : void
          
    {
          
    -= arg.x;
          
    -= arg.y;
          }  
           
      
        
    // Public static "Library" functions that deal with vectors.
        
        // These are binary factory functions that return Vector2D's
        
    public static function createSubtract (v1 Vector2Dv2 Vector2D) : Vector2D
          
    {
          return new 
    Vector2D (v1.v2.xv1.v2.y);
          }
          
        public static function 
    createAdd (v1 Vector2Dv2 Vector2D) : Vector2D
          
    {
          return new 
    Vector2D (v1.v2.xv1.v2.y);    
          }
        
        
    // These are binary Vector2D ops that return scalars.
        
    public static function dot (v1 Vector2Dv2 Vector2D) : Number
          
    {
          return 
    v1.x*v2.v1.y*v2.y;
          }
          
        public static function 
    cross (v1 Vector2Dv2 Vector2D) : Number
          
    {
          return 
    v1.x*v2.v1.y*v2.x;        
          }
          
        }
      } 
    Not many frills.

    I don't mean to say what you have is wrong. Really, a vector class is so simple that I would not fuss much about it's implementation or put a lot of focus on making a flexible / reusable component. Learning the math behind using vector arithmetic effectively is much more important. I would not be ashamed of reimplementing vector arithmetic from time to time, because different applications have different functional requirements. (Maybe you DO need to compute angle all the time, and it should be a stored member... but that's a choice that IMO should be made on an application-by-application basis)

    In reality, I find vector arithmetic is often happening inside tight inner loops and I end up just writing a lot of these functions (dot, cross, add, sub) in-place to avoid the overhead of a function call. (If AS3 had an inline function declaration that would do this for you, I would agree that making a full-fledged vector is a lot more sensible proposition).

    On the upshot, the implementation you have looks correct. But you forgot the cross product! That's the most important op of all (IMO).
    Last edited by rachil0; 08-28-2007 at 08:53 PM.

  3. #3
    Member
    Join Date
    Aug 2007
    Posts
    61
    APE (Actionscript Physics Engine) has a fairly complete Vector class.


    ---------------------------------------------------
    Glaze :2D Tile, Physics, Particle, AI Game Engine
    http://yaa-blog.blogspot.com/search/label/Glaze
    ---------------------------------------------------

  4. #4
    crossconscious
    Join Date
    Sep 2005
    Location
    Belgium
    Posts
    1,188
    Thanks for the advice. Exactly what I was hoping for.

    I havenow changed my implementation so that I have a NullVector base class (without first coordinates, they are assumed 0 in the calculations), which should be a bit faster when you don't need the first coordinates. Then my Vector class extends this. I plan to use vectors to describe levels (for collision), so it makes sense to have a class with two sets of coordinates. Not too sure about the name NullVector though, but I couldn't think of anything appropriate. (edit: think I'm going to go for DisplacementVector which extends PositionVector, but I'm not sure yet).

    As for calculating the angle each time something changes, well, that was a choice I had to make. Faster getting or faster setting of variables. It should be easy to change anyway.
    Last edited by Fall_X; 08-29-2007 at 08:00 AM.

  5. #5
    Member
    Join Date
    Aug 2007
    Posts
    61
    I saw you site & followed the discussion on tile engines. I think we have a common interest http://board.flashkit.com/board/showthread.php?t=742953

  6. #6
    crossconscious
    Join Date
    Sep 2005
    Location
    Belgium
    Posts
    1,188
    Yeah, I've seen your engine. Nice work!

    I think I know quite a bit about scrolling and tile stuff, but my knowledge about physics is way more limited than yours, so I had already planned on looking at your source code asap

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center