• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Just Another Missile System WIP [vJass]

Status
Not open for further replies.
Level 9
Joined
Mar 6, 2012
Messages
64
So I am currently created a missile system which is supposed to help me create missiles for various purposes. The system runs specified trigger on "impact" making it usable for all kind of stuff. For example, the trigger makes the caster teleport on impact location, while having dmg at the same time or other crazy triggers you can think of. I'm pretty sure this system is not optimized and not in its best form yet and that is why I am posting it here for critiques and for improvement.

Credits to Anitarf for his Vector library.

vJASS:
// Missile System by Blink
library MissileSystem2 requires Vector
globals
    real lastMissileX
    real lastMissileY
    real lastMissileZ
    real lastMissileAngleXY
    real lastMissileAngleXZ
    unit lastMissileTarget
    unit lastMissileOwner
    Missile lastMissileCreated
endglobals

struct Missile
    //missile owner and target
    private unit owner
    private unit target
    private group hitGroup
    //effect attribute
    private effect model
    //missile position
    private real x
    private real y
    private real z
    //missile target position
    private real tx
    private real ty
    private real tz
    //rotation attributes
    private vector direction
    private real turnrate
    //distance attributes
    private real distance                   //distance left for missile to travel
    private real velocity
    //hit radius
    private real hitrad
    private real hitZoffset
    //target filter
    private boolexpr filter
   
    //missile type
    private boolean FUHit                   // first unit hit ,default is true
    private boolean homing
    private boolean passThrough
    //other attributes ie. clipping,dropping
    private boolean clipping
    private boolean dropping
    private boolean willDrop
   
    //trigger that will execute when missile hits
    private trigger HitTrig
   
    //code stuff
    private static thistype array thisArray
    private static integer count = 0
    private static timer t = CreateTimer()
   
    //methods
    
    static method createXYZ takes real x, real y, real z returns thistype
        local thistype this = thistype.create()
        set thisArray[count] = this
        set this.x = x
        set this.y = y
        set this.z = z
        set this.direction = vector.create(1,0,0)
        set this.hitGroup = CreateGroup()  
        set this.passThrough = false
        set lastMissileCreated = this
       
        if count == 0 then
            call TimerStart(t, TimerInterval, true, function thistype.iterate)
        endif
        set count = count + 1
        return this
    endmethod
   
    method setRotation takes real anglexy, real anglexz returns nothing
        set this.direction.z =SinBJ(anglexz)
        set this.direction.x = CosBJ(anglexy)*CosBJ(anglexz)
        set this.direction.y = SinBJ(anglexy)*CosBJ(anglexz)
    endmethod
   
    method setOwner takes unit owner returns nothing
        set this.owner = owner
    endmethod
   
    method setTarget takes unit target returns nothing
        set this.target = target
    endmethod
   
    method setHitProperties takes real hitrad, real hitzoffset returns nothing
        set this.hitrad = hitrad
        set this.hitZoffset = hitzoffset
    endmethod
   
    method setModel takes string modelPath returns nothing
        set this.model =  AddSpecialEffect(modelPath,this.x,this.y)
        call BlzSetSpecialEffectZ(this.model,this.z)
    endmethod
   
    method setModelEffect takes effect e returns nothing
        set this.model = e
    endmethod
   
    method setVelocity takes real velocity returns nothing
        set this.velocity = velocity
    endmethod
   
    method setDistance takes real distance returns nothing
        set this.distance = distance
    endmethod
   
    method setTurnRate takes real turnrate returns nothing
       set this.turnrate = turnrate
    endmethod
   
    method setFilter takes boolexpr filter returns nothing
        set this.filter = filter
    endmethod
   
    method setHitTrig takes trigger t returns nothing
        set this.HitTrig = t
    endmethod

    method setMissileType takes boolean isFUHit, boolean isHoming returns nothing
        set this.FUHit = isFUHit
        set this.homing = isHoming
    endmethod
   
    method setPassThrough takes boolean pt returns nothing
        set this.passThrough = pt
    endmethod
   
    method setOthers takes boolean isClipping, boolean willDrop returns nothing
        set this.clipping = isClipping
        set this.willDrop = willDrop
    endmethod
   
    private method destroyt takes integer i returns nothing
        call DestroyGroup(this.hitGroup)
        call DestroyEffect(this.model)
        call this.direction.destroy()
        call this.destroy()
        set thisArray[i] = thisArray[count - 1]
        set count = count - 1 
       
        if count == 0 then
            call PauseTimer(t)
        endif
    endmethod
   
    private method calculateAngle takes nothing returns nothing         //this method is only for homing type missiles
        local vector targetVector = vector.create(this.tx-this.x,this.ty-this.y,this.tz-this.z)
        local vector rotationAxis
        if vector.getAngle(this.direction,targetVector) > this.turnrate* bj_DEGTORAD then
            set rotationAxis = vector.crossProduct(this.direction,targetVector)
            if rotationAxis.getLength() == 0 then
                set rotationAxis.x = GetRandomReal(-1,1)
                set rotationAxis.y = GetRandomReal(-1,1)
                set rotationAxis.z = GetRandomReal(-1,1)
            endif
            call this.direction.rotate(rotationAxis,this.turnrate* bj_DEGTORAD)
            call rotationAxis.destroy()
        else       
            call targetVector.setLength(1)
            set this.direction.x = targetVector.x
            set this.direction.y = targetVector.y
            set this.direction.z = targetVector.z
        endif
        call targetVector.destroy()
    endmethod
   
    private method rotateModel takes nothing returns nothing
        local real angleXY = Atan2(this.direction.y,this.direction.x)
        local real distXY = SquareRoot(this.direction.x*this.direction.x+this.direction.y*this.direction.y)
        local real angleXZ = Atan2(this.direction.z,distXY)
        call BlzSetSpecialEffectYaw(this.model,angleXY)
        call BlzSetSpecialEffectPitch(this.model,-angleXZ)
        //call BlzSetSpecialEffectOrientation(this.model, angleXY, -angleXZ,0)
    endmethod
   
    private method moveMissile takes nothing returns nothing
        set this.x = this.x + this.direction.x*this.velocity
        set this.y = this.y + this.direction.y*this.velocity
        set this.z = this.z + this.direction.z*this.velocity
        call BlzSetSpecialEffectPosition(this.model,this.x,this.y,this.z)
    endmethod

    private method checkHit takes integer i returns boolean
        local unit u
        local integer j
        local real lastTargetDis
        local real distXY
        local unit target = null
        if this.passThrough and FirstOfGroup(this.hitGroup) != null then
            set j = 0
            loop 
                set u = BlzGroupUnitAt(this.hitGroup,j)
                exitwhen u == null
                if SquareRoot(Pow(GetUnitX(u)-this.x,2)+Pow(GetUnitY(u)-this.y,2)+Pow(BlzGetUnitZ(u)+GetUnitFlyHeight(u)-this.z,2)) > this.hitrad then
                    call GroupRemoveUnit(this.hitGroup,u)
                endif
                set j = j + 1   
            endloop
        endif
       
        if this.FUHit then
            set lastMissileX = this.x
            set lastMissileY = this.y
            set lastMissileZ = this.z
            set lastMissileOwner = this.owner
            set lastMissileAngleXY = Atan2BJ(this.direction.y,this.direction.x)
            set distXY = SquareRoot(this.direction.x*this.direction.x+this.direction.y*this.direction.y)
            set lastMissileAngleXZ = -Atan2BJ(this.direction.z,distXY)
            call GroupEnumUnitsInRange(g,this.x,this.y,this.hitrad,this.filter)
            loop 
                set u = FirstOfGroup(g)
                exitwhen u == null
                if SquareRoot(Pow(GetUnitX(u)-lastMissileX,2)+Pow(GetUnitY(u)-lastMissileY,2)+Pow(BlzGetUnitZ(u)+GetUnitFlyHeight(u)-lastMissileZ,2)) <= this.hitrad /*
                */and not IsUnitInGroup(u,this.hitGroup)then
                    if target == null then
                        set target = u
                        set lastTargetDis =  SquareRoot((GetUnitX(u)-this.x)*(GetUnitX(u)-this.x)+(GetUnitY(u)-this.y)*(GetUnitY(u)-this.y))
                    elseif SquareRoot((GetUnitX(u)-this.x)*(GetUnitX(u)-this.x)+(GetUnitY(u)-this.y)*(GetUnitY(u)-this.y)+Pow(BlzGetUnitZ(u)+GetUnitFlyHeight(u)-this.z,2)) < lastTargetDis then
                        set target = u
                        set lastTargetDis =  SquareRoot((GetUnitX(u)-this.x)*(GetUnitX(u)-this.x)+(GetUnitY(u)-this.y)*(GetUnitY(u)-this.y)+Pow(BlzGetUnitZ(u)+GetUnitFlyHeight(u)-this.z,2))
                    endif
                endif
                call GroupRemoveUnit(g,u)
            endloop
            if target != null then
                call GroupAddUnit(this.hitGroup, target)
                set lastMissileTarget = target
                set target = null
                call TriggerExecute(this.HitTrig)
                return true
            endif
        endif
       
        if this.homing and SquareRoot(Pow(GetUnitX(this.target)-this.x,2) + Pow(GetUnitY(this.target)-this.y,2) + Pow(BlzGetUnitZ(this.target)+GetUnitFlyHeight(this.target)-this.z,2)) < this.hitrad /*
        */and not IsUnitInGroup(this.target, this.hitGroup) then
        call GroupEnumUnitsInRange(g,this.x,this.y,this.hitrad,this.filter)
        if IsUnitInGroup(this.target,g) then  
            call GroupAddUnit(this.hitGroup, this.target)
            //execute trigger
            set lastMissileX = this.x
            set lastMissileY = this.y
            set lastMissileZ = this.z     
            set lastMissileAngleXY = Atan2BJ(this.direction.y,this.direction.x)
            set distXY = SquareRoot(this.direction.x*this.direction.x+this.direction.y*this.direction.y)
            set lastMissileAngleXZ = -Atan2BJ(this.direction.z,distXY)
            set lastMissileOwner = this.owner
            set lastMissileTarget = this.target
            call TriggerExecute(this.HitTrig)
            return true
        endif
        endif
       
        return false
    endmethod
   
    private static method iterate takes nothing returns nothing
        local integer i
        local location loc
        local thistype this
        set i = 0
        loop
            exitwhen i >= count
            set this = thisArray[i]
            //if missile is homing
            if this.homing then
                set this.tx = GetUnitX(this.target)
                set this.ty = GetUnitY(this.target)
                set this.tz = BlzGetUnitZ(this.target)+GetUnitFlyHeight(this.target)+this.hitZoffset
            endif
            call this.calculateAngle()
            call this.rotateModel()
           
            set loc = Location(this.x,this.y)
            if this.checkHit(i) and not this.passThrough then 
                call this.destroyt(i)
            elseif this.distance <= 0 or (this.clipping and (this.z <= GetLocationZ(loc)))then
                call this.destroyt(i)
            else
                call this.moveMissile()
                //set new distance left
                set this.distance = this.distance - velocity
                set i = i + 1
            endif
            call RemoveLocation(loc)
        endloop
       
        set loc = null
    endmethod
endstruct

////////////////////////////functions to use
function CreateMissileHomingFUHsfx takes unit owner, unit target, effect model, real angle, real velocity, real turnrate, real maxDis, real hitRad, trigger Action, boolexpr condition, boolean isDropping returns nothing
    local Missile m = Missile.createXYZ(BlzGetLocalSpecialEffectX(model),BlzGetLocalSpecialEffectY(model),BlzGetLocalSpecialEffectZ(model))
    call m.setModelEffect(model)
    call m.setOwner(owner)
    call m.setTarget(target)
    call m.setTurnRate(turnrate*TimerInterval)
    call m.setRotation(angle,0)
    call m.setVelocity(velocity)
    call m.setMissileType(true,true)
    call m.setDistance( maxDis)
    call m.setHitProperties(hitRad,GetRandomReal(0.0,hitRad))
    call m.setHitTrig(Action)
    call m.setFilter(condition)
    call m.setOthers(true,false)
endfunction

function CreateMissileFUH2clip takes unit owner, string model, real cx, real cy, real cz, real angleXZ, real angleXY, real velocity, real dis, real hitrad, boolean drop, trigger Action, boolexpr condition returns nothing
    local Missile m = Missile.createXYZ(cx,cy,cz)
    local effect e = AddSpecialEffect(model, cx, cy)
    call BlzSetSpecialEffectYaw(e, Deg2Rad(angleXY))
    call BlzSetSpecialEffectZ(e, cz)
    call m.setModelEffect(e)
    call m.setOwner(owner)
    call m.setTurnRate(0)
    call m.setRotation(angleXY,angleXZ)
    call m.setVelocity(velocity)
    call m.setMissileType(true,false)//fuhit = true, homing = false
    call m.setDistance(dis)
    call m.setHitTrig(Action)
    call m.setFilter(condition)
    call m.setHitProperties(hitrad,GetRandomReal(0.0,hitrad))
    call m.setOthers(true,drop)
    //ref leaks
    set e = null
endfunction
////////////////////////////////////////////////
endlibrary
 

Attachments

  • Missile System Test2.w3x
    38.2 KB · Views: 43
Level 11
Joined
Jul 4, 2016
Messages
627
Hi, Blink, I'm not sure if it's because the demo is pushing your system to its limits or something, but I was getting about a 100 fps drop from one cast.
 
Level 23
Joined
Jan 1, 2009
Messages
1,610
The system runs specified trigger on "impact" making it usable for all kind of stuff.

Don't all missiles systems have callbacks?!

I'm pretty sure this system is not optimized

So judging by the title you know there are other missile systems, which you could check out for some inspiration.

Just from glancing over I can see quite a lot of things you should avoid. The biggest offender is probably creating a new location for every missile in iterate,
instead of reusing and moving one. SquareRoot and Pow are not fast, so avoid using them. For distances u can simply compare the squares as per Pythagorean theorem.
Using random reals in homing seems odd.
 
Status
Not open for further replies.
Top