Note - This system does not handle any physics, this is purely for moving units in different ways.
JASS:
=====================================================================================
------------------------ Projectile System made by Gwypaas -------------------------
Use local Projectile p = Projectile.create(<unit>, <Remove Projectile?>) to create a new particle, if you set the boolean to true
then the projectile will be removed upon finish of the movement. You can also do this with any of the premade types or your own.
then the syntax would be
local <Yourtype> p = <YourType.create(<unit>, <Remove Projectile?>)
Then choose what type of movement you want.
Then let the system do the rest <3
NOTE --- This system DOES NOT handle any physics.
This system is able to handle premade function pretty much "inserts" code into the timer callback
You can see the usage of theese by viewing the "Jump", "Slide For Time" and "SLide Towards Unit"
methods.
This system is coded upon the polymorphism part of JASSHelper and when you create a new struct then extend it from on of the premade types.
Check out the heavily commented Jump Struct for further information.
These are the interface methods that you can use:
method onLoop takes nothing returns nothing
This method gets called on every interval and no of the premade types uses it.
method privOnLoop takes nothing returns nothing
This is the onloop method that the premade stuff uses.
method onReach takes nothing returns nothing
This method gets called upon reach of the target. Note - The premade types does not use it.
With the use of the Projectile.create(<unit>, <Should get Removed?>) you create a basic projectile that
If you use custom methods and wants to destroy the projectile then set the projectiles "end" variable to true
and it will be destroyed on the next timer interval.
The theta = The normal angle you use when you calculate 2d stuff and it's of course in radians
the phi = The "height" angle that specifies at which height direction it should go and it's also radians.
=====================================================================================
-------------------- Premade methods in the Projectile struct ----------------------
method Slide takes real x, real y, real speed returns nothing
method SlideXYZ takes real x, real y, real z, real speed returns nothing
method SlideTowardsAngle takes real theta, real phi, real speed, real distance returns nothing
-------------------- Premade methods in the Extenions structs ----------------------
method Jump takes real x, real y, real speed, real maxH returns nothing
method SlideTowardsUnit takes unit target, real speed returns nothing
method SlideXYZLiveTime takes real x, real y, real z, real speed, real TimeLiving returns nothing
------------------- Premade methods to get the mathematic values -------------------
These methods are inline friendly
method GetPhi takes real x, real y, real z returns real
method GetTheta takes real x, real y returns real
method GetDistance takes real x, real y, real z returns real
method SetVelocityX takes nothing returns nothing
method SetVelocityY takes nothing returns nothing
method SetVelocityZ takes nothing returns nothing
These methods are not inline friendly
method SetVelocities takes nothing returns nothing
method SetEverything takes real x, real y, real z returns nothing
=====================================================================================
JASS:
library ProjectileSystem
globals
// WARNING DO NOT MAKE THE VALUE BELOW TOO SMALL OR THE PARTICLE WILL CONTINUE TO SLIDE FOREVER.
private constant real FINISH_THRESHOLD = 10 // How close it must be to the target to be considered finished.
private constant real MIN_SPEED = .025 // The minimum speed a projectile can have before it's considered finished
constant real PROJECTILE_TIMER_PERIOD = 0.02
private constant boolean EXTRA_DEBUG_MODE = false // The "extra" debug mode which shows more messages.
private constant real FPS = 1/PROJECTILE_TIMER_PERIOD
private Projectile array Datas
private integer N = 0
private timer T = CreateTimer()
endglobals
interface ProjectileBase
boolean end // Setting this to true will destroy the struct on the next interval.
boolean remUnit // Set this to true if you want to remove the unit
unit u // The projectile
real x // The current x
real y // The current y
real z // The current z
real resistance = 1// If you want the projectiles to have friction or similar
//then use the right formula to get the resistance the system should use and set
// this variables to it. resistance 1 = no resistance, less than 1 = slowing down, more than 1 = speeding up.
// Velocities
real xV
real yV
real zV
real tx // The target x
real ty // The target y
real tz // The target z
real theta // Angle
real phi //Z Angle
real rho // radius / speed
real distLeft // The distance that is left to the target
static location tloc = Location(0,0) // The location used to determine terrain height
method onLoop takes nothing returns nothing defaults nothing // What you do on each loop
method privOnLoop takes nothing returns nothing defaults nothing // What the struct you are extending does on each loop
method onReach takes nothing returns nothing defaults nothing // What you do when the projectile reaches it's target
endinterface
struct Projectile extends ProjectileBase
// Some inline friendly methods for easier creating of your own extensions
method GetPhi takes real x, real y, real z returns real
return Atan2(SquareRoot((x-.x) * (x-.x) + (y-.y) * (y-.y)), (z-.z))
endmethod
method GetTheta takes real x, real y returns real
return Atan2((y - .y), (x - .x))
endmethod
method GetDistance takes real x, real y, real z returns real
return SquareRoot((.x-x) * (.x-x) + (.y-y) * (.y-y) + (.z-z) * (.z-z))
endmethod
// Inline friendly Set Methods
method SetVelocityX takes nothing returns nothing
set .xV = Sin(.phi) * Cos(.theta) * .rho
endmethod
method SetVelocityY takes nothing returns nothing
set .yV = Sin(.phi) * Sin(.theta) * .rho
endmethod
method SetVelocityZ takes nothing returns nothing
set .zV = Cos(.phi) * .rho
endmethod
// Not inline friendy but easier to use.
method SetVelocities takes nothing returns nothing
set .xV = Sin(.phi) * Cos(.theta) * .rho
set .yV = Sin(.phi) * Sin(.theta) * .rho
set .zV = Cos(.phi) * .rho
endmethod
method SetEverything takes real x, real y, real z returns nothing
set .phi = Atan2(SquareRoot((x-.x) * (x-.x) + (y-.y) * (y-.y)), (z-.z))
set .theta = Atan2((y - .y), (x - .x))
set .distLeft = SquareRoot((.x-x) * (.x-x) + (.y-y) * (.y-y) + (.z-z) * (.z-z))
set .xV = Sin(.phi) * Cos(.theta) * .rho
set .yV = Sin(.phi) * Sin(.theta) * .rho
set .zV = Cos(.phi) * .rho
endmethod
static method Callback takes nothing returns boolean
local Projectile p
local integer i = N
local real sl
local boolean b
local real tz
loop
exitwhen i == 0
set p = Datas[i]
set sl = (RAbsBJ(p.xV) + RAbsBJ(p.yV) + RAbsBJ(p.zV)) / 3
set b = sl <= MIN_SPEED and sl >= -MIN_SPEED
if p.distLeft <= FINISH_THRESHOLD or p.end == true or b then
if p.onReach.exists == true then
call p.onReach()
endif
call p.destroy()
set Datas[i] = Datas[N]
set N = N - 1
if N == 0 then
call PauseTimer(T)
endif
else
set p.xV = p.xV * p.resistance
set p.yV = p.yV * p.resistance
set p.zV = p.zV * p.resistance
set p.x = p.x + p.xV
set p.y = p.y + p.yV
set p.z = p.z + p.zV
call MoveLocation(.tloc, p.x, p.y)
set tz = GetLocationZ(.tloc)
if p.onLoop.exists == true then
call p.onLoop()
endif
if p.privOnLoop.exists == true then
call p.privOnLoop()
endif
call SetUnitX(p.u, p.x)
call SetUnitY(p.u, p.y)
call SetUnitFlyHeight(p.u, p.z - tz, 0)
call SetUnitFacing(p.u, p.theta * bj_RADTODEG)
// I know that this doesn't seem efficient but I need this for moving targets :)
set p.distLeft = p.GetDistance(p.tx, p.ty, p.tz)
endif
set i = i-1
endloop
return false
endmethod
method Start takes nothing returns nothing
if N == 0 then
call TimerStart (T, PROJECTILE_TIMER_PERIOD, true, function Projectile.Callback)
endif
set N = N + 1
set Datas[N] = this
endmethod
static method create takes unit u, boolean RemoveProjectile returns Projectile
local Projectile p = .allocate()
set p.u = u
set p.x = GetUnitX(p.u)
set p.y = GetUnitY(p.u)
set p.z = GetUnitFlyHeight(p.u)
set p.resistance = 1
call UnitAddAbility(p.u, 'Amrf')
call UnitRemoveAbility(p.u, 'Amrf')
set p.end = false
set p.remUnit = RemoveProjectile
return p
endmethod
method Slide takes real x, real y, real speed returns nothing
set .rho = speed
set .distLeft = .GetDistance(x,y,0)
set .phi = .GetPhi(x,y,0)
set .theta = .GetTheta(x,y)
call .SetVelocityX()
call .SetVelocityY()
call .SetVelocityZ()
set .tx = x
set .ty = y
set .tz = 0
call .Start()
endmethod
method SlideXYZ takes real x, real y, real z, real speed returns nothing
set .rho = speed
set .theta = .GetTheta(x,y)
set .phi = .GetPhi(x,y,z)
set .distLeft = .GetDistance(x,y,z)
call .SetVelocityX()
call .SetVelocityY()
call .SetVelocityZ()
set .tx = x
set .ty = y
set .tz = z
call .Start()
endmethod
method SlideTowardsAngle takes real theta, real phi, real speed, real distance returns nothing
set .rho = speed
set .theta = theta
set .phi = phi
set .tx = .x + (Sin(.phi) * Cos(.theta)) * distance
set .ty = .y + (Sin(.phi) * Sin(.theta)) * distance
set .tz = .z + Cos(.phi) * distance
set .distLeft = .GetDistance(.tx, .ty, .tz)
call .SetVelocityX()
call .SetVelocityY()
call .SetVelocityZ()
call .Start()
endmethod
method onDestroy takes nothing returns nothing
debug if EXTRA_DEBUG_MODE then
debug call BJDebugMsg("Instance ID = " + I2S(this) +" || End Results: x = " + R2S(GetUnitX(.u)) + " : y = " + R2S(GetUnitY(.u)) + " : z = " + R2S(GetUnitFlyHeight(.u)))
debug else
debug call BJDebugMsg("Instance ID = " + I2S(this))
debug endif
if .remUnit then
call RemoveUnit(.u)
endif
set .u = null
endmethod
endstruct
endlibrary
JASS:
//=====================================================================================//
// ------------------- Projectile System Extensions made by Gwypaas -------------------//
//
// This is the library that you create your own projectile types in.
// Check out the "examples" below if you want more info
//
// Note, you NEED to do the typecasting that I do with the "local Jump p = pp" beacause
// otherwise it will give you syntax error because of how function interfaces are constructed
//
//=====================================================================================//
library ProjectileSystemExtensions requires ProjectileSystem
struct Jump extends Projectile // This is what makes it a projectile
// Private variables for the method
real jextra
real totalDist
real distDone
// The private method that gets called every interval
method privOnLoop takes nothing returns nothing
set .z = (4 * .jextra / .totalDist) * (.totalDist - .distDone) * (.distDone / .totalDist)
// Credits to Moyack and Spec for this formula.
set .distDone = .distDone + .rho
endmethod
// The method you use to start the "sliding" of your Jump
method Jump takes real x, real y, real speed, real maxH returns nothing
local real td = .GetDistance(x, y,0) // Getting the distance
set .rho = speed // Setting the speed
set .theta = .GetTheta(y, x) // Getting the XY angle
set .phi = .GetPhi(x,y,0) // GEtting the Z angle
// Setting hte private variables
set .distLeft = td
set .totalDist = td
set .jextra = maxH
set .distDone = 0
// Setting the Velocities based on your rho, theta and phi
call .SetVelocityX()
call .SetVelocityY()
call .SetVelocityZ()
// Setting the starting position
set .tx = x
set .ty = y
set .tz = 0
call .Start() // Fire the sliding up
endmethod
endstruct
struct SlideTowardsUnit extends Projectile
unit target
method privOnLoop takes nothing returns nothing
set .tx = GetUnitX(.target)
set .ty = GetUnitY(.target)
set .tz = GetUnitFlyHeight(.target)
set .theta = .GetTheta(.tx, .ty)
set .phi = .GetPhi(.tx, .ty, .tz)
call .SetVelocityX()
call .SetVelocityY()
call .SetVelocityZ()
endmethod
method SlideTowardsUnit takes unit target, real speed returns nothing
local real x = GetUnitX(target)
local real y = GetUnitY(target)
local real z = GetUnitFlyHeight(target)
set .target = target
set .rho = speed
set .theta = .GetTheta(x,y)
set .phi = .GetPhi(x,y,z)
set .distLeft = .GetDistance(x,y,z)
call .SetVelocityX()
call .SetVelocityY()
call .SetVelocityZ()
set .tx = x
set .ty = y
set .tz = z
call .Start()
endmethod
method onDestroy takes nothing returns nothing
set .target = null
endmethod
endstruct
struct SlideXYZLiveTime extends Projectile
real maxTime
real timeDone
method privOnLoop takes nothing returns nothing
if .timeDone >= .maxTime then
set .end = true
endif
set .timeDone = .timeDone + PROJECTILE_TIMER_PERIOD
endmethod
method SlideXYZLiveTime takes real x, real y, real z, real speed, real TimeLiving returns nothing
set .timeDone = 0
set .maxTime = TimeLiving
set .rho = speed
set .theta = .GetTheta(x,y)
set .phi = .GetPhi(x,y,z)
set .distLeft = .GetDistance(x,y,z)
call .SetVelocityX()
call .SetVelocityY()
call .SetVelocityZ()
set .tx = x
set .ty = y
set .tz = z
call .Start()
endmethod
endstruct
endlibrary
180609 - Made it work better with cliffs
130309 - Made it use methods interfaces instead of function interfaces and also rewrote parts of the documentation.
070209 - Added the "Slide towards angle" method for the people that needs it.
300109(2) - Made so the user can select if a Projectile should get removed, also added movement resistance and made so all projectiles that moves slower than a specified speed are considered finished, also updated the documentation a bit.
300109 - It now uses velocities in some way but I'm not sure if it's right. I also made methods to set the velocities that are inline friendly and one that sets all but isn't inline friendly, I also made a "Set Everything" method for the lazy people, calling that will set the velocities and angles.
290109 - Made it alot easier to use by making the extensions not using the USF function that was meant to be used by the user, It's also easier to create your own types now since I've created the .GetPhi/Theta/Distance methods so you don't need to CnP the ones that I used. The methods will also be inlined due to how I made them.
130309 - Made it use methods interfaces instead of function interfaces and also rewrote parts of the documentation.
070209 - Added the "Slide towards angle" method for the people that needs it.
300109(2) - Made so the user can select if a Projectile should get removed, also added movement resistance and made so all projectiles that moves slower than a specified speed are considered finished, also updated the documentation a bit.
300109 - It now uses velocities in some way but I'm not sure if it's right. I also made methods to set the velocities that are inline friendly and one that sets all but isn't inline friendly, I also made a "Set Everything" method for the lazy people, calling that will set the velocities and angles.
290109 - Made it alot easier to use by making the extensions not using the USF function that was meant to be used by the user, It's also easier to create your own types now since I've created the .GetPhi/Theta/Distance methods so you don't need to CnP the ones that I used. The methods will also be inlined due to how I made them.
Attachments
Last edited: