HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Even more math help!

12-05-2007, 11:24 PM#1
Dil999
I am working on a simple physics system for a map of mine. The entire thing is done, except for bouncing off the ground.
If I have a projectile, (knowing its x,y, and z-rates) and the point of ground it is colliding with, how do I find the x,y,and z rates that it should bounce off of, saying that is bounces as high as it fell (1:1 ratio). Please explain everything, because I have absolutely no idea how to do this and I would like to learn, instead of just being given a formula and putting it into my map.
12-06-2007, 02:11 AM#2
Strilanc
You're going to want to know vector math for this, because it makes the whole thing a whole lot simpler to understand.
References to get you started:
http://en.wikipedia.org/wiki/Coordinate_vector
http://en.wikipedia.org/wiki/Dot_product
http://en.wikipedia.org/wiki/Cross_product

Alright, so here's what you need to do:
- Compute the normal vector for the ground where you're hitting. You'll need three (very close) points to do this. You use your three points A,B,C to get the vectors A->B and A->C. The normal is the cross product of those two vectors.
- Compute the projection (see dot product article) of your velocity onto the normal vector.
- Subtract that projection from your velocity twice.

Code:
n1 = P3 - P1
n2 = P2 - P1
n = n1 x n2 (or n2 x n1, one has the right sign)
v -= 2*proj(v, n)

What did we do here? Essentially, we isolated the velocity going into the ground (the projection onto the normal vector), and flipped it (subtracted it twice). If the ground is perfectly flat, the z speed would have flipped. If the ground was inclined 45 degrees along x, z and x would have swapped.

I know that this is probably a confusing explanation. But vector math is really, really useful for physics, so you should get a head start on it now.
12-06-2007, 12:31 PM#3
Strilanc
It occurred to me that I wrote a JASS vector structure in the past. It's a bit old, but you should find it useful.

Collapse JASS:
//=======================================
// 3-Dimensional Vector Library
// Author: Strilanc
//=======================================
globals
    constant integer nill = 0
endglobals
struct Vector
    readonly static integer numAllocated = 0
    public real x
    public real y
    public real z
  
    ///Creates a vector with the given coordinates
    public static method create takes real x, real y, real z returns Vector
        local Vector v = Vector.allocate()
        set v.x = x
        set v.y = y
        set v.z = z
        set Vector.numAllocated = Vector.numAllocated + 1
        return v
    endmethod
    ///Cleans up properly
    private method onDestroy takes nothing returns nothing
        set Vector.numAllocated = Vector.numAllocated - 1
    endmethod
    
    ///Creates a Vector with the same coordinates as the given Vector
    public method clone takes nothing returns Vector
        if (this == nill) then
            return nill
        endif
        return Vector.create(this.x, this.y, this.z)
    endmethod
    
    ///Destroys this vector and returns the given vector
    ///mainly useful for removing temporary values
    ///EXAMPLE: v = v.destroyAndReturn(v.crossProduct(w))
    ///NOTE: be careful using this method!!
    public method destroyAndReturn takes Vector v returns Vector
        if (this != nill) then
            call this.destroy()
        endif
        return v
    endmethod
    
    ///Returns a string representation of this vector
    public method toString takes nothing returns string
        if (this == nill) then
            return "Vector:NILL"
        endif
        return "Vector:[" + R2S(this.x) + ", " + R2S(this.y) + ", " + R2S(this.z) + "]"
    endmethod

    //============================
    //===== In-Place Methods =====
    //============================
    ///Replaces all of this vector's coordinates with the coordinates of the given vector
    public method paste takes Vector v returns boolean
        if (this == nill or v == nill) then
            return false
        endif
        set v.x = this.x
        set v.y = this.y
        set v.z = this.z
        return true
    endmethod
    
    ///Sets this vector to the zero vector
    public method clear takes nothing returns boolean
        if (this == nill) then
            return false
        endif
        set this.x = 0
        set this.y = 0
        set this.z = 0
        return true
    endmethod

    ///Returns this vector's length
    public method getLength takes nothing returns real
        if (this == nill) then
            return 0
        endif
        return SquareRoot(this.x*this.x + this.y*this.y + this.z*this.z)
    endmethod
    
    ///Sets the length of this vector to d
    public method setLength takes real d returns boolean
        local real r
        if (this == nill) then
            return false
        endif

        set r = this.getLength()
        if (r <= 0) then
            return (d == 0) //zero vector can't be extended
        endif
        set r = d/r
      
        set this.x = this.x * r
        set this.y = this.y * r
        set this.z = this.z * r

        return true
    endmethod
    
    ///Adds the given vector scaled by c to this vector
    public method increaseBy takes Vector v, real c returns boolean
        if (this == nill or v == nill) then
            return false
        endif

        set this.x = this.x + v.x * c
        set this.y = this.y + v.y * c
        set this.z = this.z + v.z * c

        return true
    endmethod
    
    ///Scales this vector by the given amount
    public method scaleBy takes real c returns boolean
        if (this == nill) then
            return false
        endif

        set this.x = this.x * c
        set this.y = this.y * c
        set this.z = this.z * c

        return true
    endmethod

    //==============================
    //========= Arithmetic =========
    //==============================
    ///Returns the dot product of two vectors: the sum of their coordinates multiplied together
    public static method dot takes Vector v1, Vector v2 returns real
        if (v1 == nill or v2 == nill) then
            return 0
        endif
        return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
    endmethod
    
    ///Returns a vector equal to the cross product of the two given vectors
    public static method cross takes Vector v1, Vector v2 returns Vector
        if (v1 == nill or v2 == nill) then
            return nill
        endif
        return Vector.create(v1.y*v2.z-v2.y*v1.z, v1.z*v2.x-v2.z*v1.x, v1.x*v2.y-v2.x*v1.y)
    endmethod
    
    ///Returns a vector equal to the sum of the two given vectors
    public static method sum takes Vector v1, Vector v2 returns Vector
        if (v1 == nill or v2 == nill) then
            return nill
        endif
        return Vector.create(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z)
    endmethod
    
    ///Returns the length of this vector
    public method abs takes nothing returns real
        return this.getLength()
    endmethod
    
    ///Sets the length of this vector to 1
    public method normalize takes nothing returns boolean
        return this.setLength(1)
    endmethod
  
    //==============================
    //========= Projection =========
    //==============================
    ///Returns the magnitude of the parts of this vector parallel to the given vector
    public method scalarProjection takes Vector v returns real
        local real d
        if (this == nill or v == nill) then
            return 0.
        endif
      
        set d = v.getLength()
        if (d <= 0) then
            return 0 //v is the zero vector
        else
            return Vector.dot(this, v)/d
        endif
    endmethod
    
    ///Returns the parts of this vector parallel to the given vector
    public method projection takes Vector v returns Vector
        local Vector p
        if (this == nill or v == nill) then
            return nill
        endif
        
        //the projection is in the direction of v
        set p = v.clone()
        //and has a length equal to the scalar projection
        call p.setLength(this.scalarProjection(v))
        return p
    endmethod
    
    ///Returns the parts of this vector not parallel to the given vector
    public method perp takes Vector v returns Vector
        local Vector p
        if (this == nill or v == nill) then
            return nill
        endif
        
        //subtract the parallel parts
        set p = this.projection(v)
        call p.scaleBy(-1)
        call p.increaseBy(this, 1)
        return p
    endmethod
endstruct