To register for an Internet.com membership to receive newsletters and white papers, use the Register button ABOVE.
To participate in the message forums BELOW, click here


A Flash Developer Resource Site

Go Back   Flash Kit Community Forums > General Help > Games

Reply
 
Thread Tools Search this Thread Display Modes
Old 08-28-2007, 07:01 PM   #1
Fall_X
crossconscious
 
Join Date: Sep 2005
Location: Belgium
Posts: 1,186
[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.
__________________
www.crossconscious.com

Last edited by Fall_X; 08-28-2007 at 07:04 PM.
Fall_X is offline   Reply With Quote
Old 08-28-2007, 09:45 PM   #2
rachil0
Senior Member
 
rachil0's Avatar
 
Join Date: Jul 2007
Location: Columbus, OH.
Posts: 461
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
x : Number;
    public var
y : Number;
  
    public function
Vector2D (_x : Number = 0, _y : Number = 0)
      {
      
set(_x,_y);
      }
  
    public function
set (_x : Number, _y : Number) : void
      
{
      
x = _x;
      
y = _y;      
      }
  
    public function
length () : Number
      
{
      return
Math.sqrt(x*x + y*y);    
      }
  
    public function
lengthSquared() : Number
      
{
      return
x*x+y*y;    
      }
  
    public function
scale (s : Number) : void
      
{
      
x *= s;
      
y *= s;
      }
  
    public function
normalize() : void
      
{
      
scale( 1.0 / length() );
      }
  
    public function
add (arg : Vector2D) : void
      
{
      
x += arg.x;
      
y += arg.y;    
      }
  
    public function
subtract(arg : Vector2D) : void
      
{
      
x -= arg.x;
      
y -= arg.y;
      }  
       
  
    
// Public static "Library" functions that deal with vectors.
    
    // These are binary factory functions that return Vector2D's
    
public static function createSubtract (v1 : Vector2D, v2 : Vector2D) : Vector2D
      
{
      return new
Vector2D (v1.x - v2.x, v1.y - v2.y);
      }
      
    public static function
createAdd (v1 : Vector2D, v2 : Vector2D) : Vector2D
      
{
      return new
Vector2D (v1.x + v2.x, v1.y + v2.y);    
      }
    
    
// These are binary Vector2D ops that return scalars.
    
public static function dot (v1 : Vector2D, v2 : Vector2D) : Number
      
{
      return
v1.x*v2.x + v1.y*v2.y;
      }
      
    public static function
cross (v1 : Vector2D, v2 : Vector2D) : Number
      
{
      return
v1.x*v2.y - 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 09:53 PM.
rachil0 is offline   Reply With Quote
Old 08-29-2007, 06:14 AM   #3
rje
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
---------------------------------------------------
rje is offline   Reply With Quote
Old 08-29-2007, 08:33 AM   #4
Fall_X
crossconscious
 
Join Date: Sep 2005
Location: Belgium
Posts: 1,186
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.
__________________
www.crossconscious.com

Last edited by Fall_X; 08-29-2007 at 09:00 AM.
Fall_X is offline   Reply With Quote
Old 08-29-2007, 08:48 AM   #5
rje
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
rje is offline   Reply With Quote
Old 08-29-2007, 08:56 AM   #6
Fall_X
crossconscious
 
Join Date: Sep 2005
Location: Belgium
Posts: 1,186
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
__________________
www.crossconscious.com
Fall_X is offline   Reply With Quote
Reply

Go Back   Flash Kit Community Forums > General Help > Games

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 06:03 PM.


internet.commerce
Be a Commerce Partner
 »  »  »  »  »  »  »
 »  »  »  »  »  »
 

    

Acceptable Use Policy


The Network for Technology Professionals

Search:

About Internet.com

Legal Notices, Licensing, Permissions, Privacy Policy.
Advertise | Newsletters | E-mail Offers


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.