| 08-07-2008, 06:01 AM | #1 |
I am trying to make a projectile system to handle all the projectiles for my map. There is one problem though, the height of the projectile will increase/decrease with the terrain height and I don't know what's causing it. The movement type for the dummy unit is NOT fly or hover (It will only work properly if I cast it from 0 terrain height) I would appreciate if someone helped me find the problem JASS:library ProjectileSystem initializer Init globals private constant integer DummyRawcode = 'h000' private timer Timer = CreateTimer() private integer Counter = 0 private integer array Projectiles private constant real TimerInterval = 0.03 private boolexpr Boolexpr private group EnumGrp = CreateGroup() private location Zloc = Location( 0, 0 ) private real Temp1 private real Temp2 private integer TempInt private unit TempUnit private unit TempKnocked endglobals private struct Projectile unit missile effect sfx real x real y real z real fly real speed real time real incX real incY real incZ real startZ real lastZ real radius unit origin integer damageType boolean hitend string onhit static method create takes real x, real y, real z, real tx, real ty, real tz, real speed, real radius, integer damageType, unit origin, string sfx, string onhit, boolean hitend returns Projectile local Projectile p = Projectile.allocate() local real dist = SquareRoot( ( tx - x ) * ( tx - x ) + ( ty - y ) * ( ty - y ) + ( tz - z ) * ( tz - z ) ) local real angle = Atan2( ty - y, tx - x ) set p.origin = origin set p.missile = CreateUnit( GetOwningPlayer( origin ), DummyRawcode, x, y, Atan2( ty - y, tx - x ) * bj_RADTODEG ) call UnitAddAbility( p.missile, 'Amrf' ) call UnitRemoveAbility( p.missile, 'Amrf' ) set p.sfx = AddSpecialEffectTarget( sfx, p.missile, "origin" ) set p.hitend = hitend set p.time = dist / speed set p.incX = dist * Cos( angle ) / ( p.time / TimerInterval ) set p.incY = dist * Sin( angle ) / ( p.time / TimerInterval ) set p.incZ = ( tz - z ) / ( p.time / TimerInterval ) set p.x = x set p.y = y set p.z = z call MoveLocation( Zloc, x, y ) set p.startZ = GetLocationZ( Zloc ) set p.radius = radius set p.damageType = damageType set p.onhit = onhit return p endmethod private method onDestroy takes nothing returns nothing call DestroyEffect( .sfx ) call KillUnit( .missile ) endmethod endstruct private function ProjectileHit takes nothing returns boolean local Projectile p = TempInt local unit u = GetFilterUnit() if GetWidgetLife( u ) > 0 and GetUnitFlyHeight( u ) + 50 < p.fly + p.radius and GetUnitFlyHeight( u ) + 50 > p.fly - p.radius and IsUnitEnemy( u, GetOwningPlayer( p.origin ) ) then call UnitDamageTargetEx( p.origin, u, 100, ATTACK_TYPE_NORMAL, p.damageType, false ) if p.onhit != null and p.onhit != "" then call ExecuteFunc( p.onhit ) endif if p.hitend then set p.time = 0 endif endif set u = null return false endfunction private function Update takes nothing returns nothing local integer i = Counter - 1 local Projectile p loop exitwhen i < 0 set p = Projectiles[i] set p.time = p.time - TimerInterval if p.time > 0 then set p.x = p.x + p.incX set p.y = p.y + p.incY call MoveLocation( Zloc, p.x, p.y ) set p.z = p.z + p.incZ set p.fly = p.z + p.startZ - GetLocationZ( Zloc ) set p.lastZ = p.fly call SetUnitAnimationByIndex( p.missile, R2I( Acos( ( p.fly - p.lastZ ) / SquareRoot( p.incX * p.incX + p.incY * p.incY + ( p.fly - p.lastZ ) * ( p.fly - p.lastZ ) ) ) * bj_RADTODEG ) ) call SetUnitX( p.missile, p.x ) call SetUnitY( p.missile, p.y ) call SetUnitFlyHeight( p.missile, p.fly, 0 ) if p.fly < 0 then set p.time = 0 endif set TempInt = p call GroupEnumUnitsInRange( EnumGrp, p.x, p.y, p.radius, Boolexpr ) else call p.destroy() set Counter = Counter - 1 if Counter < 0 then call PauseTimer(Timer) set Counter = 0 else set Projectiles[i] = Projectiles[Counter] endif endif set i = i - 1 endloop endfunction function ProjectileStop takes unit targ returns boolean local integer i = Counter - 1 local Projectile p = 0 local boolean b = false loop exitwhen i < 0 set p = Projectiles[i] if p.missile == targ then call p.destroy(p) set Counter = Counter - 1 if Counter < 0 then call PauseTimer(Timer) set Counter = 0 else set Projectiles[i] = Projectiles[Counter] endif set b = true endif set i = i - 1 endloop return b endfunction function AddProjectile takes real x, real y, real z, real tx, real ty, real tz, real speed, real radius, integer damageType, unit origin, string sfx, string onhit, boolean hitend returns boolean local Projectile p = 0 set p = Projectile.create( x, y, z, tx, ty, tz, speed, radius, damageType, origin, sfx, onhit, hitend ) if Counter == 0 then call TimerStart(Timer, TimerInterval, true, function Update) endif set Projectiles[Counter] = p set Counter = Counter + 1 return true endfunction private function Init takes nothing returns nothing set Boolexpr = Condition( function ProjectileHit ) endfunction endlibrary This is the function I use to create the projectile: JASS:private function Fireball takes nothing returns nothing local unit u = GetTriggerUnit() local location l = GetSpellTargetLoc() call AddProjectile( GetUnitX( u ), GetUnitY( u ), GetUnitFlyHeight( u ) + 65, GetLocationX( l ), GetLocationY( l ), GetLocationZ( l ), 3000, 85, DAMAGE_FIRE, u, "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl", "", true ) call RemoveLocation( l ) set l = null set u = null endfunction |
| 08-07-2008, 09:52 AM | #2 |
GetUnitZ(u) == GetUnitFlyingHeight(u) + GetLocationZ(GetUnitLoc(u)) That's why it works only for 0 terrain height. |
| 08-07-2008, 10:28 AM | #3 | |
I myself, like to use Anitarfs vectors for stuff like this. Use GetLocationZ on units location. This way its allso easy to detect when bullet or projectile hits the ground. Set Units fly height: Units Z value - GetLocationZ on units location You should think twice before you do this, because, like Ash said: Quote:
|
| 08-07-2008, 11:07 AM | #4 |
he does that... or he fixed that after the comments? |
| 08-07-2008, 11:16 AM | #5 | |
Quote:
And where ? , as far i see, he doesn't. |
| 08-07-2008, 12:46 PM | #6 |
JASS:set p.startZ = GetLocationZ( Zloc ) ... set p.fly = p.z + p.startZ - GetLocationZ( Zloc ) call SetUnitFlyHeight( p.missile, p.fly, 0 ) Also, are you using some special model that has a lot of animations for different tilts? |
| 08-07-2008, 02:29 PM | #7 |
Thanks for the replies, but none of these methods work so far. Also, I am using the dummy model that has 360 different animations for the tilt. |
| 08-07-2008, 02:37 PM | #8 |
Hmm correct me if i'm wrong, but you don't use GetLocationZ before calculate the dist in the static method create of your struct. |
| 08-07-2008, 02:52 PM | #9 | ||
Quote:
That? And I do it for the target location when I create the fireball, Quote:
I think I may do something wrong somewhere there though >.> |
| 08-07-2008, 03:19 PM | #10 |
No, that : JASS:local real dist = SquareRoot( ( tx - x ) * ( tx - x ) + ( ty - y ) * ( ty - y ) + ( tz - z ) * ( tz - z ) ) |
| 08-07-2008, 03:43 PM | #11 |
Ok, I changed up the code a bit, and the height only glitches up when it goes over water now... Here it is so far: EDIT: it is now a problem with Warcraft's water being lower than GetLocationZ shows. TY for the help >.> JASS:library ProjectileSystem initializer Init globals private constant integer DummyRawcode = 'h000' private timer Timer = CreateTimer() private integer Counter = 0 private integer array Projectiles private constant real TimerInterval = 0.03 private boolexpr Boolexpr private group EnumGrp = CreateGroup() private location Zloc = Location( 0, 0 ) private real Temp1 private real Temp2 private integer TempInt private unit TempUnit private unit TempKnocked endglobals private struct Projectile unit missile effect sfx real x real y real z real fly real speed real time real incX real incY real incZ real startZ real lastZ real radius unit origin integer damageType boolean hitend string onhit static method create takes real x, real y, real z, real tx, real ty, real tz, real speed, real radius, integer damageType, unit origin, string sfx, string onhit, boolean hitend returns Projectile local Projectile p = Projectile.allocate() local real dist local real angle = Atan2( ty - y, tx - x ) local real locz local real tlocz call MoveLocation( Zloc, x, y ) set locz = GetLocationZ( Zloc ) call MoveLocation( Zloc, tx, ty ) set tlocz = GetLocationZ( Zloc ) set dist = SquareRoot( ( tx - x ) * ( tx - x ) + ( ty - y ) * ( ty - y ) + ( tz + tlocz - ( z + locz ) ) * ( tz + tlocz - ( z + locz ) ) ) set p.origin = origin set p.missile = CreateUnit( GetOwningPlayer( origin ), DummyRawcode, x, y, Atan2( ty - y, tx - x ) * bj_RADTODEG ) call UnitAddAbility( p.missile, 'Amrf' ) call UnitRemoveAbility( p.missile, 'Amrf' ) set p.sfx = AddSpecialEffectTarget( sfx, p.missile, "origin" ) set p.hitend = hitend set p.time = dist / speed set p.incX = dist * Cos( angle ) / ( p.time / TimerInterval ) set p.incY = dist * Sin( angle ) / ( p.time / TimerInterval ) set p.incZ = ( tz + tlocz - ( z + locz ) ) / ( p.time / TimerInterval ) set p.x = x set p.y = y set p.z = z + locz set p.radius = radius set p.damageType = damageType set p.onhit = onhit return p endmethod private method onDestroy takes nothing returns nothing call DestroyEffect( .sfx ) call KillUnit( .missile ) endmethod endstruct private function ProjectileHit takes nothing returns boolean local Projectile p = TempInt local unit u = GetFilterUnit() if GetWidgetLife( u ) > 0 and GetUnitFlyHeight( u ) + 50 < p.fly + p.radius and GetUnitFlyHeight( u ) + 50 > p.fly - p.radius and IsUnitEnemy( u, GetOwningPlayer( p.origin ) ) then call UnitDamageTargetEx( p.origin, u, 100, ATTACK_TYPE_NORMAL, p.damageType, false ) if p.onhit != null and p.onhit != "" then call ExecuteFunc( p.onhit ) endif if p.hitend then set p.time = 0 endif endif set u = null return false endfunction private function Update takes nothing returns nothing local integer i = Counter - 1 local Projectile p loop exitwhen i < 0 set p = Projectiles[i] set p.time = p.time - TimerInterval if p.time > 0 then set p.x = p.x + p.incX set p.y = p.y + p.incY call MoveLocation( Zloc, p.x, p.y ) set p.z = p.z + p.incZ set p.fly = p.z + p.startZ - GetLocationZ( Zloc ) call BJDebugMsg( R2S( p.fly ) ) call BJDebugMsg( R2S( GetLocationZ( Zloc ) ) ) set p.lastZ = p.fly call SetUnitAnimationByIndex( p.missile, R2I( Acos( ( p.fly - p.lastZ ) / SquareRoot( p.incX * p.incX + p.incY * p.incY + ( p.fly - p.lastZ ) * ( p.fly - p.lastZ ) ) ) * bj_RADTODEG ) ) call SetUnitX( p.missile, p.x ) call SetUnitY( p.missile, p.y ) call SetUnitFlyHeight( p.missile, p.fly, 0 ) if p.fly < 0 then set p.time = 0 endif set TempInt = p call GroupEnumUnitsInRange( EnumGrp, p.x, p.y, p.radius, Boolexpr ) else call p.destroy() set Counter = Counter - 1 if Counter < 0 then call PauseTimer(Timer) set Counter = 0 else set Projectiles[i] = Projectiles[Counter] endif endif set i = i - 1 endloop endfunction function ProjectileStop takes unit targ returns boolean local integer i = Counter - 1 local Projectile p = 0 local boolean b = false loop exitwhen i < 0 set p = Projectiles[i] if p.missile == targ then call p.destroy(p) set Counter = Counter - 1 if Counter < 0 then call PauseTimer(Timer) set Counter = 0 else set Projectiles[i] = Projectiles[Counter] endif set b = true endif set i = i - 1 endloop return b endfunction function AddProjectile takes real x, real y, real z, real tx, real ty, real tz, real speed, real radius, integer damageType, unit origin, string sfx, string onhit, boolean hitend returns boolean local Projectile p = 0 set p = Projectile.create( x, y, z, tx, ty, tz, speed, radius, damageType, origin, sfx, onhit, hitend ) if Counter == 0 then call TimerStart(Timer, TimerInterval, true, function Update) endif set Projectiles[Counter] = p set Counter = Counter + 1 return true endfunction private function Init takes nothing returns nothing set Boolexpr = Condition( function ProjectileHit ) endfunction endlibrary |
| 08-07-2008, 04:20 PM | #12 | |
Quote:
Try to use an offset and regions. Create the region where there is water. Then check when an unit enter the region, and when it leaves. Creates as many regions as you have different depths. |
| 08-07-2008, 05:05 PM | #13 |
I'm pretty sure there's another way to check for water, try using search. |
| 08-07-2008, 05:20 PM | #14 |
Try to change the model of your projectile. For example a flying unit and then a swimming unit. Maybe the model can affect the flying height. |
| 08-07-2008, 08:15 PM | #15 |
Why would it be related to a model and not to walking type. Also please don't use a model with 360 animations >< It should be 180 and you can safely make it for every 5th angle with absolutely no impact on visualisation. I know those animations are tiny but 360 of them is several kilos. Your whole model would probably easily fit into 5-10k .. Even if the missile can change pitch increments of 5 will look well enough at the speeds you get. |
