• 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!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Projectile coming back

Level 7
Joined
Aug 26, 2016
Messages
139
What do I need to write so that the projectile, when it collides with an enemy or travels a certain distance, flies back to Caster?
JASS:
library Shield1Lib

native UnitAlive takes unit id returns boolean
function GetLocZS takes real x, real y returns real
    call MoveLocation( LFZ, x, y )
    return GetLocationZ( LFZ )
endfunction

function MoveS takes nothing returns nothing
    local bullet A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local unit u
    local string WeaponEffect2 = "Weapon/VoidboltRoughMinor.mdx"
   
    set A.x = A.x + A.s * A.v.x * Cos( A.v.z )
    set A.y = A.y + A.s * A.v.y * Cos( A.v.z )
    set A.z = A.z + A.s * A.v.z
   
    set A.d = A.d - A.s
   
    call SetUnitX( A.dummy, A.x )
    call SetUnitY( A.dummy, A.y )
    call SetUnitFlyHeight( A.dummy, A.z - GetLocZS( A.x, A.y ), 0.00 )
   
    call GroupEnumUnitsInRange( TempGroup, A.x, A.y, A.r, null )
   
    loop
        set u = FirstOfGroup( TempGroup )
        exitwhen u == null
        call GroupRemoveUnit( TempGroup, u )
       
        if UnitAlive( u ) and IsUnitEnemy( u, A.p ) and RAbsBJ( GetUnitFlyHeight( u ) - GetUnitFlyHeight( A.dummy ) ) <= 100.00 then
            
           
            call GroupClear( TempGroup )
            call UnitDamageTarget( A.caster, u, 90.00, false, false, null, null, null )
            call StopSoundBJ( gg_snd_1hDaggerHitFleshCriticalA, false )
            call PlaySoundOnUnitBJ( gg_snd_1hDaggerHitFleshCriticalA, 100, A.dummy )
            call PauseTimer( GetExpiredTimer( ) )
        call FlushChildHashtable( H, GetHandleId( GetExpiredTimer( ) ) )
        call DestroyTimer( GetExpiredTimer( ) )
      
        call KillUnit(A.dummy)
        call RemoveUnit( A.dummy )
       
        set A.dummy = null
        set A.caster = null
        call A.v.destroy( )
        call A.destroy( )
       
        endif
    endloop
   
    if A.d <= 0.00 or A.z - GetLocZS( A.x, A.y ) <= 20.00 or IsBulletNearDestructible(A.x, A.y) then
       
         call PauseTimer( GetExpiredTimer( ) )
        call FlushChildHashtable( H, GetHandleId( GetExpiredTimer( ) ) )
        call DestroyTimer( GetExpiredTimer( ) )
      
        call KillUnit(A.dummy)
        call RemoveUnit( A.dummy )
       
        set A.dummy = null
        set A.caster = null
        call A.v.destroy( )
        call A.destroy( )
     
      
    endif
      
endfunction

function Trig_ShieldGow_Actions takes nothing returns nothing
    local timer t = CreateTimer( )
    local unit Target = udg_Camera[1]
    local bullet A = bullet.create( )
    local real x = GetUnitX(Target)
    local real y = GetUnitY(Target)
    local real z = GetLocZS( x, y ) + 90.00
   
    set A.caster = udg_UnitBody[1]
    set A.p = GetOwningPlayer( A.caster )
  
    // for offset
    set A.x = GetUnitX( A.caster )  
    set A.y = GetUnitY( A.caster )
    set A.z = GetUnitFlyHeight( A.caster ) + GetLocZS( A.x, A.y ) + 90.00
   
    set A.v = vector.create( x - A.x, y - A.y, z - A.z )
   
    set A.x = A.x + 100.00 * A.v.x * Cos( A.v.z )
    set A.y = A.y + 100.00 * A.v.y * Cos( A.v.z )
    set A.z = GetUnitFlyHeight( A.caster ) + GetLocZS( A.x, A.y ) + 90.00
   
    // for move
        set A.v.x = x - A.x
        set A.v.y = y - A.y
        set A.v.z = z - A.z 

  
     call A.v.normalize( )
   
    set A.d = 550.00
    set A.s = 800.00 * 0.03125
    set A.r = 80.00
   
   
    set A.dummy = CreateUnit( A.p, 'u002', A.x, A.y, Atan2( A.v.y, A.v.x )  * bj_RADTODEG  )
   
   
    call SetUnitPathing( A.dummy, false )
    call UnitAddAbility( A.dummy, 'Arav' )
    call SetUnitX( A.dummy, A.x )
    call SetUnitY( A.dummy, A.y )
    call SetUnitFlyHeight( A.dummy, A.z - GetLocZS( A.x, A.y ), 0.00 )
  
    call SaveInteger( H, GetHandleId( t ), 0, A )
    call TimerStart( t, 0.02, true, function MoveS )
  
  
  
    set t = null
    set Target = null
   
   
endfunction

//===========================================================================


function InitTrig_ShieldGow takes nothing returns nothing
    local trigger t8 = CreateTrigger()
    call TriggerRegisterTimerEventSingle( t8, 0.00 )
    call TriggerAddAction( t8, function Trig_ShieldGow_Actions )
    set t8 = null
endfunction
endlibrary
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
You have unscoped functions within your library that use very generic names. That's a really bad idea in most situations because of potential namespace conflicts with other code (that you did or didn't write). Such functions should generally be made private or public depending on their use case.

When the projectile goes 'out' it's seeking a fixed target location, so the change in position (described by the velocity variables A.v.x and A.v.y) per interval is constant. This is fine and trivial, really.

To make the projectile return to the caster it now must seek a moving location whose coordinates might be affected by any number of other things that cause motion in your map. While not fundamentally that different than the fixed target location, will require considerably more math and making some explicit choices/assumptions about how the specifics of the return trajectory.
  • Should the return always take the same amount of time, no matter how far from the caster the projectile may currently be. (Fixed total duration, so variable projectile velocity)
  • Should return velocity always be fixed to some maximum value? If so then the return time scales with caster movement away from the projectile.
  • How does this projectile track its target? Should it have an infinitely small turning radius to make pinpoint adjustments or should it arc and curve to track.
  • Does the projectile lag/stop/pause at the target location for any period of time? Should an acceleration (if velocity is capped: up to the cap but not exceeding it) occur when it resumes moving or will it begin moving at full speed.
  • What if the caster dies or is teleported very far away during the return seek? What should happen then?
Answer these (and similar) questions and you'll have a better idea of how to approach this. In general you will just be updating set of 'target' coordinates, and then making a determination about how to compute a velocity that moves the projectile an appropriate amount toward that (temporary) coordinate.

If you'd like to see a finished version of something very similar to what you're describing here check out Moonerang in my spell pack. It launches to a target and then tracks the mouse cursor with acceleration, a maximum velocity, and a maximum turn angle that the tracking can achieve. Since I was not concerned with reaching the tracked location, the tracking portion is time-based and does not adjust velocity to reach the destination at a particular time.
 
Top