• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Physics Engine

Status
Not open for further replies.
Level 22
Joined
Dec 31, 2006
Messages
2,216
Hello!

As some of you know I'm making a physics engine or more correct; an entity engine. It's going to be a little more advanced than SEE (Simple Entity Engine). Progress is going really well, but I've encountered two problems.

The first one is collision between entities. I tried to make it myself and made a function to pick the entities and I made a loop which looped through the entities and then calculated how they would move after hitting each other. The picking and collision detection worked very well, except for the fact that the picking method lagged when I had more that 60 entities. How they moved after hitting each other was totally different story. The entities didn't get wtfpwnd or something, it was in fact pretty cool, but it wasn't like I wanted it to be.. When two entities moved towards each other and collided both of them moved smoothly around each other and in slow motion.
After they had "left" each other they suddenly went to normal motion again. I don't have the script here because I removed it. It would be nice if someone could provide me with a nice script or something that calculates how they should move after colliding. The variables I have are:
x, y, z coordinates of both entities.
x, y, z velocities of both entities.
restitution (bounciness) of both entities.
mass of both entities.
and the size of both entities.
I don't think you need the others.

Now for the second problem:
This one is about rolling and friction. I manage to add friction and stuff with the ground and there are no problems with it. But I want to make it so the entities can roll instead of just slide. I tried, but I failed :/
I know the entity must rotate with a speed that matches the velocity to make the friction between the ground and the entity be about 0. Like this: rotations per second * (Pi*r^2)m == SquareRoot(xvel*xvel + yvel*yvel + zvel*zvel)m/s. The problem is that I'm not sure how I would increase/decrease the rolling speed to make it match the velocity and I'm not sure how I would calculate the friction when I have this variable...
I have these variables which you may use:
Angular Momentum.
Current roll angle.
Radius.
Mass.
x,y,z velocity.
friction.
I don't think you need any more variables.

If I've said something wrong then please notify me!

+rep to those who help!

Yours sincerely,
The_Reborn_Devil
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
SEE got too many lines...

And the rolling thing, I could make it so you can set if an entity can roll or not.


Edit: SEE is really annoying. It got two collision "functions", one is advanced and the other is simple or something like that. And if you look more you can see a comment that says something like: At this point variable names doesn't necessarily have anything to do with what they hold. And that's pretty annoying for me, because I want to easily know what that variable holds instead of looking through the script to try and find it out..
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Or maybe an option for the entity to be either spherical or cubic?

Cubic entities have complete different collisions which aren't really possible in Warcraft. As in, your vectors can act all nice and stuff, but you can't actually show it, aside maybe from making a cube from tons of special effects / units / whatever and repositioning them every frame.

By the way, this is HINDY's collision detection + response, just in C++, in case it helps:
Code:
#define FPS 40
#define COLL_ALGO_SPD 70.0

int BallIntersection(Ball *a,Ball *b)
{
	float vx = a->vx - b->vx;
	float vy = a->vy - b->vy;
	float r2 = vx*vx + vy*vy;
	if((r2)>(COLL_ALGO_SPD*COLL_ALGO_SPD/(FPS*FPS)))
	{
	    float px = a->x - b->x;
	    float py = a->y - b->y;
	    float s = px*vx + py*vy;
	    float r = px*px + py*py;
	    vx = a->r + b->r;
	    vy = s*s - r2*(r - vx*vx);
	    if(vy >= 0.0)
		{
	        vy = (-s - sqrt(vy))/r2;
	        if((vy > 0.0) & (vy <= 1.0))
			{
                b->x += vy*b->vx;
                b->y += vy*b->vy;
                a->x += vy*a->vx;
                a->y += vy*a->vy;
                s = s*(1.0 + 0.9*0.9)/(r*(1 + 1) + 0.001);
                b->vx += s*px;
                b->vy += s*py;
                a->vx -= s*px;
                a->vy -= s*py;
	        }
            else if((vy < 0.0) & (r < vx*vx))
			{
                float vz = (vx/(sqrt(r) + 0.001) - 1.0)/(1 + 1 + 0.001);
                if(r*vz*vz > 0.01/(FPS*FPS))
				{
                    b->x -= px;
                    b->y -= py;
                    a->x += px;
                    a->y += py;
                }
            }
	    }
	}
	else
	{
        float px = a->x - b->x;
        float py = a->y - b->y;
        float r = px*px + py*py;
        r2 = a->r + b->r;
        if(r < r2*r2)
		{
            float s = (px*vx + py*vy)*(1 + 0.9*0.9)/(r*(1 + 1) + 0.001);
            float vz = (r2/(sqrt(r) + 0.001) - 1.0)/(1 + 1 + 0.001);
            if(r*vz*vz > 0.01/(FPS*FPS))
			{
                b->x -= px;
                b->y -= py;
                a->x += px;
                a->y += py;
            }
            b->vx += s*px;
            b->vy += s*py;
            a->vx -= s*px;
            a->vy -= s*py;
        }
	}
	return 0;
}


I blame bbcode for messing the tabs :/
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Cubic entities have complete different collisions which aren't really possible in Warcraft. As in, your vectors can act all nice and stuff, but you can't actually show it, aside maybe from making a cube from tons of special effects / units / whatever and repositioning them every frame.

I think it's possible, because the model I'm using is dummyRoll.mdx and it supports both pitch and roll. But I don't think it's necessary.

I'll try that code later. The one I tested first which didn't work looked like that, but not exactly the same. Maybe that one works ^^
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Hehe. It's only 46,2kb :)

It works a little different than dummy.mdx
To change it's pitch and rotation you must use call SetUnitLookAt("bone_Head", DUMMY, xoffset, yoffset, zoffset)
So don't use SetUnitFacing(). Also, to change it's roll angle you must use call SetUnitAnimationByIndex(DUMMY, i)
I'm not entirely sure what you must use as the index, but I know 1 means straight up. Look for a map called FlightSimConcept. The creator uses dummyRoll.mdx. The map should be here at the hive.
 

Attachments

  • dummyRoll.mdx
    46.2 KB · Views: 92
Level 20
Joined
Apr 22, 2007
Messages
1,960
It's going to be a little more advanced than SEE
:eek: Given you can pretty much do anything you want (which is sane) with SEE, I don't know how you'll achieve that. What exactly do you mean by "more advanced"?

As for the rolling, I never succeeded in implementing it because I figured it would pretty much be useless and overcomplicated. I tried, though, but it was outside the scope of my studies and my teachers had trouble understanding what I was trying to accomplish.

If you need an in-depth explanation of how I solved collision detection/resolution for SEE, you know, you could just ask me. lol
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
By more advanced I mean more stuff like: Magnetism, Gravity (not just the earth's gravity, but the gravity of all the entities), Rolling (already said, but I'll say it again), some GMod inspired stuff like weld, rope and ball-socket constraints (ball-socket constraints will also have the option to prevent entities from changing their roll/pitch angle, this could be nice if you want to make wheels for a car) and thrusters, some water stuff like buoyancy and making entities skip across the water and maybe more.

If I need any help I'll ask you :)
I will probably need help because I don't think my two physics books can help me with everything.
 
Level 20
Joined
Apr 22, 2007
Messages
1,960
I think that magnetism and universal gravity are inconvenient for such systems. For efficiency reasons, I designed my system in a way that universal gravity would be difficult to implement to the core, but possible within a specific entity type.

The ball-socket constraint is a neat idea I guess. I made some half-assed constraints in SEE though, since barely anyone would ever use such a thing. I also tried to get buoyancy to work in the latest version (without water doodads), but I gave up due to the fucked-up'edness of invisible platforms. Maybe I was just doinitrong (it had been a while since I'd Jassed).
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Hmm. Maybe I'll make it so magnetism and gravity can be added through addition modules which the user can make. And for the water thing, I'm going to use a custom model for the water. Can't remember the author. It's called WaterPlane.mdx.
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
this might help
http://www.thehelper.net/forums/showthread.php?t=124461&highlight=deflection
this is similar to the one before but used as a spell
http://www.thehelper.net/forums/showthread.php?t=123712
(this is 2D only...sry)


I messed around with deflection myself (in JAVA)
had some similar problem with performance when checking the distance between 1k balls and comparing them to their radii :hohum:
in the end I checked the screen and checked if all balls in the sorounding boxes didn't touch each other

however it is easier by far when using wc3
just pick all units within range
beware of not destroying the created groups instantly
creating groups in GUI leaks - no madder what you are doing ( things like set bj_wantDestroyGroup = true or call DestroyGroup make the leaks smaller but far from being negligible )
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
You never check for distances in collision detection, the square root is too expensive.
Instead (speaking about spheres that is) just check the relation between x2 + y2 + z2 and r2.

This is a part of a very old code of mine

Code:
    float r  = r1 + r2;
    float dx = x1 + x2;
    float dy = y1 + y2;
    float dz = z1 + z2;
    float collid = dx*dx + dy*dy + dz*dz - r*r;
    
    if(collid < 0) return 1;
    return 0;

I left out the case were it's equal to zero, in which the spheres are just beginning to scratch each other (no distance).
 
Level 20
Joined
Apr 22, 2007
Messages
1,960
The_Reborn_Devil said:
Can't remember the author.
I remember iNfraNe made a water model for this specific purpose a long time ago.

D4RK_G4NDALF said:
creating groups in GUI leaks - no madder what you are doing ( things like set bj_wantDestroyGroup = true or call DestroyGroup make the leaks smaller but far from being negligible )
...?

GhostWolf said:
the square root is too expensive.
SquareRoot is actually pretty fast. It's just more convenient to avoid it as much as possible.

GhostWolf said:
Instead (speaking about spheres that is) just check the relation between x2 + y2 + z2 and r2.
That's the simple solution. The problem with that is what if you have two entities moving faster than the length of their diameters per iteration? Then they will effectively never intersect but instead just pass right through one another. That is why you have to take time and velocity into the equation as well, and it becomes a bit more complicated (actually, it's just a quadratic equation involving vectors and dot products etc.)
 

N.O

N.O

Level 6
Joined
Feb 20, 2009
Messages
200
Since your going to make it more advanced then SEE, then I have a good suggestion and that would be fixing the lag I see in huge physics systems like SEE...
 

N.O

N.O

Level 6
Joined
Feb 20, 2009
Messages
200
Lol I love how element just responded with wow you must have a crappy computer...
I have a epic computer sorry, if you wanne know what it has I can tell u a few things.
My computer holds up to 150 GB as well got 2GB RAM and a really good procressor as well graphics card.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
I get no lag before it reaches 200 entities and I have an old computer (going to upgrade it heavily soon). 180GB HDD, 1GB RAM (with 5GB virtual memory), 2,21 GHz (clocked to 2,3 GHz) AMD Athlon 64 processor and GeForce 7600GT.
 
Last edited:
Lol I love how element just responded with wow you must have a crappy computer...
I have a epic computer sorry, if you wanne know what it has I can tell u a few things.
My computer holds up to 150 GB as well got 2GB RAM and a really good procressor as well graphics card.
Lol. You think 2GB RAM is "really epic". 2GB isn't good or bad, it's like... average. But still, your computer must have something wrong with it if it can't handle up to 200 entities.
 

N.O

N.O

Level 6
Joined
Feb 20, 2009
Messages
200
Lol. You think 2GB RAM is "really epic". 2GB isn't good or bad, it's like... average. But still, your computer must have something wrong with it if it can't handle up to 200 entities.

I ran it on my other computer that was a bit better with alot more RAM and I still detected lag... btw I think it was 5GB RAM, not entirely sure. I'll check sometime later today to make sure though.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
I haven't had much time lately, but now I got a lot of time, so I'm going to work on it a lot today, tomorrow and the day after tomorrow.
Currently it supports friction (not rolling. I haven't found a solution yet), bouncing with any kind of terrain, collision with other entities and slow motion.

I do have some problems with the collision between entities. For some reason the entities bounce away from each other with higher speed when I have low restitution and the opposite when I have restitution at 1, but if I go over 1 the speed suddenly increases again....
Also, for some reason my wc3 gets errors when the entities reaches a certain height or something, and when I tried to make them "bounce" down again when they got too high up, they just ignored me :/
Also, they bounce away from each other with insane speed. It's not just a little fast, it's so fast that I need to make the time go 10 times slower to actually see the balls..

It's really weird.
 
Level 20
Joined
Apr 22, 2007
Messages
1,960
The_Reborn_Devil said:
Currently it supports friction (not rolling. I haven't found a solution yet)
Rolling would involve messed up torque and moments of inertia and shit... I just figured it would be too complicated for no real reason. At least there's a visible advantage when working with boxes or bounding boxes. When you're working with perfect spheres, sliding can provide a similar effect to rolling, if you feel like playing with animation speeds and stuff. You can actually make it really nice if you fool around with negative animation speeds. Then again, you have some weird dummy model which I haven't checked out yet, so maybe that opens even more possibilities.

The_Reborn_Devil said:
For some reason the entities bounce away from each other with higher speed when I have low restitution and the opposite when I have restitution at 1, but if I go over 1 the speed suddenly increases again....
If you want to post your code, maybe I can help.

The_Reborn_Devil said:
Also, for some reason my wc3 gets errors when the entities reaches a certain height or something
Weird, that's never happened to me.

The_Reborn_Devil said:
Also, they bounce away from each other with insane speed. It's not just a little fast, it's so fast that I need to make the time go 10 times slower to actually see the balls..
Did you happen to forget to scale the resulting velocities down to per-period velocity instead of per-second?
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Okay, here's the codes:

Vector System (Not even close to done):
JASS:
library VectorSystem

globals
    private constant location l = Location(0., 0.)
    private constant location l2 = Location(0., 0.)
    
    private constant real SR = 1.
endglobals

struct vector
    real x
    real y
    real z
    real xvel
    real yvel
    real zvel
    
    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 v.xvel = 0.
        set v.yvel = 0.
        set v.zvel = 0.
        return v
    endmethod
    
    static method GetBounceVector takes real x, real y, real xvel, real yvel, real zvel, real re returns vector
        local real vx
        local real vy
        local real vz
        local real px
        local real py
        local real pz
        local vector v = vector.allocate()
        call MoveLocation(l, x-SR, y)
        call MoveLocation(l2, x+SR, y)
        set vx = GetLocationZ(l) - GetLocationZ(l2)
        call MoveLocation(l, x, y-SR)
        call MoveLocation(l2, x, y+SR)
        set vy = GetLocationZ(l) - GetLocationZ(l2)
        set vz = (xvel*vx + yvel*vy + zvel*SR)/(vx*vx + vy*vy + SR*SR)
        set px = vx*vz
        set py = vy*vz
        set pz = SR*vz
         
        set v.xvel = (xvel - px) - px*re
        set v.yvel = (yvel - py) - py*re
        set v.zvel = (zvel - pz) - pz*re
        return v
    endmethod
endstruct

endlibrary


Entity Core. There are some things there that I've begun working on. Also you can see that the collision between entities part is 99,99% equal to yours, and that's because I just copied it and changed a few things just to test it. I'm going to make my own version when I'm done debugging (will probably be very similar to yours). Also, ignore the "sleep" things. That's something I'm working on.
Time for teh code:
JASS:
library EntityCore initializer Init uses VectorSystem

globals
    private constant timer t = CreateTimer()
    private constant real interval = 0.04
    private real slowmo = 1
    private constant real m = 64. //How many wc3 units there are in one meter
    private constant real grav = ((9.80665*m)/((1/interval)*(1/interval)))
    private constant integer dummyID = 'h000'
    private constant real THRESHOLDS = 40.
    private constant real COLL_ALGO_SPD = 400.
    
    
    private real maxx
    private real maxy
    private real minx
    private real miny
    
    private entity array Entity
    private integer Total = 0
endglobals



struct entity
    unit u
    effect model
    real mass
    real coll
    real restitution
    real friction
    vector v
    boolean wantDestroy
    boolean canBounce
    boolean resting
    
    static method create takes player p, string mdl, real mass, real coll, real x, real y, real z, real a, real restitution, real friction, boolean canBounce returns entity
        local entity e = entity.allocate()
        local location l = Location(x, y)
        set e.u = CreateUnit(p, dummyID, x, y, a * bj_RADTODEG)
        set e.model = AddSpecialEffectTarget(mdl, e.u, "origin")
        set e.mass = mass
        set e.coll = coll
        set e.v = vector.create(x, y, z + GetLocationZ(l))
        set e.restitution = restitution
        set e.friction = friction
        set e.wantDestroy = false
        set e.canBounce = canBounce
        set e.resting = false
        call SetUnitAnimationByIndex(e.u, 1)
        call SetUnitLookAt(e.u, "bone_Head", e.u, 0., 20., 0.)
        call UnitAddAbility(e.u, 'Amrf')
        call UnitRemoveAbility(e.u, 'Amrf')
        call SetUnitFlyHeight(e.u, z, 0.)
        call RemoveLocation(l)
        set Total = Total + 1
        set Entity[Total] = e
        if Total == 1 then
            call TimerStart(t, interval, true, function entity.Loop)
        endif
        set l = null
        return e
    endmethod

    
    static method Loop takes nothing returns nothing
        local integer i = 1
        local entity e
        local location l = Location(0., 0.)
        local real lz
        local real s
        local vector v
        local integer i2
        
        
        local entity e2
        local group g
        local real vx
        local real vy
        local real vz
        local real px
        local real py
        local real pz
        local real s2
        local real r
        local real r2
    
        if Total == 0 then
            call PauseTimer(t)
            return
        endif
        loop
            exitwhen i > Total
            set e = Entity[i]
            
            //Updates the entity's position and it's z velocity and moves the entity based on it's speed
            set e.v.x = e.v.x + (e.v.xvel/slowmo)
            set e.v.y = e.v.y + (e.v.yvel/slowmo)
            set e.v.z = e.v.z + (e.v.zvel/slowmo)
            set e.v.zvel = e.v.zvel - ((e.mass * grav)/slowmo)
            call MoveLocation(l, e.v.x, e.v.y)
            set lz = GetLocationZ(l)
            set e.v.z = e.v.z - lz
            call SetUnitX(e.u, e.v.x)
            call SetUnitY(e.u, e.v.y)
            call SetUnitFlyHeight(e.u, e.v.z, 0.)
            call SetUnitAnimationByIndex(e.u, 1)
            //call SetUnitLookAt(e.u, "bone_Head", e.u, e.v.xvel, e.v.yvel, e.v.zvel)
            call SetUnitLookAt(e.u, "bone_Head", e.u, 0., 20., 0.)
            set e.v.z = e.v.z + lz
            
            set s = SquareRoot(e.v.xvel*e.v.xvel + e.v.yvel*e.v.yvel + e.v.zvel*e.v.zvel)
            
            //Checks if the entity is within map bounds
            if e.v.x > maxx or e.v.x < minx or e.v.y > maxy or e.v.y < miny then
                //set e.wantDestroy = true
                if e.v.x > maxx or e.v.x < minx then
                    set e.v.xvel = e.v.xvel*-1
                elseif e.v.y > maxy or e.v.y < miny then
                    set e.v.yvel = e.v.yvel*-1
                endif
            endif
            
            //Checking for collision with the ground
            if e.v.z - e.coll > lz then
                //Entity did not touch the surface
            else
                //Entity is touching the surface. Make it bounce
                set v = vector.GetBounceVector(e.v.x, e.v.y, e.v.xvel, e.v.yvel, e.v.zvel, e.restitution)
                set e.v.xvel = v.xvel
                set e.v.yvel = v.yvel
                set e.v.zvel = v.zvel
                set e.v.z = lz + e.coll
                if (e.v.zvel*e.v.zvel)/2. <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
                    set e.v.xvel = e.v.xvel*(1-(e.friction/slowmo))
                    set e.v.yvel = e.v.yvel*(1-(e.friction/slowmo))
                    set e.v.zvel = 0.
                endif
                if e.v.xvel*e.v.xvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
                    set e.v.xvel = 0.
                elseif e.v.yvel*e.v.yvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
                    set e.v.yvel = 0.
                endif
                call v.destroy()
            endif
            //Checking for collision between entities
            set i2 = 1
            loop
                exitwhen i2 > Total
                set e2 = Entity[i2]
                
                if e2 != e then
                set vx = e.v.xvel - e2.v.xvel
                set vy = e.v.yvel - e2.v.yvel
                set vz = e.v.zvel - e2.v.zvel
                set r2 = vx*vx + vy*vy + vz*vz
                
                if r2 >= (COLL_ALGO_SPD*COLL_ALGO_SPD)/((1/interval)*(1/interval)) then
                        // If the relative velocity is larger than the collision separator, advanced collision detection is executed
                        // The following collision detection was established using the equation: |deltaP + t*deltaV| <= r1 + r2
                        // Note that at this point, variable names most likely have nothing to do with what they hold
                        set px = e.v.x - e2.v.x
                        set py = e.v.y - e2.v.y
                        set pz = e.v.z - e2.v.z
                        set s  = px*vx + py*vy + pz*vz
                        set r  = px*px + py*py + pz*pz
                        set vx = e.coll + e2.coll
                        set vy = s*s - r2*(r - vx*vx)
                        if vy >= 0. then
                            set vy = (-s - SquareRoot(vy))/r2
                            if vy > 0. and vy <= 1. then
                            
                                // --
                                // The following prepares collision resolution while moving entities to their touching position
                                set e2.v.x = e2.v.x + e2.v.xvel*vy
                                set e2.v.y = e2.v.y + e2.v.yvel*vy
                                set e2.v.z = e2.v.z + e2.v.zvel*vy
                                set e.v.x = e.v.x + e.v.xvel*vy
                                set e.v.y = e.v.y + e.v.yvel*vy
                                set e.v.z = e.v.z + e.v.zvel*vy
                                // --
                                
                                // --
                                // The following is code for collision resolution
                                set s = s*(1. + e2.restitution*e.restitution)/(r*(e2.mass + e.mass) + 0.001)
                                if e2.canBounce then
                                    set vx = s*e.mass
                                    set e2.v.xvel = e2.v.xvel + px*vx
                                    set e2.v.yvel = e2.v.yvel + py*vx
                                    set e2.v.zvel = e2.v.zvel + pz*vx
                                    if e2.v.xvel*e2.v.xvel + e2.v.yvel*e2.v.yvel + e2.v.zvel*e2.v.zvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
                                        // If the entity moves slower than the threshold velocity, set the velocity to 0
                                        set e2.v.xvel = 0.
                                        set e2.v.yvel = 0.
                                        set e2.v.zvel = 0.
                                    else
                                        //set e2.resting = false
                                    endif
                                endif
                                if e.canBounce then
                                    set vx = s*e2.mass
                                    set e.v.xvel = e.v.xvel - px*vx
                                    set e.v.yvel = e.v.yvel - py*vx
                                    set e.v.zvel = e.v.zvel - pz*vx
                                    if e.v.xvel*e.v.xvel + e.v.yvel*e.v.yvel + e.v.zvel*e.v.zvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
                                        // If the entity moves slower than the threshold velocity, set the velocity to 0
                                        set e.v.xvel = 0.
                                        set e.v.yvel = 0.
                                        set e.v.zvel = 0.
                                    else
                                        //set e.resting = false
                                    endif
                                endif
                            elseif vy < 0.0 and r < vx*vx then
                                set vz = (vx/(SquareRoot(r) + 0.001) - 1.0)/(e2.mass + e.mass + 0.001)
                                set vy = e.mass*vz
                                if r*vy*vy > 0.01/((1/interval)*(1/interval)) then
                                    set e2.v.x = e2.v.x - vy*px
                                    set e2.v.x = e2.v.x - vy*py
                                    set e2.v.x = e2.v.x - vy*pz
                                    //set e2.resting = false
                                endif
                                set vy = e2.mass*vz
                                if r*vy*vy > 0.01/((1/interval)*(1/interval)) then
                                    set e.v.x = e.v.x + vy*px
                                    set e.v.x = e.v.x + vy*py
                                    set e.v.x = e.v.x + vy*pz
                                    //set e.resting = false
                                endif
                            endif
                        endif
                else
                        set px = e.v.x - e2.v.x
                        set py = e.v.y - e2.v.y
                        set pz = e.v.z - e2.v.z
                        set r  = px*px + py*py + pz*pz
                        set r2 = e.coll + e2.coll
                        if r < r2*r2 then
                            // If the relative velocity is smaller than the collision separator;
                            // and if two entities are currently colliding, simple collision script is executed
                            // --
                            // The following code moves entities apart from eachother based on their mass and the distance between them
                            set s2 = (px*vx + py*vy + pz*vz)*(1. + e2.restitution*e.restitution)/(r*(e2.mass + e.mass) + 0.001)
                            set vz = (r2/(SquareRoot(r) + 0.001) - 1.)/(e2.mass + e.mass + 0.001)
                            set vy = e2.mass*vz
                            if r*vy*vy > 0.01/((1/interval)*(1/interval)) then
                                set e.v.x = e.v.x + vy*px
                                set e.v.y = e.v.y + vy*py
                                set e.v.z = e.v.z + vy*pz
                                //set e.resting = false
                            endif
                            set vy = e.mass*vz
                            if r*vy*vy > 0.01/((1/interval)*(1/interval)) then
                                set e2.v.x = e2.v.x - vy*px
                                set e2.v.y = e2.v.y - vy*py
                                set e2.v.z = e2.v.z - vy*pz
                                //set e2.resting = false
                            endif
                            // --
                            // The following is code for collision resolution
                            if e2.canBounce then
                                set vx = s*e.mass
                                set e2.v.xvel = e2.v.xvel + px*vx
                                set e2.v.yvel = e2.v.yvel + py*vx
                                set e2.v.zvel = e2.v.zvel + pz*vx
                                if e2.v.xvel*e2.v.xvel + e2.v.yvel*e2.v.yvel + e2.v.zvel*e2.v.zvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
                                    // If the entity moves slower than the threshold velocity, set the velocity to 0
                                    set e2.v.xvel = 0.
                                    set e2.v.yvel = 0.
                                    set e2.v.zvel = 0.
                                else
                                    //set e2.resting = false
                                endif
                            endif
                            if e.canBounce then
                                set vx = s*e2.mass
                                set e.v.xvel = e.v.xvel - px*vx
                                set e.v.yvel = e.v.yvel - py*vx
                                set e.v.zvel = e.v.zvel - pz*vx
                                if e.v.xvel*e.v.xvel + e.v.yvel*e.v.yvel + e.v.zvel*e.v.zvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
                                    // If the entity moves slower than the threshold velocity, set the velocity to 0
                                    set e.v.xvel = 0.
                                    set e.v.yvel = 0.
                                    set e.v.zvel = 0.
                                else
                                    //set e.resting = false
                                endif
                            endif
                        endif
                        
                endif
                endif
                set i2 = i2 + 1
            endloop
            
            //Destroying entities marked for destruction
            if e.wantDestroy then
                set Entity[i] = Entity[Total]
                set Total = Total - 1
                set i = i - 1
                call e.destroy()
            endif
            set i = i + 1
        endloop
        call RemoveLocation(l)
    endmethod
    
    method onDestroy takes nothing returns nothing
        call RemoveUnit(.u)
        call DestroyEffect(.model)
        call .v.destroy()
        set .u = null
        set .model = null
    endmethod
endstruct

private function Init takes nothing returns nothing
    call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 0., 0., 500., 0., 0.4, 0.3, true)
    call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., -100., 0., 500., 0., 0.4, 0.3, true)
    call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 0., -100., 500., 0., 0.4, 0.3, true)
    call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 100., 0., 500., 0., 0.4, 0.3, true)
    call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 0., 100., 500., 0., 0.4, 0.3, true)
    call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., -100., 100., 500., 0., 0.4, 0.3, true)
    call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 100., 100., 500., 0., 0.4, 0.3, true)
    call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 100., -100., 500., 0., 0.4, 0.3, true)
    call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., -100., -100., 500., 0., 0.4, 0.3, true)
    
    set maxx = GetRectMaxX(bj_mapInitialPlayableArea)
    set maxy = GetRectMaxY(bj_mapInitialPlayableArea)
    set minx = GetRectMinX(bj_mapInitialPlayableArea)
    set miny = GetRectMinY(bj_mapInitialPlayableArea)
endfunction

endlibrary
 
Level 20
Joined
Apr 22, 2007
Messages
1,960
Just some things I've noticed:
JASS:
set e.v.zvel = e.v.zvel - ((e.mass * grav)/slowmo)
Acceleration is independent of mass. So yeah, remove the e.mass from there.
You should also replace the local locations with global locations and move them instead. It's faster than creating local locations every iteration.
Oh god, your collision detection is O(n2), as in it evaluates a <-> b and then b <-> a. You should rewrite it considering that (I know you will anyway just remember). In my experience, working with loops for collision detection is difficult and slow.
Also, object-oriented ftw.
Otherwise, I'm too lazy to review the rest! :D

Oh also, I use per interval. Thus the "/FPS" everywhere. :D

Aha, I think I found what you did wrong.
JASS:
set s2 = (px*vx + py*vy + pz*vz)*(1. + e2.restitution*e.restitution)/(r*(e2.mass + e.mass) + 0.001)
That should be set s, not s2!

Try that, and tell me what happens.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Ye, I'm going to change the O(n) thing.
And about the acceleration thing, the downward force (gravity) is G = mg where G is the downward force, m is mass and g is 9.81. So it shouldn't be independent of mass, unless I use "weight" instead of mass.
I'm going to try that change after I've slept a little :)

+rep ^^

Edit: omg. "You must spread some Reputation around before giving it to HINDYhat again."
I'll give +rep later then.

Edit2: Ahh. Finally I could give you +repz.
 
Last edited:
Level 20
Joined
Apr 22, 2007
Messages
1,960
Newton's second law:
ΣF = m*a
The sum of all forces on an object is equal to its mass times its resulting acceleration.

It's also known that Fg = m*g (gravitational force) near the surface of the Earth, where g is gravitational constant of acceleration 9.8 m/s2.
Then if gravity is the only force acting on an object:
Fg = m*a
m*g = m*a
g = a
See what I mean?
In other words, watermelons fall at the same rate as pennies, barring air drag and stuff.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Hmm.. According to my physics book you're wrong, but I have experience before that books say something on one page and something completely different on another page.

Well, at least we can agree that heavy guys got a higher terminal velocity than light guys.

Edit: Hmm. I seem to have mixed both seconds and intervals together, lol. I didn't mix it in the wrong way though, but it's still lol. So I've changed everything to FPS instead. Also I've tested that change from s2 to s and I don't know if it's better. I don't get those fatal errors any more, but the entities doesn't bounce so much. They bounce a little though.

Edit2: Everything is working fine now.
 
Last edited:
Level 7
Joined
Mar 8, 2009
Messages
360
Hmm.. According to my physics book you're wrong, but I have experience before that books say something on one page and something completely different on another page.

Well, at least we can agree that heavy guys got a higher terminal velocity than light guys.

Everything that hindyhat said is correct.
EDIT: Except that it only applies to vacuum.

Heavy guys don't necessary have a higher terminal velocity than light guys, their aerodynamic form is more important (if the light guy has a speedo suit on and tries to keep himself vertical, then he will probably have a higher terminal velocity than the heavy guy who will receive higher resistance from the air because he is larger)
 
Level 20
Joined
Apr 22, 2007
Messages
1,960
Your physics books lie. As I mentioned, "watermelons fall at the same rate as pennies, barring air drag and stuff."

Air drag is FD = 0.5ρv2ACD (shamelessly copied from wikipedia)
Where ρ : air density
v : speed
A : cross-sectional area
CD : drag coefficient

From there it's possible to extrapolate a formula for terminal velocity (when acceleration becomes 0, there is no longer a change in velocity). The two acting forces on an object would be gravity and air drag, both equal and opposite:
ΣF = ma = 0
Fg - FD = 0
mg - FD = 0
mg = FD
mg = 0.5ρv2ACD
2mg/ρACD = v2
v = √(2mg/ρACD)
As you can see, terminal velocity is higher if the object has greater mass, but smaller if it has a greater cross-sectional area. There is also an independent drag coefficient factor, which really depends for every single object you're working with.

This is all of course if you're working with air drag. If you aren't working with air drag (and you aren't in your system) then a = g.
 
Status
Not open for further replies.
Top