• 🏆 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!

Physics System

Level 3
Joined
Feb 5, 2008
Messages
18
This is like a combination of knockback and jumping system, units can be knocked across the terrain or flying in the air.

Code:
//============================================================================================================
//Physics Engine v1 by Damurjin
//This system is a combination of knockback and jumping, allowing ground units to be thrown
//in the air and fall realistically.

//Requires Caster System by Vexorian 

//Note: You must import this as a trigger named 'Physics' if you are using GUI

//IMPORTANT:
//DisableMovement, EnableMovement and IsMoveable functions must work in order for 
//ground units to fly in the air properly, 
//unless you are fine with units walking in mid-air
//For default settings to work you must:
//-Change the 'Slow Aura (Tornado)' ability's movement speed reduction to -10
//-Change the 'Targets Allowed' to Self
//-Change the Gameplay Constants - Unit Minimum Speed to 0

//Available Functions:
//*Sets the speed of a unit
// SetSpeed(Unit, unit damager, XYspeed, Zspeed, angle) returns index
//
//*Adds speed to a unit
// AddSpeed(Unit, unit damager, XYspeed, Zspeed, angle, XYspeedLimit) returns index
//
//*Sets the speed of the unit so the unit will land at the destination
// SetSpeedToLoc(Unit, cause, pos, loc, XYspeed) returns nothing
//
//*Sets the speed of the unit so the unit will land at the destination after the time
// SetSpeedToLocTime (Unit, cause, pos, loc, time) returns nothing
//
//Unit - The unit that the movement will be applied to
//damager - The unit that will damage the Physics unit if it hurts itself when landing
//XYspeed - The horizontal speed in units per second
//Zspeed - The vertical speed in units per second
//XYspeedLimit - The limit of XYspeed (0 or less is considered no limit)
//pos - Position of the unit
//loc - Destination of the unit

//There are many settings available such as gravity, fall damage.

//There are 2 options available that can be disabled if you want:
//1. Flying Classification
//   Adds classification to units that are high in the air
//   This might be used to prevent melee units from attacking them,
//   For the default settings, you could set all melee units to be unable to attack 'Ancients'
//   so when a unit goes too high in the air, the Ancient classification is added and melee units
//   are unable to attack them
//2. Melee Attack Disable
//   Disables melee unit attacks that are high in the air  

//Tip: If you want to add additional features, please try to add them in events section

//Notes:
//-Other movement systems will stack
//-While speed arguments are passed as units per second, the data is stored as
// units per execution time so it will be faster, same applies to Gravity.
//============================================================================================================

globals
    //The deceleration towards the ground
    real udg_Gravity = 1000
    //If map limits are set to 0, then it will Get values from playable map rect (Not very accurate)
    real udg_MapLimitMaxX = 0
    real udg_MapLimitMaxY = 0 
    real udg_MapLimitMinX = 0
    real udg_MapLimitMinY = 0
    unit array udg_Physics_unit
    trigger gg_trg_Physics
endglobals

//============================================================================================================
//Movement disabling
//Disables movement of a unit if a ground unit flies high to prevent air walking

function DisableMovement takes unit Unit returns nothing
    call UnitAddAbility(Unit, 'Aasl')
endfunction

function EnableMovement takes unit Unit returns nothing
    call UnitRemoveAbility(Unit, 'Aasl')
    call UnitRemoveAbility(Unit, 'Basl')
endfunction

function IsMoveable takes unit Unit returns boolean
    return not UnitHasBuffBJ(Unit, 'Basl')
endfunction
//============================================================================================================

//============================================================================================================
//Settings

//Returns the Storm Crow Form ability which makes flight possible
//ThIs will be added to the unit when Physics Is applied and removed when Physics Is destroyed
function GetFlightAbilityId takes nothing returns integer
    return 'Arav'
endfunction

//*************************************************************************************************************
//To reduce lag made it so that many Physics objects would run in series rather than parallel
//Example: There are 10 Physics objects and the TimeOut Is 4 and execTime Is 0.01
//
//Time      Indexes of Physics Objects that will execute
//0.00 ---> 0, 4, 8
//0.01 ---> 1, 5, 9
//0.02 ---> 2, 6
//0.03 ---> 3, 7
//0.04 ---> 0, 4, 8
//Sorry if you still don't understand but it is my best explanation :(
//*************************************************************************************************************

//The real execution time of any Physics Object Is timeOut * execTime

//The number of trigger executions that will be skipped
function GetPhysicsTimeOut takes nothing returns integer
    return 4
endfunction

//The time the executions will occur
function GetPhysicsPeriod takes nothing returns real
    return 0.01
endfunction

//The condition when a unit Is considered on the ground
//Note: A value above 0 Is recommended
function onGround takes real height returns boolean
    return height < 10
endfunction

//Returns the factor of XY speed converted into Z speed when Wall bounce occurs
function GetWallBounceUp takes nothing returns real
    return 0.2
endfunction

//Returns the factor of XY speed remaining by when Wall bounce occurs
function GetWallBounceBack takes nothing returns real
    return 0.5
endfunction

//Returns the factor of Z speed that Is converted into damage when landing
function GetFallDamageFactor takes unit Unit returns real
    return 0.
endfunction

function GetFallAttackType takes nothing returns attacktype
    return ATTACK_TYPE_SIEGE
endfunction

function GetMaxPhysics takes nothing returns integer
    return 200
endfunction

//Creates a effect when the unit impacts the ground, effects may be based on damage recieved
function fallArt takes unit Unit, location pos, real dmg returns nothing
    local string path   
    if (dmg <= 0) then
        return
    endif
    if (dmg < 50) then
        set path = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl"
    else    
        if (dmg < 100) then
            set path = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
        else
            set path = "Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl"
        endif
    endif
    call DestroyEffect(AddSpecialEffectTarget(path, Unit, "origin"))
endfunction

//Returns the decrease of speed due to friction
//Note: Values are applied every execution, NOT every second
//      So if you want a decrease of 25 per second, with timeOut = 4 and execTime = 0.01
//      Then the value should be 25 * (4 * 0.01) = 1
function friction takes unit Unit, location pos, real height, boolean flyer returns real
    //Friction only applies when the unit Is on the ground
    if (not onGround(height)) then
        return 0
    endif
    //No friction if on ice
    if (GetTerrainTypeBJ(pos) == 'Nice') then
        return 0
    endif
    //Less friction if on water    
    if (not IsTerrainPathableBJ(pos, PATHING_TYPE_FLOATABILITY)) then
        return 0.6
    endif
    return 1.
endfunction


//End of settings
//============================================================================================================

//============================================================================================================
//Flying Classification
//I find it useful to reserve a unit classification so if a unit flies high,
//it will be treated as air to avoid Melee ground units attacking flying units
function GetFlyingType takes nothing returns unittype
    return UNIT_TYPE_ANCIENT
endfunction

//The condition when a unit Is a flying unit
function IsHigh takes real height returns boolean
    return height > 100
endfunction

//To Disable, make thIs function return false
function FlyingClassification takes nothing returns boolean
    return true
endfunction
//============================================================================================================

//============================================================================================================
//Melee Attack Disable
//Disables Melee attacker's attack to prevent it attacking a ground unit

//Note: thIs method of dIsabling attack will not work for units with cargo in them
function DisableAttack takes unit Unit returns nothing
    call UnitAddAbility(Unit, 'Abun')
endfunction

function EnableAttack takes unit Unit returns nothing
    call UnitRemoveAbility(Unit, 'Abun')
endfunction

//To Disable, make thIs function return false
function MeleeDisable takes nothing returns boolean
    return true
endfunction

//============================================================================================================

//Unless you really know what you are doing you should not modify anything below



//============================================================================================================
//Utility Functions
//These are not actually part of the Physics Engine but are needed by it

//Limits locations so they may not exceed the value of 'Map_Limit'
function MapLimits takes location loc returns location
    local real x = GetLocationX(loc)
    local real y = GetLocationY(loc)
    if (x > udg_MapLimitMaxX or y > udg_MapLimitMaxY or x < udg_MapLimitMinX or y < udg_MapLimitMinY) then
        call RemoveLocation(loc)
        return Location(RMinBJ(RMaxBJ(x, udg_MapLimitMinX), udg_MapLimitMaxX), RMinBJ(RMaxBJ(y, udg_MapLimitMinY), udg_MapLimitMaxY))
    else
        return loc 
    endif
    return null
endfunction

//These Z values are based on the location Z + the unit's flying height
//Note: thIs calculation Is wrong when the unit Is on water or Is a flying unit

//Gets a unit and returns the Z of the unit
function GetUnitZ takes unit Unit returns real
    local real locZ
    local location pos
    set pos = GetUnitLoc(Unit)
    set locZ = GetLocationZ(pos)
    call RemoveLocation(pos)
    return locZ + GetUnitFlyHeight(Unit)
endfunction

//Sets the unit's fly height
function SetUnitZ takes unit Unit, real z returns nothing
    local location pos
    set pos = GetUnitLoc(Unit)
    call SetUnitFlyHeight(Unit, z - GetLocationZ(pos), 1000000000)
    call RemoveLocation(pos)
endfunction

//Polar projection but with Map_Limit restrictions
function PolarProjectionML takes location loc, real dIstance, real angle returns location
    return MapLimits(PolarProjectionBJ(loc, dIstance, angle))
endfunction

//ThIs move unit function differs from the 'SetUnitLoc' function as it ignores pathing
function SetUnitXYLoc takes unit Unit, location loc returns nothing
    call SetUnitX(Unit,GetLocationX(loc))            
    call SetUnitY(Unit,GetLocationY(loc))
endfunction

//Returns true if the location supports the type of pathing
function IsPathable takes location loc, pathingtype path returns boolean
    return not IsTerrainPathableBJ(loc, path)
endfunction

function AddUnitState takes unit Unit, unitstate state, real amount returns nothing
    call SetUnitState(Unit, state, RMaxBJ(GetUnitState(Unit, state) + amount, 0))
endfunction

function IsMoving takes unit Unit returns boolean
    return OrderId2StringBJ(GetUnitCurrentOrder(Unit)) != ""
endfunction 

//End of Utility Functions
//============================================================================================================

//============================================================================================================
//Set and Get functions

function GetPhysicsAngle takes unit Unit returns real
    return GetAttachedReal(Unit, "P_angle")
endfunction

function SetPhysicsAngle takes unit Unit, real angle returns nothing
    call AttachReal(Unit, "P_angle", angle)
endfunction

function GetPhysicsHeight takes unit Unit returns real
    return GetAttachedReal(Unit, "P_height")
endfunction

function SetPhysicsHeight takes unit Unit, real height returns nothing
    call AttachReal(Unit, "P_height", height)
endfunction

function GetPhysicsXYSpeed takes unit Unit returns real
    return GetAttachedReal(Unit, "P_XYspeed")
endfunction

function SetPhysicsXYSpeed takes unit Unit, real speed returns nothing
    call AttachReal(Unit, "P_XYspeed", speed)
endfunction

function GetPhysicsZSpeed takes unit Unit returns real
    return GetAttachedReal(Unit, "P_Zspeed")
endfunction

function SetPhysicsZSpeed takes unit Unit, real speed returns nothing
    call AttachReal(Unit, "P_Zspeed", speed)
endfunction

function GetPhysicsDamager takes unit Unit returns unit
    return GetAttachedUnit(Unit, "P_damager")
endfunction

function SetPhysicsDamager takes unit Unit, unit damager returns nothing
    call AttachObject(Unit, "P_damager", damager)
endfunction

//============================================================================================================

//============================================================================================================
//Events
//These are just spaces where people can add extra functionality without changing my code

//Occurs immediately when the destructor Is called, before cleaning variables
function PhysicsDestroyEvent takes unit Unit returns nothing    
endfunction

//Occurs before anything in the execution for a unit
function PhysicsExecuteEvent takes unit Unit returns nothing    
endfunction

//Occurs when a unit lands on the ground
//The return value Is the Zspeed that the unit will have after the bounce
function PhysicsLandEvent takes unit Unit returns real
    return 0.
endfunction

//============================================================================================================
//Physics Engine

function InitPhysics takes nothing returns nothing
    local integer counter = 0
    local real execTime = GetPhysicsPeriod() * I2R(GetPhysicsTimeOut())
    loop
        set udg_Physics_unit[counter] = null
        set counter = counter + 1
        exitwhen counter >= GetMaxPhysics()
    endloop
    set udg_Gravity = udg_Gravity * execTime * execTime
    if (udg_MapLimitMaxX == 0 and udg_MapLimitMaxY == 0 and udg_MapLimitMinX == 0 and udg_MapLimitMinY == 0) then
        set udg_MapLimitMaxX = GetRectMaxX(bj_mapInitialPlayableArea) - GetRectCenterX(bj_mapInitialPlayableArea)
        set udg_MapLimitMaxY = GetRectMaxY(bj_mapInitialPlayableArea) - GetRectCenterY(bj_mapInitialPlayableArea)
        set udg_MapLimitMinX = GetRectMinX(bj_mapInitialPlayableArea) - GetRectCenterX(bj_mapInitialPlayableArea)
        set udg_MapLimitMinY = GetRectMinY(bj_mapInitialPlayableArea) - GetRectCenterY(bj_mapInitialPlayableArea)
    endif
endfunction

//Handles XY plane
function XYPhysics takes unit Unit, location pos, real height returns nothing
    local location loc
    local real speed = GetPhysicsXYSpeed(Unit)
    //Move the unit to the next location
    set loc = PolarProjectionML(pos, speed, GetPhysicsAngle(Unit))
    call SetUnitXYLoc(Unit, loc)
    //ThIs slows the XY plane speed if the unit Is moving to a higher ground
    if (onGround(height)) then
        //call SetPhysicsXYSpeed(Unit, speed + (GetPhysicsHeight(Unit) - height - GetLocationZ(loc)) * execTime)
    endif
    call RemoveLocation(loc) 
    set loc = null
endfunction

//Sets the bounce angle of a Wall bounce
function SetBounceAngle takes unit Unit, location pos, location newPos returns nothing
    //Check if cliff direction Is horizontal
    local location loc = Location(GetLocationX(pos), GetLocationY(newPos))
    local boolean pathable = IsPathable(loc, PATHING_TYPE_WALKABILITY)
    local real angle = GetPhysicsAngle(Unit)
    call RemoveLocation(loc)
    if (pathable) then
        call SetPhysicsAngle(Unit, 360 - angle)
        return 
    endif
    //Check if cliff direction Is vertical
    set loc = Location(GetLocationX(newPos), GetLocationY(pos))
    set pathable = IsPathable(loc, PATHING_TYPE_WALKABILITY)
    call RemoveLocation(loc)
    if (pathable) then
        call SetPhysicsAngle(Unit, 180 - angle)
        return 
    endif
    //If cannot find then just reflect directly backwards
    call SetPhysicsAngle(Unit, angle + 180)
endfunction

//Will bounce a unit back if it hits a higher cliff
function WallBounce takes unit Unit, location pos, location newPos returns nothing  
    local real z = GetLocationZ(pos) 
    local location newPos = GetUnitLoc(Unit) 
    local real newZ = GetLocationZ(newPos)
    local real XYspeed = GetPhysicsXYSpeed(Unit)
    //Bounce back only if the new location Is higher than the previous and Is unwalkable 
    if (z < newZ and IsTerrainPathableBJ(newPos, PATHING_TYPE_WALKABILITY)) then
        call SetPhysicsZSpeed(Unit, GetPhysicsZSpeed(Unit) + XYspeed * GetWallBounceUp())                
        call SetPhysicsXYSpeed(Unit, GetPhysicsXYSpeed(Unit) * GetWallBounceBack())
        call SetBounceAngle(Unit, pos, newPos)
    endif
    call RemoveLocation(pos)
endfunction

//Handles Z plane
function ZPhysics takes unit Unit, location pos, real height, boolean flyer returns nothing
    local real Zspeed = GetPhysicsZSpeed(Unit)
    local real sign = RSignBJ(Zspeed)
    local real height = GetUnitFlyHeight(Unit)
    local location loc = GetUnitLoc(Unit)
    //Updates the height of the unit
    call SetPhysicsHeight(Unit, RMaxBJ(GetPhysicsHeight(Unit) + Zspeed, GetLocationZ(loc))) 
    call SetUnitZ(Unit, GetPhysicsHeight(Unit))
    //Flyers have their Z speed reduced towards 0
    if (flyer) then
        if (RAbsBJ(Zspeed) > udg_Gravity) then
            call SetPhysicsZSpeed(Unit, Zspeed - sign * udg_Gravity)
        else
            call SetPhysicsZSpeed(Unit, 0)
        endif
        return
    endif
    if (not IsHigh(height)) then
        call WallBounce(Unit, pos, loc)
    endif
    if (onGround(height)) then
        call EnableMovement(Unit)
    else
        //If unit Is not on the ground then it Is affected by gravity
        call SetPhysicsZSpeed(Unit, Zspeed - udg_Gravity)
        //Movement and pathing should be Disabled if it Is going up
        call DisableMovement(Unit)
    endif
    //A classification may be applied if the unit Is flying
    if (FlyingClassification()) then
        if (IsHigh(height)) then
            if (not IsUnitType(Unit, GetFlyingType())) then
                call UnitAddType(Unit, GetFlyingType())
                //A Melee attacker cannot attack while in the air
                if (MeleeDisable() and IsUnitType(Unit, UNIT_TYPE_MELEE_ATTACKER)) then 
                    call DisableAttack(Unit)
                endif
            endif 
        else
            if (IsUnitType(Unit, GetFlyingType())) then
                call UnitRemoveType(Unit, GetFlyingType())   
                call EnableAttack(Unit)     
            endif 
        endif
    endif                   
    call RemoveLocation(loc)
endfunction

//Landing on the ground
function Landing takes unit Unit, location pos, real height returns nothing
    local real Zspeed = GetPhysicsZSpeed(Unit)
    local unit damager = GetPhysicsDamager(Unit)
    local real dmg
    //Occurs when the unit Is on ground and its Z speed Is negative
    if (onGround(height) and Zspeed < 0) then
        //Since it landed, z speed must be absorbed
        call SetPhysicsZSpeed(Unit, PhysicsLandEvent(Unit))
        call SetUnitFlyHeight(Unit, 0, 999999999)
        //Damage the unit
        if (GetFallDamageFactor(Unit) > 0) then
            set dmg = RMaxBJ(dmg, -1 * Zspeed * GetFallDamageFactor(Unit))
            call fallArt(Unit, pos, dmg)
            //Locust units cannot be damaged so reduce life instead
            if (GetUnitAbilityLevel(Unit,  'Aloc') == 1 or damager == null) then
                call AddUnitState(Unit, UNIT_STATE_LIFE, -dmg)
            else
                call UnitDamageTarget(damager, Unit, dmg, false, true, GetFallAttackType(), DAMAGE_TYPE_NORMAL, null)
            endif
        endif
        call EnableMovement(Unit)
    endif
endfunction

//Destructor function, calling thIs will clean up all variables used
function PhysicsDestroy takes unit Unit, integer num returns nothing
    call EnableMovement(Unit)
    call PhysicsDestroyEvent(Unit)
    call SetUnitFlyHeight(Unit, 0, 999999999)
    call SetPhysicsAngle(Unit, 0)
    call SetPhysicsHeight(Unit, 0)  
    call SetPhysicsZSpeed(Unit, 0)  
    call SetPhysicsXYSpeed(Unit, 0)
    call SetPhysicsDamager(Unit, null)
    call UnitRemoveAbility(Unit, GetFlightAbilityId())
    set udg_Physics_unit[num] = null
endfunction

//The function that will be called every loop                   
function PhysicsExecute takes integer num returns nothing
    local boolean flyer = not IsUnitType(udg_Physics_unit[num], UNIT_TYPE_GROUND)
    local real height = GetUnitFlyHeight(udg_Physics_unit[num])
    local location pos
    local real XYspeed = GetPhysicsXYSpeed(udg_Physics_unit[num])
    //If the unit has been removed, then set the physics unit to null
    if (GetUnitName(udg_Physics_unit[num]) == null) then
        set udg_Physics_unit[num] = null
    endif
    call PhysicsExecuteEvent(udg_Physics_unit[num])
    set pos = GetUnitLoc(udg_Physics_unit[num])
    call Landing(udg_Physics_unit[num], pos, height)
    //Stops when:
    //  -The unit Is not moving in the XY plane
    //  -The unit Is not moving in the Z plane
    //  -The unit Is on the ground or Is a flying unit
    if (XYspeed <= 0 and GetPhysicsZSpeed(udg_Physics_unit[num]) == 0 and (onGround(height) or flyer)) then 
        call PhysicsDestroy(udg_Physics_unit[num], num)
    else
        call XYPhysics(udg_Physics_unit[num], pos, height)
        call SetPhysicsXYSpeed(udg_Physics_unit[num], XYspeed - friction(udg_Physics_unit[num], pos, height, flyer))
        call ZPhysics(udg_Physics_unit[num], pos, height, flyer)
    endif 
    call RemoveLocation(pos)
endfunction

function PhysicsExecution takes nothing returns nothing
    local integer count = ModuloInteger(GetTriggerExecCount(gg_trg_Physics), GetPhysicsTimeOut())
    loop
        if (udg_Physics_unit[count] != null) then
            call PhysicsExecute(count)
        endif
        set count = count + GetPhysicsTimeOut()
        exitwhen count >= GetMaxPhysics()
    endloop
endfunction

//End of Physics Engine
//============================================================================================================

//Function for returning array index of a Physics unit
function findPhysicsUnit takes unit Unit returns integer
    local integer counter = 0
    loop
        if (Unit == udg_Physics_unit[counter]) then
            return counter
        endif
        set counter = counter + 1
        exitwhen counter >= GetMaxPhysics()
    endloop
    return -1
endfunction

//Physics constructor
function Physics takes unit Unit, unit damager, real XYspeed, real Zspeed, real angle returns integer   
    local integer index = findPhysicsUnit(null) 
    local real execTime = GetPhysicsPeriod() * I2R(GetPhysicsTimeOut())
    if (index == -1 or GetUnitDefaultMoveSpeed(Unit) == 0) then
        return -1
    endif
    set udg_Physics_unit[index] = Unit         
    call SetPhysicsAngle(Unit, angle)
    call SetPhysicsHeight(Unit, GetUnitZ(Unit))
    call SetPhysicsXYSpeed(Unit, XYspeed * execTime)
    call SetPhysicsZSpeed(Unit, Zspeed * execTime)
    call SetPhysicsDamager(Unit, damager)
    call UnitAddAbility(Unit, GetFlightAbilityId())
    return index
endfunction

//Set force to a unit
function SetForceByIndex takes integer index, real XYspeed, real Zspeed, real angle, real XYspeedLimit returns nothing
    local real execTime = GetPhysicsPeriod() * I2R(GetPhysicsTimeOut())
    if (XYspeedLimit > 0) then
        set XYspeed = RMinBJ(XYspeed, XYspeedLimit)
    endif
    call SetPhysicsAngle(udg_Physics_unit[index], angle)
    call SetPhysicsXYSpeed(udg_Physics_unit[index], XYspeed * execTime)
    call SetPhysicsZSpeed(udg_Physics_unit[index], Zspeed * execTime)
endfunction

//============================================================================================================
//Physics Interface
//These are the functions you should use

//Set speed to a unit
function SetSpeed takes unit Unit, unit damager, real XYspeed, real Zspeed, real angle returns integer
    local integer index = findPhysicsUnit(Unit)
    if (index == -1) then
        return Physics(Unit, damager, XYspeed, Zspeed, angle)
    endif
    call SetForceByIndex(index, XYspeed, Zspeed, angle, 0)
    return index
endfunction

//Adds speed to a unit
function AddSpeed takes unit Unit, unit damager, real XYspeed, real Zspeed, real angle, real XYspeedLimit returns integer
    local integer index = findPhysicsUnit(Unit)
    local real oldXYspeed
    local real oldAngle
    local real Xspeed
    local real Yspeed 
    local real execTime = GetPhysicsPeriod() * I2R(GetPhysicsTimeOut())
    if (index == -1) then
        return Physics(Unit, damager, XYspeed, Zspeed, angle)
    endif
    set oldXYspeed = GetPhysicsXYSpeed(Unit)
    set oldAngle = GetPhysicsAngle(Unit)
    if (XYspeedLimit < 0 and oldXYspeed > XYspeedLimit) then
        return index
    endif
    set Xspeed = oldXYspeed / execTime * CosBJ(oldAngle) + XYspeed * CosBJ(angle)
    set Yspeed = oldXYspeed / execTime * SinBJ(oldAngle) + XYspeed * SinBJ(angle)
    set XYspeed = SquareRoot(Pow(Xspeed, 2) + Pow(Yspeed, 2))
    set Zspeed = GetPhysicsZSpeed(Unit) / execTime + Zspeed
    set angle = Atan2BJ(Yspeed, Xspeed)
    call SetForceByIndex(index, XYspeed, Zspeed, angle, XYspeedLimit)
    return index
endfunction 

//Get a Zspeed so that the unit will land at the location
function GetZspeedToLoc takes unit Unit, location pos, location loc, real XYspeed returns real
    local real Zheight = GetUnitFlyHeight(Unit)
    local real time = DistanceBetweenPoints(pos, loc) / XYspeed 
    local real execTime = GetPhysicsPeriod() * I2R(GetPhysicsTimeOut())
    return Zheight / time + 0.5 * (udg_Gravity / execTime / execTime) * time
endfunction  

//Adds force so that the unit will land at the location
function SetSpeedToLoc takes unit Unit, unit damager, location pos, location loc, real XYspeed returns nothing
    local real angle = AngleBetweenPoints(pos, loc)
    local real Zspeed = GetZspeedToLoc(Unit, pos, loc, XYspeed)
    call SetSpeed(Unit, damager, XYspeed, Zspeed, angle)
endfunction 

//Adds force so that the unit will land at the location after the duration
function SetSpeedToLocTime takes unit Unit, unit damager, location pos, location loc, real time returns nothing
    call SetSpeedToLoc(Unit, damager, pos, loc, DistanceBetweenPoints(pos, loc) / time)
endfunction

//End of Physics Interface
//============================================================================================================


//===========================================================================
function InitTrig_Physics takes nothing returns nothing
    set gg_trg_Physics = CreateTrigger(  )
    call TriggerAddAction(gg_trg_Physics, function PhysicsExecution)
    call TriggerRegisterTimerEventPeriodic( gg_trg_Physics, GetPhysicsPeriod() )
endfunction

I have been using it for my maps for quite awhile but it used a ton of global variables, only recently adapted it to cscache.

This code is very efficient, you can have a lot (for a decent computer at least) of units knockback without much lag.

This only for units with foot movement type at the moment.
There is a problem with unit's Z value on water.

Thx to Vexorian for the Caster System
 

Attachments

  • PhysicsTest.w3x
    44.4 KB · Views: 161
Level 22
Joined
Dec 31, 2006
Messages
2,216
Use
JASS:
 tags.
I see you used some BJ's in there, remove those. I also see you use locations when it's not needed, try to use x,y coordinates instead as much as possible.
 
Level 14
Joined
Nov 18, 2007
Messages
816
[x]Graveyard this.
For various reasons:
  • using locations
  • using slow BJs
  • using slow explicit conversions of data types
  • using degrees
  • inexistent encapsulation
  • using gamecache
  • bad portability
  • using vJass without using all its benefits
 
Level 9
Joined
May 23, 2009
Messages
422
I have not test this yet,but it must be flawless to pass the approval...
Find mistakes yourself,listen to users,update your JASS,get your JASS approved...

Thanks,
:spell_breaker: The_Grapist :spell_breaker:
 
this is not a physics engine, it's just a simulation engine.

A true physics engine would allow you to add forces to objects and set properties to them, like mass, this just do maths to simulate physics.

There's also no use of momentuim, impulse or other important elements which a programmer would most likely use. For instance, you only try to simulate perfactly elastic colissions, in a very bad way since you not even calculate the velocities of the objects and their direction, not even assuming that the mass of the ground/wall is >> than the object and use the Center of Mass properties for the particle system to solve the linear momemtum formula.

There's also no support for dynamics of rotation, angular velocity and balancing of rigid bodies. Furthermore, There's no support for Rigid bodies and atleast instanced geometry for detecting colissions.

Yet, the biggest lacking part of all this system is: "A Vector System!" How the fuck can you make a physics system without a vector system? is quite pointless.

This system is very far from being called a physics engine.
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
There's also no support for dynamics of rotation, angular velocity and balancing of rigid bodies

Meh, I don't really know how many wc3 map makers would actually care about rotational dynamics, angular momentum, gyroscopic forces, etc. I think most people are impressed when they see a ball bounce off a cliff in wc3, lol.

Yet, the biggest lacking part of all this system is: "A Vector System!" How the fuck can you make a physics system without a vector system? is quite pointless.

You can so make a physics system without a vector system. It'll just be really, really, damn hard.

Anyway, this code for this system is so convoluted and inefficient...If you didn't use vJASS and said it was for people who can't use/don't know how to use/don't want to use vJASS then it might be considered somewhat acceptable.

But as it is stuff like this should not exist:

JASS:
function GetWallBounceUp takes nothing returns real
    return 0.2
endfunction

//Returns the factor of XY speed remaining by when Wall bounce occurs
function GetWallBounceBack takes nothing returns real
    return 0.5
endfunction

You should use constant global variables, i.e.:

JASS:
globals
    constant real WALL_BOUNCE_UP = 0.2
    constant real WALL_BOUNCE_BACK = 0.5
endglobals

And don't use locations everywhere. Use x y z coordinates and only locations where it is absolutely necessary (like to get z value of a point).
 
Top