• 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.

Tracking spell issue

Status
Not open for further replies.
Level 21
Joined
Mar 27, 2012
Messages
3,232
I'm coding a spell with a tracking component, but I don't know how to do it properly.
The intuitive solution would be to make it apply speed toward the target, but this causes a problem that I call "orbiting" - Some projectiles will circle around their targets forever.
This is the current code and map with my tries to fix the issue commented out, so you could see how it happens.
Note that I do not want the tracking to mean instant changing of direction, but rather a gradual tracking.
The spell and most of its mechanics is inspired by Jan from Little Fighter 2.

JASS:
native UnitAlive takes unit u returns boolean 
//! import "ExtraFunctions.j"
//! import "Effect.j"
library HealSpirit initializer in requires ExtraFunctions,Effect
    globals
        private trigger CastTrig = CreateTrigger()
        private trigger LoopTrig = CreateTrigger()
        
        private unit array Unit
        private unit array Target
        private real array Vx
        private real array Vy
        private real array Heal
        private real array Speed
        private real array Torque
        private real array Angle
        private integer Units = 0
        
        private constant integer ABIL   = 'A000'
        private constant integer DUMMY  = 'h001'
        private constant string SFX     = "Abilities\\Spells\\Human\\Heal\\HealTarget.mdl" 
        private constant real RANGE     = 1000
        private constant real TIMEOUT   = 0.0312500
        
        private player p
    endglobals
    
    private function filter takes nothing returns boolean
        if IsUnitEnemy(GetFilterUnit(),p) then
            return false
        endif
        if not(UnitAlive(GetFilterUnit())) then
            return false
        endif
        return true
    endfunction
    
    private function Loop takes nothing returns nothing
        local integer i = 1
        local real x1
        local real y1
        local real x2
        local real y2
        local real distance
        local real currentangle
        local real r
        local real r2
        loop
            exitwhen i > Units
            set x1 = GetUnitX(Unit[i])
            set y1 = GetUnitY(Unit[i])
            set x2 = GetUnitX(Target[i])
            set y2 = GetUnitY(Target[i])
            set distance = RealDistance(x1,y1,x2,y2)
            if distance < 100 then
                call SetUnitX(Unit[i],x2)
                call SetUnitY(Unit[i],y2)
                call ApplyTimedEffectTarget(SFX,Target[i],"chest",1)
                call KillUnit(Unit[i])
                set Unit[i] = Unit[Units]
                set Target[i] = Target[Units]
                set Vx[i] = Vx[Units]
                set Vy[i] = Vy[Units]
                set Speed[i] = Speed[Units]
                set Torque[i] = Torque[Units]
                set Angle[i] = Angle[Units]
                set Units = Units - 1
            else
                set x1 = x1+Vx[i]
                set y1 = y1+Vy[i]
                call SetUnitX(Unit[i],x1)
                call SetUnitY(Unit[i],y1)
                set Angle[i] = AngleBetweenPointsEx(x1,y1,x2,y2)
                call SetUnitFacing(Unit[i],Angle[i])
                //set currentangle = Asin(Vy[i]/Vx[i])*bj_RADTODEG
                //set r = currentangle - Angle[i]
                //call Debug(R2S(r))
                set Vx[i] = Vx[i] + Torque[i] * Cos((Angle[i]) * bj_DEGTORAD)
                set Vy[i] = Vy[i] + Torque[i] * Sin((Angle[i]) * bj_DEGTORAD)/*
                set Vx[i] = Vx[i] + Torque[i] * Cos((Angle[i]+r) * bj_DEGTORAD)
                set Vy[i] = Vy[i] + Torque[i] * Sin((Angle[i]+r) * bj_DEGTORAD)*/
                set Speed[i] = SquareRoot(Vx[i]*Vx[i]+Vy[i]*Vy[i])
                set i = i + 1
            endif
        endloop
        if Units == 0 then
            call DisableTrigger(LoopTrig)
        endif
    endfunction
    
    private function Create takes real x,real y,unit target,real speed,real healamount, boolean randomstart returns nothing
        local real r
        if randomstart then
            set r = GetRandomReal(0,360)
        else
            set r = AngleBetweenPointsEx(x,y,GetUnitX(target),GetUnitY(target))
        endif
        set Units = Units + 1
        set Unit[Units] = CreateUnit(GetOwningPlayer(target),DUMMY,x,y,r)
        set Target[Units] = target
        set Vx[Units] = speed * Cos(r * bj_DEGTORAD)
        set Vy[Units] = speed * Sin(r * bj_DEGTORAD)
        set Heal[Units] = healamount
        set Speed[Units] = speed
        set Torque[Units] = speed*TIMEOUT
        set Angle[Units] = r
        call EnableTrigger(LoopTrig)
    endfunction
    
    private function Cast takes nothing returns nothing
        local unit caster
        local unit u
        local group g
        local real x
        local real y
        local real speed
        if GetSpellAbilityId() == ABIL then
            set caster = GetTriggerUnit()
            set x = GetUnitX(caster)
            set y = GetUnitY(caster)
            set g = CreateGroup()
            set p = GetOwningPlayer(caster)
            call GroupEnumUnitsInRange(g,x,y,RANGE,Filter(function filter))
            loop
                set u = FirstOfGroup(g)
                exitwhen u == null
                call Create(x,y,u,10,200,true)
                call Create(x,y,u,15,100,true)
                call Create(x,y,u,20,50,true)
                call GroupRemoveUnit(g,u)
            endloop
            call DestroyGroup(g)
            set g = null
        endif
    endfunction
    
    private function in takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i > 15
            call TriggerRegisterPlayerUnitEvent(CastTrig,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
            set i = i + 1
        endloop
        call TriggerAddAction(CastTrig,function Cast)
        call TriggerRegisterTimerEvent(LoopTrig,TIMEOUT,true)
        call TriggerAddAction(LoopTrig,function Loop)
    endfunction
endlibrary
Requirements
 

Attachments

  • Healing Spirits.w3x
    17.7 KB · Views: 46
Status
Not open for further replies.
Top