| 04-06-2009, 01:45 PM | #1 | |
Note - This system does not handle any physics, this is purely for moving units in different ways. Documentation: 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 ===================================================================================== Now to the code: 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 Changelog:
|
| 04-06-2009, 02:26 PM | #2 |
Aren't velocities physics? |
| 04-06-2009, 02:56 PM | #3 |
Yes you can use them in physics but in this system I only use them for movement, but that's also a sort of physics :) |
| 04-16-2009, 02:33 PM | #4 |
Blah disappointment, when I read "ProjectileSystem" I thought it would do projectiles like blizz' attacks and spell missiles. So it is like a 3d collision missile. I guess some will find an use. Why do people use [jass] for documentation? that's non-sense. |
| 05-19-2009, 12:40 AM | #5 |
Now Vex, can't blame one for trying. I must say I was also disappointed it wasn't a missile system, but good work nonetheless. |
| 06-11-2009, 12:24 PM | #6 | |
Quote:
I agree...but i find this useful ![]() |
| 06-18-2009, 03:57 PM | #7 |
Fixed the movement over cliffs. |
