| 01-21-2009, 08:36 PM | #1 |
For some reason I can't explain (whether it's just something obvious I'm not seeing, or the math involved), my dummy projectile starts going crazy over uneven terrain. Firstly, the dummy is supposed to travel in a parabolic path, but it keeps adjusting itself to terrain height (even though my function that sets the dummy's Z is meant to cater for that...). Secondly, I'm using dummy.mdx and trying to get the projectile pointing in the right direction in flight, but that's going crazy and ends up facing up, down, up, down (and so on). I'll cut out the configurables, the only one which is actually relevant to the parabola is .CURVE, which has a value of 2.5 JASS:struct PB //Required globals private static location tempLoc = Location (0,0) private static group genGroup = CreateGroup () private static timer spellTimer = CreateTimer () private static PB array data private static PB gdata = 0 private static integer N = 0 private static real groupX = 0 private static real groupY = 0 private static real doublePi = bj_PI * 2 private static real offsetX private static real offsetY private static real MinX = GetRectMinX (bj_mapInitialPlayableArea) private static real MaxX = GetRectMaxX (bj_mapInitialPlayableArea) private static real MinY = GetRectMinY (bj_mapInitialPlayableArea) private static real MaxY = GetRectMaxY (bj_mapInitialPlayableArea) //Required struct members private unit caster private unit proj private real speed private real pcos private real psin private real curdist private real maxdist private effect pfx //Required helper functions private static method RingEffect takes string fxString, real ringCount, real effectCount, real offset, real x, real y returns nothing local integer i1 = 1 local integer i2 = 1 local real angle = GetRandomReal (0, .doublePi) local real x2 local real y2 loop exitwhen i1 > ringCount loop exitwhen i2 > effectCount set angle = angle + .doublePi/effectCount set x2 = x + Cos (angle) * (i1 * offset) set y2 = y + Sin (angle) * (i1 * offset) call DestroyEffect(AddSpecialEffect (fxString, x2, y2)) set i2 = i2 + 1 endloop set i1 = i1 + 1 endloop endmethod private static constant method JumpParabola takes real dist, real maxdist,real curve returns real local real t = (dist*2)/maxdist-1 return (-t*t+1)*(maxdist/curve) endmethod private static method SetUnitXY takes unit u,real x,real y returns nothing if x < .MaxX and x > .MinX and y < .MaxY and y > .MinY then call SetUnitX(u,x) call SetUnitY(u,y) endif endmethod private static method GetCoordZ takes real x, real y returns real call MoveLocation (.tempLoc, x, y) return GetLocationZ (.tempLoc) endmethod private static method SetUnitZ takes unit u, real h returns boolean local real z = h - .GetCoordZ (GetUnitX (u), GetUnitY (u)) if z > 0 then call SetUnitFlyHeight (u, z, 0) return false else return true endif endmethod private static method GetUnitZ takes unit u returns real return .GetCoordZ (GetUnitX (u), GetUnitY (u)) + GetUnitFlyHeight (u) endmethod private static method GetRandOffset takes real x, real y, real dist returns nothing local real discrepdist = ((dist - .ACC_RANGE)/.ACC_DISCREP_MULTI)*.ACC_DISCREP local real angle = GetRandomReal (0, .doublePi) set .offsetX = x + Cos (angle) * discrepdist set .offsetY = y + Sin (angle) * discrepdist endmethod //Spell functions private static method GroupFunc takes nothing returns boolean local PB a = .gdata local unit u = GetFilterUnit () local real ux = GetUnitX (u) local real uy = GetUnitY (u) local real x = .groupX - ux local real y = .groupY - uy local real dist = SquareRoot (x*x + y*y) local real percent = (.DamageRadius (a.caster) - dist)/.DamageRadius (a.caster) local real dmg if percent < .MIN_DMG_PERCENT then set percent = .MIN_DMG_PERCENT endif set dmg = .Damage (a.caster) * percent if IsUnitEnemy (u, GetOwningPlayer (a.caster)) then call UnitDamageTarget (a.caster, u, dmg, false, true, .ATYPE, .DTYPE, .WTYPE) endif set u = null return false endmethod private static method Move takes nothing returns nothing local integer i = .N local real fxAngle = 0 local real x = 0 local real y = 0 local real x2 = 0 local real y2 = 0 local real z = 0 local real uz = 0 local real ex = 0 local real ey = 0 local boolean b = false local real hDist = 0 local real zDif = 0 local integer animindex = 0 local PB a loop exitwhen i == 0 set a = .data[i] set x = GetUnitX (a.proj) set y = GetUnitY (a.proj) set x2 = x + a.pcos*a.speed set y2 = y + a.psin*a.speed set z = .JumpParabola (a.curdist, a.maxdist, .CURVE) set uz = .GetUnitZ (a.proj) set hDist = SquareRoot ((x2-x)*(x2-x) + (y2-y)*(y2-y)) set zDif = z - uz set animindex = R2I (Atan2 (zDif, hDist) * bj_RADTODEG + 90) if animindex >= 0 and animindex <= 180 then call SetUnitAnimationByIndex (a.proj, animindex) endif call .SetUnitXY (a.proj, x2, y2) set b = .SetUnitZ (a.proj, z) if b and a.curdist > 0 then if .RESET_DUMMY then call SetUnitAnimationByIndex (a.proj, 0) endif call DestroyEffect (a.pfx) set a.curdist = 0 call KillUnit (a.proj) set .gdata = a call GroupEnumUnitsInRange (.genGroup, x, y, .DamageRadius (a.caster), Condition (function PB.GroupFunc)) call .RingEffect (.END_FX, .RING_COUNT, .FX_COUNT, .RING_OFFSET, x, y) call a.destroy () set .data[i] = .data[.N] set .N = .N - 1 if .N == 0 then call PauseTimer (.spellTimer) endif endif set a.curdist = a.curdist + a.speed set i = i - 1 endloop endmethod private static method SpellCond takes nothing returns boolean return GetSpellAbilityId () == .SID endmethod private static method SpellActions takes nothing returns nothing local PB a local integer i = 0 local unit u local unit c = GetTriggerUnit () local real cx = GetUnitX (c) local real cy = GetUnitY (c) local real sx local real sy local location l = GetSpellTargetLoc () local real tx = GetLocationX (l) local real ty = GetLocationY (l) local real x = tx - cx local real y = ty - cy local real rx2 local real ry2 local real angle = Atan2 (y, x) local real dist = SquareRoot (x*x + y*y) local real angle2 local real dist2 //ix, iy and idist are testing variables local real ix local real iy local real idist //set rx = cx + Cos (angle) * dist //set ry = cy + Sin (angle) * dist call RemoveLocation (l) set l = null if .N == 0 then call TimerStart (.spellTimer, .TIMER_INT, true, function PB.Move) endif loop exitwhen i == .PROJCOUNT if dist < .MIN_RANGE then set angle = GetRandomReal (0, .doublePi) endif set a = PB.create () set a.caster = c set sx = cx + Cos (GetRandomReal (0, .doublePi)) * GetRandomReal (0, .SPAWN_OFFSET) set sy = cy + Sin (GetRandomReal (0, .doublePi)) * GetRandomReal (0, .SPAWN_OFFSET) set u = CreateUnit (GetOwningPlayer (a.caster), .LID, sx, sy, angle * bj_RADTODEG) call SetUnitVertexColor (u, .LR, .LG, .LB, .LA) call SetUnitScale (u, .LS, .LS, .LS) call SetUnitAnimation (u, .ANIM) call QueueUnitAnimation (u, "stand") call UnitApplyTimedLife (u, 'BTLF', .LIFESPAN) if dist <= .ACC_RANGE then set angle2 = GetRandomReal (0, .doublePi) set dist2 = GetRandomReal (0, .TARGET_OFFSET) set rx2 = tx + Cos (angle) * dist2 set ry2 = ty + Sin(angle) * dist2 else call .GetRandOffset (tx, ty, dist) set rx2 = .offsetX set ry2 = .offsetY endif set x = rx2-cx set y = ry2-cy set ix = rx2 - tx set iy = ry2 - ty set idist = SquareRoot (ix*ix + iy*iy) set angle = Atan2 (y, x) set a.pcos = Cos (angle) set a.psin = Sin (angle) set a.maxdist = SquareRoot (x*x + y*y) if a.maxdist < .MIN_RANGE then set angle = GetUnitFacing (u) * bj_DEGTORAD set a.maxdist = a.maxdist + .MIN_RANGE set a.pcos = Cos (angle) set a.psin = Sin (angle) endif set a.proj = CreateUnit (GetOwningPlayer (a.caster), .PID, sx, sy, angle * bj_RADTODEG) call SetUnitVertexColor (a.proj, .PR, .PG, .PB, .PA) call UnitAddAbility (a.proj, 'Arav') call UnitRemoveAbility (a.proj, 'Arav') set a.curdist = 0 set a.speed = GetRandomReal (.SPEED_LOW, .SPEED_HIGH) * .TIMER_INT set a.pfx = AddSpecialEffectTarget (.PROJ_FX, a.proj, .ATTACH_PT) set i = i + 1 set .N = .N + 1 set .data[.N] = a endloop set c = null set u = null endmethod private static method onInit takes nothing returns nothing local trigger t = CreateTrigger () call TriggerRegisterAnyUnitEventBJ (t, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition (t, Condition (function PB.SpellCond)) call TriggerAddAction (t, function PB.SpellActions) if .ALLOW_PRELOAD then call KillUnit (CreateUnit (Player (0), .LID, 0, 0, bj_UNIT_FACING)) call KillUnit (CreateUnit (Player (0), .PID, 0, 0, bj_UNIT_FACING)) call DestroyEffect (AddSpecialEffect (.PROJ_FX, 0, 0)) call DestroyEffect (AddSpecialEffect (.END_FX, 0, 0)) endif set .MinX = GetRectMinX (bj_mapInitialPlayableArea) set .MaxX = GetRectMaxX (bj_mapInitialPlayableArea) set .MinY = GetRectMinY (bj_mapInitialPlayableArea) set .MaxY = GetRectMaxY (bj_mapInitialPlayableArea) endmethod endstruct Also, I've tested on gentle terrain height changes (Terrain -> Height -> Raise) and cliffs (Terrain -> Grass Cliff) and the problem is occuring for both (although far more extreme on the cliffs) Also, who is the author of dummy.mdx? ???? isn't much of a credit to the author ![]() |
| 01-21-2009, 10:06 PM | #2 |
Is your projectile unit a flying unit by any chance? |
| 01-21-2009, 11:11 PM | #3 |
I believe vexorian was the author of dummy.mdx, but I could be wrong. As Anitarf said, make your unit movement type hover and then add and remove the crow-form ability. |
| 01-22-2009, 12:33 AM | #4 | |
Quote:
|
| 01-22-2009, 12:50 AM | #5 | |
Quote:
|
| 01-22-2009, 01:01 AM | #6 |
I think GetLocationZ returns the terrain z value without the unit's flyheight. JASS:call SetUnitFlyHeight (u, z+GetUnitFlyHeight(unit), 0) |
| 01-22-2009, 01:21 AM | #7 |
The issue, as Anitarf is saying in a sly way, is that flying units are hardcoded to try to smooth out their heights over terrain, so they don't move up and down as you would want them too, since you're also moving them left and right. |
| 01-22-2009, 04:38 PM | #8 | ||||
Quote:
Quote:
And thanks for letting me know who made dummy.mdx :) Quote:
Quote:
If I factored the unit's flyheight into that, it would (approximately) achieve double the height that it should (since the dummy's height would be 20-40 below the value of z above) at normal fly height |
| 01-22-2009, 04:55 PM | #9 |
JASS:
set z = .JumpParabola (a.curdist, a.maxdist, .CURVE) + GetLocationZ(loc)
|
