- Joined
- Feb 22, 2006
- Messages
- 752
XEMissile by Anitarf was developed, is more efficient and makes this deprecated: http://www.wc3c.net/showthread.php?t=109660
Hey, remember those projectiles in CS that never made it to xe? Well, some time last year I got tired of waiting for Vex to make an xeprojectile system, so I made one myself. I tried to make it as similar as possible to xecollider so I wouldn't have to remember two completely different APIs, and hopefully this helps other people as well.
I hope I'm not being too presumptious naming this xeprojectile, but this was purely to make it fit with the rest of the xe modules.
Changelog
v1.1.0
Credits
Requires
(xe)projectile v1.1.0
Hey, remember those projectiles in CS that never made it to xe? Well, some time last year I got tired of waiting for Vex to make an xeprojectile system, so I made one myself. I tried to make it as similar as possible to xecollider so I wouldn't have to remember two completely different APIs, and hopefully this helps other people as well.
I hope I'm not being too presumptious naming this xeprojectile, but this was purely to make it fit with the rest of the xe modules.
Changelog
v1.1.0
- Removed all the delegate abuse from the code preventing xeprojectile.destroy() from causing bugs and simply used jasshelper's 0.9.Z.* support for .destroy() overriding to make xeprojectile.destroy() private.
- No actual changes. Just bumped up version number since v0.9.1 seemed stable enough to push it out of beta.
- Refactored internal code to make system more robust when it comes to calling xeprojectile.destroy()
- Fixed some coding bugs
- Fixed divide by 0 bug
- Changed documentation layout
- Fixed documentation error where it claimed instantiating xeprojectile itself does nothing. In fact you can still have a moving projectile-like special effect just by using the xeprojectile struct.
- Fixed bug where a location was unnecessarily being created in the constructor
- Fixed bug where .targetLoc was not being removed properly after the projectile is destroyed
- Fixed bug where projectiles would not fly toward the correct z-value if the terrain z values of the projectile's location and the target location were different
- Deleted unnecessary local location variable in xeprojectile.executeMovement()
- First public release
Credits
- Vexorian for making xe and the projectile functions in CS
Requires
- xebasic by Vexorian
- xefx by Vexorian
- jasshelper 0.9.Z.0+
Code Library
JASS:
library xeprojectile requires xebasic, xefx
//*********************//
// xeprojectile //
// By: aznricepuff //
// v1.1.0 //
//*********************//
struct xeprojectile
private delegate xefx fx
private location loc = null
private location targetLoc = null
private real absZ = 0.0
private real targX = 0.0
private real targY = 0.0
private real targZ = 0.0
real speed = 0.0
real arc = 0.0
unit target = null
real targetZOffset = 0.0
boolean destroyOnHit = true
integer data = 0
boolean start = false
private boolean toDestroy = false
private static xeprojectile array v
private static integer n = 0
private static timer t
static method create takes real x, real y, real z, real dir returns xeprojectile
local xeprojectile this = xeprojectile.allocate()
set this.fx = xefx.create(x, y, dir)
set this.loc = Location(x, y)
set this.z = z
set this.targetLoc = Location(x, y)
set this.targetX = x
set this.targetY = y
set this.targetZ = z
set .v[.n] = this
if (.n == 0) then
call TimerStart(.t, XE_ANIMATION_PERIOD, true, function xeprojectile.executeMovement)
endif
set .n = .n + 1
return this
endmethod
method operator x= takes real x returns nothing
call MoveLocation(this.loc, x, this.y)
set this.fx.x = x
set this.fx.z = this.absZ - GetLocationZ(this.loc)
endmethod
method operator y= takes real y returns nothing
call MoveLocation(this.loc, this.x, y)
set this.fx.y = y
set this.fx.z = this.absZ - GetLocationZ(this.loc)
endmethod
method operator z= takes real z returns nothing
set this.absZ = z + GetLocationZ(this.loc)
set this.fx.z = z
endmethod
method operator targetX takes nothing returns real
return this.targX
endmethod
method operator targetY takes nothing returns real
return this.targY
endmethod
method operator targetZ takes nothing returns real
call MoveLocation(this.targetLoc, this.targX, this.targY)
return this.targZ - GetLocationZ(this.targetLoc)
endmethod
method operator targetX= takes real x returns nothing
set this.targX = x
call MoveLocation(this.targetLoc, this.targX, this.targY)
endmethod
method operator targetY= takes real y returns nothing
set this.targY = y
call MoveLocation(this.targetLoc, this.targX, this.targY)
endmethod
method operator targetZ= takes real z returns nothing
set this.targZ = z + GetLocationZ(this.targetLoc)
endmethod
method terminate takes nothing returns nothing
set this.toDestroy = true
endmethod
private method destroy takes nothing returns nothing
call this.fx.destroy()
call RemoveLocation(this.loc)
call RemoveLocation(this.targetLoc)
call this.deallocate()
endmethod
stub method onHit takes nothing returns nothing
endmethod
stub method onTick takes nothing returns nothing
endmethod
static method executeMovement takes nothing returns nothing
local integer i = 0
local real curX
local real curY
local real curZ
local real targetX
local real targetY
local real targetZ
local real dx
local real dy
local real increment
local real theta
local real phi
local real distanceRemaining
local real zAccel
local real zSpeed
local real time
local boolean done
local xeprojectile this
loop
exitwhen (i >= .n)
set this = .v[i]
if (this.toDestroy) then
call this.destroy()
set .v[i] = .v[.n - 1]
set .n = .n - 1
set i = i - 1
if (.n == 0) then
call PauseTimer(.t)
endif
elseif (this.start) then
set done = false
set curX = this.x
set curY = this.y
set curZ = this.absZ
set targetX = this.targX
set targetY = this.targY
set targetZ = this.targZ
if (this.target != null) then
if (GetWidgetLife(this.target) < 0.405) then
set this.target = null
else
set targetX = GetUnitX(this.target)
set targetY = GetUnitY(this.target)
call MoveLocation(.targetLoc, targetX, targetY)
set targetZ = GetUnitFlyHeight(this.target) + this.targetZOffset + GetLocationZ(.targetLoc)
endif
endif
set dx = targetX - curX
set dy = targetY - curY
set theta = Atan2(dy, dx)
set this.xyangle = theta
if (this.speed > 0) then
set increment = this.speed * XE_ANIMATION_PERIOD
set distanceRemaining = SquareRoot(dx * dx + dy * dy)
if (distanceRemaining <= increment) then
set this.x = targetX
set this.y = targetY
set this.absZ = targetZ
set this.fx.z = this.absZ - GetLocationZ(this.loc)
set done = true
else
set this.x = curX + increment * Cos(theta)
set this.y = curY + increment * Sin(theta)
set zAccel = this.arc * 8000
set time = distanceRemaining / this.speed
set zSpeed = (targetZ - curZ + 0.5 * zAccel * time * time) / time
set phi = Atan2(zSpeed, this.speed)
set this.zangle = phi + bj_DEGTORAD
set this.absZ = curZ + zSpeed * XE_ANIMATION_PERIOD
set this.fx.z = this.absZ - GetLocationZ(this.loc)
endif
endif
set distanceRemaining = (this.x - targetX) * (this.x - targetX) + (this.y - targetY) * (this.y - targetY)
if (done or distanceRemaining <= 20.0) then
set this.start = false
call this.onHit()
if (this.destroyOnHit) then
set this.toDestroy = true
endif
else
call this.onTick()
endif
endif
set i = i + 1
endloop
endmethod
private static method onInit takes nothing returns nothing
set .t = CreateTimer()
endmethod
endstruct
endlibrary
Documentation
Code:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
======================================= xeprojectile API ========================================
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-------------
Version 1.1.0
-------------
This module requires xebasic and xefx.
To make a projectile, you first need to create a struct that extends xeprojectile. Trying to
instantiate xeprojectile itself will do very little (it will work, but the most you could do
with it is create a moving, projectile-like special effect). In your struct you can make as many
fields and methods as necessary, allowing for lots of customization, as long as they dont
conflict with the members in xeprojectile.
The xeprojectile struct delegates a bunch of stuff to xefx (like xecollider). So anything xefx
can do, xeprojectile can also do. Check out xefx's documentation for more info.
====================================== struct xeprojectile ======================================
The xeprojectile struct is the core of this module. By itself, it can simulate a moving special
effect with a trajectory modeled after normal projectiles in wc3. By extending this struct with
others and overriding the xeprojectile.onHit() and xeprojectile.onTick() methods, however, you
can create customized projectiles that execute specific code when they hit their targets and
every XE_ANIMATION_PERIOD seconds during their flight path.
Instance Fields
===============
------
real arc = 0.00
------
The arc of this projectile's flight path. Has the same effect on this projectile as
the "Missile - Arc" data field in the Object Editor has on a unit's projectile missile. The
greater the value, the larger the arc in which the projectile will fly.
------
integer data = 0
------
Theoretically attaching is not necessary since any data you need to save should go to an
instance field in your projectile struct, but just in case, you can use this field to attach
structs and such to this projectile.
------
boolean destroyOnHit = true
------
Determines whether this projectile is automatically destroyed when it hits its either its
target coordinates or unit. Note that if this is set to false, the projectile will have to be
manually destroyed using terminate().
------
real speed = 0.0
------
The (ground) speed of this projectile in wc3 distance units per second.
------
boolean start = false
------
Determines whether the projectile is moving or not. When this field is set to true, this
projectile will begin to fly toward its target. If this field is set to false, this projectile
will not move and will not register the onTick() or onHit() events. This field is automatically
set to false after the projectile hits its target.
------
unit target = null
------
The target unit of this projectile. If this field is non-null, the projectile will ignore the
xeprojectile.targetX, xeprojectile.targetY, and xeprojectile.targetZ fields and instead home in
on the specified target. If this field is null, the projectile will use the
xeprojectile.targetX, xeprojectile.targetY, and xeprojectile.targetZ fields instead.
------
real targetX
------
The x-coordinate of this projectile's target point. The default value is the x-coordinate of
the location where the projectile was initially created. Note that this field has no effect if a
unit target is set.
------
real targetY
------
The y-coordinate of this projectile's target point. The default value is the y-coordinate of
the location where the projectile was initially created. Note that this field has no effect if a
unit target is set.
------
real targetZ = 0.0
------
The z-offset of this projectile's target point. Note that this field has no effect if a unit
target is set.
------
real targetZOffset = 0.0
------
The z offset of this projectile's target point above the target unit. If the field
xeprojectile.target is null, this field has no effect.
Instance Methods
================
------
stub method onHit takes nothing returns nothing
------
This method is called when this projectile hits its target (either a point or a unit). This
method is called before xeprojectile.destroyOnHit is evaluated, so if xeprojectile.destroyOnHit
is set to true, this method can still stop the destruction of this projectile by setting the
boolean to false. This method is also called after the field xeprojectile.start is set to false,
so if for any reason you need this projectile to continue moving, simply set xeprojectile.start
to true and reset the appropriate target data.
------
stub method onTick takes nothing returns nothing
------
This method is called every timer loop AFTER all movement calculations have been done. It
will not be called if this projectile has hit its target; xeprojectile.onHit() will be called
instead.
------
method terminate takes nothing returns nothing
------
Destroys this projectile.
Last edited by a moderator: