Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
I have worked on this missle engine for 2 months now and start the first official beta today.
Please post feedback, critism, pros, cons, bugs, etc.
Thanks all for your patience!
And thanks for downloading.
Preview image by Furby. Thanks a lot!
Edit:
I've updated the testmap and added a second spell.
There is a lot of improvements in version 0.1.7 and I plan to make it even faster and even more modular. I also plan to create an easy to understand API.
Changed all constants (TRUE, FALSE) to true/false
Changed interval to 0.03125
Fixed object leaks
Performance improvements on MissileMovement: Less object generation
Merged MissileLocHelpers to Missile<type>Target
Removed HomingMissile wrapper
Added second spell (Rain of Fire)
Removed Libraries from Modules
Changed name to Missile.
Completely remade in modules, supports now a lot of optional stuff.
Added SpellHelper, fixed a lot of problems, made the Miranas Arrow example WAY more powerful to show what this system is able to be capable of.
BPower:
11:02, 25th Feb 2016
Reason for re-review:
Nowadays the spell section is packed full of missile systems from different authors, therefore a more qualified
moderator comment than "this is neat stuff" is required. There is keen...
I will add x/y and zOffset to the target anyway, you will be able to change it at any time, so the missile could actually have your own arc or you can make it so that an ability increases the perfection of the flight and removes the offset from the not precise shot.
local real realhigh = GetUnitFlyHeight(.getEffUnit())
now i can put my headshot system to work (and the projectiles that goes above the target won't hit him never (unless he jumps but datz gonna be stupid)).
you mean a "standart" ZOffset? Like it's gonna be automatic the "unit's height" measure check? I tell ya, most units have an 80. height.
also, Offsets in my camera view are very usefull cuz you'd have to always target the units feet to the projectile to hit it's location; with this i can make an interactive offset that measures the distance from the target and can simulate the "z" so you can target the chest.
you should create a function that takes one string (effect's path) and three real (x,y,z) parameters to create a special effect at the exact location and also a function to clean it. =)
that function might even using a unit with a special effect attached to it, i think thats the easy way, it's better than using destructable. also because you'll be able to use vexorians color system in it.
that way you can make missiles with trails using onLoop.
(i want check my missiles trageotories and also make easy special effects)
I still think it should take 3 reals not use specifically the missiles parameters. with that you make make special effects like a person bleeding in different parts or a looping expiral around the missile when it onLoops.
if you just use a function with those 4 parameters instead of just the string path, you'll be able to put speciall effects ANYWHERE ANYHEIGHT in the map, get it? that gives you liberty to put it on the missile or to put it on the target or in the caster or both at the same time. (and if are greedy you can put a forth real parameter "timer" for it to die, so you won't need cleaning it artificially, calling something. but i don't think thats really necessary, though usefull))
if you just use a function with those 4 parameters instead of just the string path, you'll be able to put speciall effects ANYWHERE ANYHEIGHT in the map, get it? that gives you liberty to put it on the missile or to put it on the target or in the caster or both at the same time. (and if are greedy you can put a forth real parameter "timer" for it to die, so you won't need cleaning it artificially, calling something. but i don't think thats really necessary, though usefull))
I will add the function
CreateSpecialEffectOnLoc takes real x, real y, real z, string eff returns effect
to the CustomEffect library.
Into the CustomMissile library I will add a new function like
addEffect takes string s returns effect. (This calls the CreateSpecialEffectOnLoc function with the current x, y and z parameters of the missile)
oh, it would be interesting if the missile system had a remake of the collision (.hitrange) system. hitrange does not detect pathing but the "unit point" location of the widget, so even if the destructable has a big pathing map or the unit have a big collision size, the missile will only hit it if the widget gets within the .hitrange radius of the missile.
Here's a graphic telling why only having .hitrange as "collision" detection parameter is a problem:
this can be solved by making the Missile System able detect pathing around its projectiles, this way it can hit units by its collision size, buildings n' destructibles by it's pathing and other missiles by the .hitrange system (since the missile's collision size = 0.00).
is it possible to detect pathing n' apply this "method"???
=======
....If it isn't (since you are storing units in a group created by trigger) you might consider creating several extra hitrange detecter functions, those taking two parameters, the first,a text macro stating the kind of widget desired.the second, the range used to detect it's center.
Examples:
call hitrange[1]( UNIT_TYPE_HERO, 32.00) ----> stupid example: if unittype of the unitpicket on the hitrange group = hero, the arrow will detect it at range 32.00
call hitrange[2]( UNIT_TYPE_STRUCTURE, 120.00) ---> if unittype of the unitpicket on the hitrange group = building, the arrow will detect it at range 120.00 (large to simulate the pathing)
call hitrange[3]( UNIT_TYPE_POLYMORPHED , 16.00) ---> polimorphed units are smaller, so the projectile detects it with more difficulty
call hitrange[4]( WIDGET_TYPE_LARGEDEST, 50.00) ----> tree that is larger than a unit (btw, you gonna have to generate some customisable textmacros, or teach how to do it, this one could detect a destructable and filter it by it's typeid or even by it's life (supposing that bigger destructables have bigger lifes) )
call hitrange[5](WIDGET_TYPE_SMALLTREE, 20.00) same as before, but smaller.
you might even be more specific like:
set .hitrange.unit = 32.
set .hitrange.dest1 = 40.
set .hitrange.dest2 = 120.
but thats gonna take a LOT of time to make a library (i can help you doing the massive work if you choose to do this)
Here's a graphic how the .hitrange becomes after this kind of change
obviously this kinda makes the system somehow slower, so it might be an optional module or optional feature (like .hitwalls) having multiple projectiles with this sytems (filtering 5 or 6 types of widget) might affect performance. One way to get pass that is to always put the maximum .hitrange and always check the distance between the widget and the projectile, if the distance is equal o smaller than the required for that kind of widget, the projectile "touches" the widget. (gosh this is complicated)
unfortunatly this system will not detect exotic shapes, since is all based on hitrange radius, it will always be a "round" "pathing".
oh, and i also made a sample spell for your map, i'll put the coding here later, if you want. It's a Flame Splash: a phoenix missile projectile with 1500 max range that deals 100 area damage (area 150) on unithit, on wallnit,on desthit,on reachtarget. also, when this damage is dealt, 20 small flame drops come out of the projectile (that is already dead with flashy effects) simulating a "flame splash". those drops deal 25 damage to any unit it hits. The whole thing is very flashy looks very realistic (not that liquid fire exists...)
//|=======================================================|
//| this system is made by The_Witcher |
//| all credits for this system goes to him |
//|=======================================================|
library CollisionSystem initializer Init
globals
private integer array class
private real array xx
private real array yy
private real array zz
private integer total = 0
private hashtable h = InitHashtable()
private real maxR = 0
private group g = CreateGroup()
private boolean Free = true
private real X
private real Y
private real Z
endglobals
function AddEnvironmentCollision takes integer rcode, real SizeX, real SizeY, real SizeZ returns nothing
if LoadInteger(h,rcode,0) == 0 then
set total = total + 1
set xx[total] = SizeX / 2
set yy[total] = SizeY / 2
set zz[total] = SizeZ
set class[total] = rcode
call SaveInteger(h, rcode, 0, total)
if SizeX > maxR then
set maxR = SizeX
endif
if SizeY > maxR then
set maxR = SizeY
endif
endif
endfunction
private function GetRectFromCircle takes real x, real y, real radius returns rect
return Rect(x - radius, y - radius, x + radius, y + radius)
endfunction
private function Destrloop takes nothing returns nothing
local integer i = LoadInteger(h,GetDestructableTypeId(GetEnumDestructable()),0)
local real x = GetDestructableX(GetEnumDestructable())
local real y = GetDestructableY(GetEnumDestructable())
if Free then
if i != 0 then
if (X > x - xx[i] and X < x + xx[i]) and (Y > y - yy[i] and Y < y + yy[i]) and (Z >= 0 and Z < zz[i]) then
set Free = false
endif
endif
endif
endfunction
private function AliveFilter takes nothing returns boolean
return not (IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) or GetUnitTypeId(GetFilterUnit()) == 0 )
endfunction
function IsWayFree takes real x, real y, real z returns boolean
local location p = Location(x,y)
local unit u
local integer i
local real xxx
local real yyy
local real zzz
set X = x
set Y = y
set Z = z
set Free = true
call EnumDestructablesInCircleBJ(maxR,p,function Destrloop)
if Free then
call GroupEnumUnitsInRange(g,x,y,maxR,Condition(function AliveFilter))
loop
set u = FirstOfGroup(g)
exitwhen u == null or not Free
set i = LoadInteger(h,GetUnitTypeId(u),0)
if i != 0 then
set xxx = GetUnitX(u)
set yyy = GetUnitY(u)
set zzz = GetUnitFlyHeight(u)
set Free = (X > xxx - xx[i] and X < xxx + xx[i]) and (Y > yyy - yy[i] and Y < yyy + yy[i]) and(Z >= zzz and Z < zzz+ zz[i])
set Free = not Free
endif
call GroupRemoveUnit(g,u)
endloop
endif
return Free
endfunction
function IsWayFreeLoc takes location p, real z returns boolean
return IsWayFree(GetLocationX(p),GetLocationY(p),z)
endfunction
private function Init takes nothing returns nothing
//call AddEnvironmentCollision(
endfunction
endlibrary
i requested this sys some time ago
may it's usefull (my unit collision sys still bugs -.-')
hmm
my unit collision doesn't have this problem
i post it here but don't use it becasue it doesn't work
JASS:
library UnitCollision initializer Init
globals
//------------------ small Setup part ---------------------
private constant integer Sphere = 1
private constant integer Cylinder = 2
private constant integer Dummy_Id = 'h000' // your private dummy unit
//----------------- end of the settings -------------------
private location Point1 = Location(0,0)
private location Point2 = Location(0,0)
private hashtable UC_Hash
private real Max_CollSize = 0.
private group Picked_Group = CreateGroup()
private boolean Collision_Check = false
//---------------- stored things for the Unit Collision --------------
private real Stored_X = 0.
private real Stored_Y = 0.
private real Stored_Z = 0.
private real Stored_Size = 0.
private player Stored_Player = null
// ------------ stored things for the Damage Units in range function ---------
private real Stored_Damage = 0.
private unit Stored_Damagedealer = null
endglobals
function GetUnitCollSizeSphere takes unit u returns real
return LoadReal( UC_Hash, GetUnitTypeId(u), 1)
endfunction
function GetUnitRadCylinder takes unit u returns real
return LoadReal( UC_Hash, GetUnitTypeId(u), 1)
endfunction
function GetUnitHeightCylinder takes unit u returns real
return LoadReal( UC_Hash, GetUnitTypeId(u), 2)
endfunction
function GetUnitType takes unit u returns integer
return LoadInteger(UC_Hash,GetUnitTypeId(u),0)
endfunction
function AddUnitCollisionSphere takes integer uID, real rad returns nothing
call SaveInteger(UC_Hash, uID, 0, Sphere)
call SaveReal(UC_Hash, uID, 1, rad)
//-------------------------------------
if rad >= Max_CollSize then
set Max_CollSize =rad+.5
endif
endfunction
function AddUnitCollisionCylinder takes integer uID, real rad, real height returns nothing
local real x = SquareRoot((rad*rad)+(height*height))
//-------------------------------------
call SaveInteger(UC_Hash, uID, 0, Cylinder)
call SaveReal(UC_Hash, uID, 1, rad)
call SaveReal(UC_Hash, uID, 2, height)
//-------------------------------------
if x >= Max_CollSize then
set Max_CollSize = x+.5
endif
endfunction
function CheckForCollisionAction takes nothing returns boolean
local real array r
local unit u = GetFilterUnit()
call MoveLocation(Point2,Stored_X,Stored_Y)
call MoveLocation(Point1,GetUnitX(u),GetUnitY(u))
//-------------------------------------------------------------------
if Collision_Check == false then
if GetUnitTypeId(u)!= Dummy_Id and GetWidgetLife(u) > 0.405 then
if GetUnitType(u) == Sphere then
//--------------------------------------
set r[0] = Stored_X - GetUnitX(u)
set r[1] = Stored_Y - GetUnitY(u)
set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
//--------------------------------------
set r[3] = (GetUnitFlyHeight(u)+GetLocationZ(Point1))-(Stored_Z+GetLocationZ(Point2))
set r[4] = SquareRoot(r[2] * r[2] + r[3] * r[3])
//--------------------------------------
set Collision_Check = ((r[4] <= GetUnitCollSizeSphere(u)+Stored_Size) and GetOwningPlayer(u) != Stored_Player)
//--------------------------------------
elseif GetUnitType(u) == Cylinder then
//--------------------------------------
set r[0] = Stored_X - GetUnitX(u)
set r[1] = Stored_Y - GetUnitY(u)
set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
//--------------------------------------
set r[3] = GetUnitFlyHeight(u)
//--------------------------------------
set Collision_Check = (r[2] <= GetUnitRadCylinder(u)+Stored_Size and Stored_Z+GetLocationZ(Point2) > r[3]-Stored_Size+GetLocationZ(Point1) and Stored_Z+GetLocationZ(Point2) < r[3]+GetUnitHeightCylinder(u)+Stored_Size+GetLocationZ(Point1) and GetOwningPlayer(u) != Stored_Player)
//--------------------------------------
endif
endif
endif
//--------------------------------------
set u = null
return false
endfunction
function CheckForCollision takes real x, real y, real z, real size, player p returns boolean
set Stored_Player = p
set Stored_X = x
set Stored_Y = y
set Stored_Z = z
set Stored_Size = size
//-----------------------------------------------------------------
call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, Filter(function CheckForCollisionAction))
//-----------------------------------------------------------------
set Picked_Group = null
//-----------------------------------------------------------------
return Collision_Check
endfunction
// |==========================================================================|
// |--------------------------------------------------------------------------|
// |==========================================================================|
function DamageUnitsInRangeAction takes nothing returns boolean
local unit u = GetFilterUnit()
local real array r
call MoveLocation(Point2,Stored_X,Stored_Y)
call MoveLocation(Point1,GetUnitX(u),GetUnitY(u))
//-------------------------------------------------------------------
if GetUnitTypeId(u)!= Dummy_Id and GetWidgetLife(u) > 0.405 then
if GetUnitType(u) == Sphere then
//------------------------------------------------
set r[0] = Stored_X - GetUnitX(u)
set r[1] = Stored_Y - GetUnitY(u)
set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
//------------------------------------------------
set r[3] = (GetUnitFlyHeight(u)+GetLocationZ(Point1))-(Stored_Z+GetLocationZ(Point2))
set r[4] = SquareRoot(r[2] * r[2] + r[3] * r[3])
//---------------------------------------------------------------------------------------------------------------------------
if (r[4] <= GetUnitCollSizeSphere(u)+Stored_Size) and GetOwningPlayer(u) != GetOwningPlayer(Stored_Damagedealer) then
call UnitDamageTarget(Stored_Damagedealer, u, Stored_Damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
//---------------------------------------------------------------------------------------------------------------------------
elseif GetUnitType(u) == Cylinder then
//----------------------------------------------------
set r[0] = Stored_X - GetUnitX(u)
set r[1] = Stored_Y - GetUnitY(u)
set r[2] = SquareRoot(r[0] * r[0] + r[1] * r[1])
//------------------------------------------------
set r[3] = GetUnitFlyHeight(u)
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
if r[2] <= GetUnitRadCylinder(u)+Stored_Size and Stored_Z+GetLocationZ(Point2) > r[3]-Stored_Size+GetLocationZ(Point1) and Stored_Z+GetLocationZ(Point2) < r[3]+GetUnitHeightCylinder(u)+Stored_Size+GetLocationZ(Point1) and GetOwningPlayer(u) != GetOwningPlayer(Stored_Damagedealer) then
call UnitDamageTarget(Stored_Damagedealer, u, Stored_Damage, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
endif
endif
set u = null
return false
endfunction
function DamageUnitsInRange takes real x, real y, real z, real damage, real rad, unit damagedealer returns nothing
set Stored_Damagedealer = damagedealer
set Stored_Y = y
set Stored_Z = z
set Stored_Size = rad
set Stored_Damage = damage
//-------------------------------------------------------------------
call GroupEnumUnitsInRange(Picked_Group, x, y, Max_CollSize, Filter(function DamageUnitsInRangeAction))
//-------------------------------------------------------------------
set Picked_Group = null
set Stored_Damagedealer = null
endfunction
private function Init takes nothing returns nothing
set UC_Hash = InitHashtable()
//---------------------------------------------------------
// This is a good place to add a collision to a unit type
//---------------------------------------------------------
call AddUnitCollisionSphere('h004',100)
call AddUnitCollisionSphere('h001',30)
call AddUnitCollisionSphere('h005',50)
call AddUnitCollisionSphere('h007',90)
call AddUnitCollisionCylinder('h002',50,45)
call AddUnitCollisionCylinder('h008',45,100)
call AddUnitCollisionCylinder('h006',100,240)
call AddUnitCollisionCylinder('h003',60,280)
call AddUnitCollisionCylinder('h009',12.5,35)
call AddUnitCollisionCylinder('h00A',14,35)
endfunction
endlibrary
we are getting off topic xD the focus here is anacrhons system.
Edit: anadron, i'm trying to use grouputils but my spell scope does not reconizes NewGroup() as function. why does that happens? can you fix the system so it can reconize? Weird thing since it reconizes ReleaseGroup(group) and the other functions
JASS:
private struct spellMissile extends CustomMissile
private group targetgroup = NewGroup()
it does not work, the WE does not let me do this
Plz help me with that because i need a group for the spell to work and while i can't solve this, 'im creating and destroing groups everytime the spell is casted.
Right now I am really busy with reallife, so sorry, I am checking this idea later.
it does not work, the WE does not let me do this
Plz help me with that because i need a group for the spell to work and while i can't solve this, 'im creating and destroing groups everytime the spell is casted.
You can't do this, just do that on the onCreate method.
Edit:
I will NOT add CreateEffectOnLoc because that's the purpose of the CustomEffect.
Edit2:
I will also not change the collision system. It's fine as it is now. The other stuff will just explode the range of this system and it will be a lot slower.
dunno, i'm new to vJASS, most i know is because of your system. still did not get the idea of struct, method those stuff. just learning how to use it.
since you don't want to set the missile detection slower you can generate a custom pathing radius based on the unit's life or collision size or whatever. the missile will detect the units radius when both custom collision and hitrange radius cross.(life for destructibles, custom value for units). that way your system does not get slower and this system will become just a module. you will just generate like eight points (or more if the radius is too big) around the widget to "simulate" the radius (it will be actually a octogon but i think you got my point).those points might be dummy units that are bounded to the Main unit. You only need to create one extra function in the system to make subordinate units (the points) lead to the main unit.(or even less than if you make an Optional to the library AutoIndex (you know AutoIndex right?))
i think autoindex even lets you make extra values to store in the unit so each unit type might have different colliding radius, zheights (you may use this for other things in your system!), all you need to do is to make those values be stored at the unit creation xD
anyway just some ideas.
plzzzzzzz i really need pathing difference for units and destructibles in my map.
You can do that on your own.
I am not wanting a system that forces the user to input the collision ranges of every unit on the map to be set just to use this system.
Just do it yourself, disable collision and trigger it yourself. (use the onLoop method)
Is it better to use onTouchUnit and make the .hitrange equal to the maximum custom pathing radius possible? onUnittouch will check the storied custom radius and check if the missile is close enought to perform a "hiting" action.
I don't know what the exact aim of the system is, but typically projectiles aren't going to need a whole whack-load of collision detection. If there is such a requirement for very specific collision, then you should really be using a physics engine.
It seems though like it would almost be easier to only handle X/Y collision detection, and let the user handle the height modifications themselves. In my system (probably similar in this one) you can reference the x/y/z of a projectile and the collision interface-method includes a unit variable, so you would be able to gather the x/y/z coordinates of the unit as well (and be able to accomplish the same thing, but leave more open to the user).
I still don't know though, Anachron, what are your thoughts?
By the way, Anachron, how can projectiles be enumerated in this?
That's because you can't declare private variables inside a function/method, only local variables. Try using:
JASS:
local group targetGroup = NewGroup()
You shouldn't ever really need local groups, though, since a single global group variable can be used to do all the necessary process requirements of any single function. For example:
JASS:
globals
private group enumGlobal = CreateGroup()
endglobals
...
method onCreate takes nothing returns nothing
call GroupEnumUnitsInRange(enumGlobal, ...)
// Be sure to clear the group (not destroy it) at the end, so that
// there are no units remaining.
call GroupClear(enumGlobal)
endmethod
That's because you can't declare private variables inside a function/method, only local variables. Try using:
JASS:
local group targetGroup = NewGroup()
You shouldn't ever really need local groups, though, since a single global group variable can be used to do all the necessary process requirements of any single function. For example:
JASS:
globals
private group enumGlobal = CreateGroup()
endglobals
...
method onCreate takes nothing returns nothing
call GroupEnumUnitsInRange(enumGlobal, ...)
// Be sure to clear the group (not destroy it) at the end, so that
// there are no units remaining.
call GroupClear(enumGlobal)
endmethod
so i can't just pick a group from the grouputils stack?
i can't have a global group because it would make the spell not MUI (if two people cast it at the same time, the target won't be targeted by both, the group avoids the same spell hitting the unit twice.)
Well if Anachron has his struct setup properly then you should be able to extend the CustomMissile struct and add certain properties to it (such as your group), which would give something like:
JASS:
struct yourMissile extends CustomMissile
private group enumGroup = null
method onDestroy takes nothing returns nothing
// You should make sure you release the group.
call ReleaseGroup(enumGroup)
endmethod
method onCreate takes nothing returns nothing
set enumGroup=NewGroup()
endmethod
endstruct
Well it really doesn't matter where you create the group, as long as you create it before you use it, and destroy/release it when you are done using it.
And yes, this will pick a group from the "GroupUtils" stack because I am assigning the group to NewGroup.
I suggest you read the vJass Manual that's included in the jasshelper folder of your JNGP download.
I think there is some sort of problem with groups being created/destroyed, which is why GroupUtils is so commonly used. If you only need a group for instant unit enumerations (like for area of effect damage, where units are not needed for any more than an instant) you can use a global group because you will not be needing to create/destroy it.
it's a function that takes 3 real parameters (x,y,z) and a sfx parameter to create a special effect using them. it creates a special effect unit, set's its flaying height to x,y n z and then attach a special effect at its origin using the sfx parameter. I'd love to do this, but i dunno how to clean it later so it wont leak
I tried to make a way to create spell effects a the EXACT location the spell hits.
here's what i did, tell me if that leaks or have some problem:
JASS:
scope ShortBow initializer init
private keyword spell
private struct spellMissile extends CustomMissile
private spell spellInst = 0
private unit source = null
//these are private methods to create a effect unit at the extact location i want the "blood" effect it lives only for the amount of seconds i want.
private method CreateInstantZUnit takes real x, real y, real z, real a returns unit
local unit instantUnit = CreateUnit(.owner, 'CExx', x, y, a)
call SetUnitFlyHeight(instantUnit, z - GetLocZ(x, y), 0.)
return instantUnit
endmethod
//in this space you would find a public static method to make the spell have target, method onCreate blah blah blah
//blah blah
//blah blah
method onUnitTouch takes nothing returns nothing
local unit effectunit = CreateInstantZUnit(.x,.y,.z,0.)
call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl", effectunit, "origin"))
set .hitunits = false
set .hitwalls = false
set .hitdests = false
set .alive = false
call BJDebugMsg("HIT!!!")
set effectunit = null
endmethod
endstruct
is there a better way to do this? this actually works but it is destroied toooo soon, it does not even play the effect entirelly.
Other than that it looks fine, though you do not null instantUnit in CreateInstantZUnit which will cause a memory leak. To fix this use a global variable instead of declaring a local variable. It would look something like:
JASS:
globals
private unit tempUnit = null
endglobals
...
//these are private methods to create a effect unit at the extact location i want the "blood" effect it lives only for the amount of seconds i want.
private method CreateInstantZUnit takes real x, real y, real z, real a returns unit
set tempUnit = CreateUnit(.owner, 'CExx', x, y, a)
call SetUnitFlyHeight(instantUnit, z - GetLocZ(x, y), 0.)
return tempUnit
endmethod
method onUnitTouch takes unit theUnit returns nothing
local real x = GetUnitX(theUnit)
local real y = GetUnitY(theUnit)
local real z = GetLocZ(x, y) + GetUnitFlyHeight(theUnit)
local CustomEffect e = CreateEffect(x, y, z, GetUnitFacing(theUnit))
set e.sfx = "Effect\\Path.mdl"
call e.destroy()
endmethod
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.