• 🏆 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!

2d Projectile System GuiFriendlyv 0.5.0.0

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
This 2d projectile system, can support more projectiles then any other system on the hive in the spells section, my comparison doesn't contain vJass, as i am unable to implement them in the test map but they(at least berbs one) cannot support more then 250(on my computer) and anachrons one and all the other vjass one in the spells section use the same methods ie enumerating unit groups, they do it more efficiently then the gui ones, enumgroupinrange instead of creating a group out of the units in range. but the end result is that they have to go thorough 33 unitgroups every second per projectile, so if you have 1000 projectiles thats 33000 times a second. I am unsure how UnitEntersRange event works, but it doesn't do anything as inefficient as that.


Here is a comparison of it between it and other non vJass Projectiles

JASS:
//==================================================================================================================\\
//           ____      ______     _____                                                            _                \\
//          / __ \    |  ___ \   |  __  \                                               _         | |               \\
//        /__/  \  \  | |   \  \ | |  \  |                                             | |        | |               \\
//               |  | | |     \ || |__/  | _   _      ___      _     ___      _____  __| |__   _  | |    ___        \\
//              /  /  | |     | ||  ____/ | |/ __\  /  _  \   |_|  /  __ \  /   __/ |__   __| |_| | |  /  __ \      \\
//            /  /    | |     | || |      |  /     |  / \  |   _  | / _| | |  /        | |     _  | | | / _| |      \\
//          /  /      | |    /  || |      | |      | |   | |  | | | |/_ /  | |         | |    | | | | | |/_ /       \\
//         /  /_____  | |___/  / | |      | |      |  \_/  |  | | |  \___  |  \____    | |    | | | | |  \___       \\
//        |_________| |______/   |_|      |_|       \ ___ /   | |  \ ____|  \ ___ /    |_|    |_| |_|  \ ____|      \\
//                                ____                     _  / |                                                   \\
//                              /  __  \                   \ _ / _                                                  \\
//                             |  /  \__|                       | |                                                 \\
//                              \  \      __     __    __     __| |__     ___    __    __                           \\
//                               \  \     \  \ /  /  / _  \  |__   __|  /  __ \ |   \/   |                          \\
//                                 \  \     \   /   | /  \      | |    | / _| | | |\  /| |                          \\
//                               __ \  \     | |     \  \       | |    | |/_ /  | | \/ | |                          \\
//                              |  \_/  |    | |      _/  |     | |    |  \___  | |    | |                          \\
//                               \ ___ /     |_|    \ __ /      |_|     \ ____| |_|    |_|                          \\
//                                                                                                                  \\
//                                                    ______                                                        \\
//                                                   |  __  \                                                       \\
//                                                   | |  |  |  __     __                                           \\
//                                                   | | /  /   \  \ /  /                                           \\
//                                                   | | \  \     \   /                                             \\
//                                                   | |  |  |     | |                                              \\
//                                                   | |__|  |     | |                                              \\
//                                                   |_____ /      |_|                                              \\
//                          _        _                                                                              \\
//                         |  \     | |                                                                             \\
//                         |   \    | |                                                                             \\
//                         | |\ \   | |  ____    _   _      ___       ____      ___      ____                       \\
//                         | | \ \  | | |___ \  | |/ __\  /  _  \   / ___  |  /  _  \  / ___  |                     \\
//                         | |  \ \ | |  ___| | |  /     | /   \ | | |   | | | /   \ || |   | |                     \\
//                         | |   \ \| | /  _  | | |      | |   | | | |   | | | |   | || |   | |                     \\
//                         | |    \   | | (_) | | |      | \ _ / | | |___| | | \ _ / || |___| |                     \\
//                         |_|     \__| \ ___/  |_|       \ ___ /   \ ___  |  \ ___ /  \ ___  |                     \\
//                                                                       | |                | |                     \\
//                                                                  ___ / /             __ / /                      \\
//                                                                 |____/              |___/                        \\
//                                                                                                                  \\
//====================================================================================================================
//2d projectile system By Narogog,
//=======================================================
//
//version 0.1b
//
//importing
// copy and paste the trigger entiled "Variables" after doing so you can delete it.
// copy and paste this to the maps header
// copy and paste MS to your map
// Give Credits
// if you want to modify this go ahead. but Give credits.
//
//
//
//User variables 
//
//=============================================================================
// udg_Proj_CollisionEvent (real)                                             *
//is used to trigger collision events                                         *
// when its =0.00 a projectile has collided with a unit collision has occured *
// when its = 1.00 a projectile collision occured                             *
// when its = 2.00 a unit has collided with a unit                            *
// when its = 3.00 a projectile has ran out of fuel,                          *
// when its = 3.50 its target has died                                        *
// when its = 4.00 a unit has left the playable map                           *
//=============================================================================
//
//====================================================================
// udg_Proj_CollisionUnit (unit)                                     * 
// is the unit that is being hit                                     *
// used in all collisions                                            *
//====================================================================
//
//====================================================================
// udg_Proj_CollidingU (unit)                                        * 
// is the projectile that is colliding                               *
// used in 1,2                                                       *
//====================================================================
//
//====================================================================
// udg_Proj_CollisionIndex (int)                                     * 
// the index of the projectile, used with 1,3,3.5,4                *
// used with call Proj_deallocate(udg_Proj_CollisionIndex) to "kill" *
// the projectile                                                    *
//====================================================================
//
//====================================================================
// udg_Proj_CollisionIndex2 (int)                                    * 
// used only in projectile collisions ie 2                           *
//====================================================================
//
//====================================================================
// Proj_deallocate (function)                                        *
// how to use just call Proj_deallocate(projindex)                   *
// where projindx is LoadInteger(udg_Proj,GetHandleId(someProj),1)   *
// what does this do? well it "destroys" the projectile              *
// make sure you nullify all data connected to the projectile        *          
//====================================================================
//
//====================================================================
// CreateProjectile (function)                                       *
// to use                                                            *
// set udg_I CreateProjectile(owner,x,y,facing,speed,life,attach,    *
//   modelpath, 0,null)                                              *
// then you can use udg_I as the index of an array, import get rid of*
// all data connected to the projectile. before deallocating it      *                                                       
//====================================================================
//
//====================================================================
// udg_Proj_Target[array] (unit)                                     *
// use this when setting a new target for a projectile               *
// CAUTION only use udg_CollisionIndex for changing this             *
// to prevent interfering with another projectile                    *
//====================================================================
// end of user vars begining of system variables                     *
//
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//udg_Proj_Group (group)                                             *
// this is the lazy projectile group                                 *
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//udg_Proj_Leave_Map (group)                                         *
// this is a group that contains all units who have left the map     *
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//udg_Proj_NotCollidable (group)                                     *
// this contains units that cannot be collided with                  *
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//end of system vars(for now)
//
//do NOT modify the following values
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// udg_Proj_Group_Count (integer)                                    *
// this is just the number of lazy projectiles                       *
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//udg_ProjMax (integer)                                              *
//number of active projectiles                                       *
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//
//
//Currently there is only one global collision size.
//
//
//currently does NOT support Terrain wall collisions. 
//currently does Not support Destructible collisions.
//


// Allocate

function Proj_allocate takes nothing returns integer
    // allocate it
    local integer this
    if udg_Proj_instanceRecycle == 0 then
        set udg_Proj_instanceCount = udg_Proj_instanceCount + 1
        set this = udg_Proj_instanceCount
    else
        set this = udg_Proj_instanceRecycle
        set udg_Proj_instanceRecycle = udg_Proj_recycleNext[this]
    endif
    // add it to the list
    set udg_Proj_next[this] = 0
    set udg_Proj_prev[this] = udg_Proj_prev[0]
    set udg_Proj_next[udg_Proj_prev[0]] = this
    set udg_Proj_prev[0] = this
    // return the new instance
    return this
endfunction

// deallocate:
function Proj_deallocate takes integer this returns nothing
    // deallocate it
    if this == 0 then
    else
       set udg_Proj_recycleNext[this] = udg_Proj_instanceRecycle
       set udg_Proj_instanceRecycle = this
       // remove it from the list
       set udg_Proj_next[udg_Proj_prev[this]] = udg_Proj_next[this]
       set udg_Proj_prev[udg_Proj_next[this]] = udg_Proj_prev[this]
       set udg_Proj_Max = udg_Proj_Max - 1
       call ShowUnit(udg_Proj_U[this],false)// making it visible
       set udg_Proj_Group_Count= udg_Proj_Group_Count +1
       call GroupAddUnit(udg_Proj_Group,udg_Proj_U[this])
       call GroupAddUnit(udg_Proj_NotCollidable,udg_Proj_U[this])
       call SaveInteger(udg_Proj,GetHandleId(udg_Proj_U[this]),1,0) 
       call DestroyEffect(udg_Proj_E[this])
       call DisableTrigger(LoadTriggerHandle(udg_Proj,GetHandleId(udg_Proj_U[this]),0))

    endif
endfunction

function Proj_Collision takes nothing returns boolean//this triggers the collision event 
   local unit u = GetTriggerUnit()  

   set udg_Proj_CollisionUnit = LoadUnitHandle(udg_Proj,GetHandleId(GetTriggeringTrigger()),0)
   
   if IsUnitInGroup(u,udg_Proj_NotCollidable)==false and GetUnitState(u, UNIT_STATE_LIFE) > 0 and GetUnitState(udg_Proj_CollisionUnit, UNIT_STATE_LIFE) > 0 then
     
     //this checks to see if it is a projectile collision, ie only projectiles are involved.
    
     if GetUnitTypeId(udg_Proj_CollisionUnit) == udg_Proj_UnitId then
        if GetUnitTypeId(u) == udg_Proj_UnitId then
           set udg_Proj_CollisionIndex=LoadInteger(udg_Proj,GetHandleId(udg_Proj_CollisionUnit),1)
           set udg_Proj_CollisionIndex2=LoadInteger(udg_Proj,GetHandleId(u),1)
           set udg_Proj_CollidingU = u 
           set udg_Proj_CollisionEvent    = 1

        else
           set udg_Proj_CollidingU = udg_Proj_CollisionUnit 
           set udg_Proj_CollisionUnit=u
           set udg_Proj_CollisionIndex=LoadInteger(udg_Proj,GetHandleId(udg_Proj_CollidingU),1)
           set udg_Proj_CollisionEvent    = 0
        endif
     else
         
        set udg_Proj_CollidingU=u
        if GetUnitTypeId(udg_Proj_CollidingU) != udg_Proj_UnitId then
          set udg_Proj_CollisionEvent    = 2
        else
          set udg_Proj_CollisionIndex=LoadInteger(udg_Proj,GetHandleId(udg_Proj_CollidingU),1)
          set udg_Proj_CollisionEvent    = 0
        endif
     endif

     set udg_Proj_CollisionEvent       = -1

   endif
   set u = null
   return false
endfunction

// CreateProjectile takes player owner of projectile, real x coord, real y coord, real facing, real speed, real how long the projectile lasts, string attachement string ie "origin", string model 

function CreateProjectile takes player p, real x, real y, real f, real s, real l, string a, string e,unit target, real rate returns integer 
  local integer i = Proj_allocate()
  if udg_Proj_Max == 0 then
     call EnableTrigger(gg_trg_MS)
  endif

  set udg_Proj_Max = udg_Proj_Max +1

  if udg_Proj_Group_Count==0 then// if there are no enough projectiles that are idle it creates one

     set udg_Proj_U[i] = CreateUnit(p,udg_Proj_UnitId,x,y,f)
     call PauseUnit(udg_Proj_U[i],true)// pausing unit so user can't issue it orders, Unit in range does not detect units with 'aloc' so i am not giving the units 'aloc'
     set udg_Proj_T = CreateTrigger()
     call TriggerRegisterUnitInRange( udg_Proj_T, udg_Proj_U[i],60, null)// you can modify collision size here 
     call TriggerAddCondition(udg_Proj_T, Condition(function Proj_Collision))
     call SaveTriggerHandle(udg_Proj,GetHandleId(udg_Proj_U[i]),0,udg_Proj_T) // saving trigger etc...
     call SaveUnitHandle(udg_Proj,GetHandleId(udg_Proj_T),0,udg_Proj_U[i])

  else 

    loop

      set udg_Proj_U[i] = FirstOfGroup(udg_Proj_Group) // other wise it just gets one from Missle group
      call GroupRemoveUnit(udg_Proj_Group, udg_Proj_U[i])
      exitwhen udg_Proj_U[i] != null

    endloop

    set udg_Proj_Group_Count = udg_Proj_Group_Count - 1 
    call SetUnitX(udg_Proj_U[i],x)// seting projectiles position
    call SetUnitY(udg_Proj_U[i],y)
    call SetUnitFacing(udg_Proj_U[i],f)//setting its facing
    call SetUnitOwner(udg_Proj_U[i],p,true)//setting owner  
    call ShowUnit(udg_Proj_U[i],true)// making it visible
    call EnableTrigger(LoadTriggerHandle(udg_Proj,GetHandleId(udg_Proj_U[i]),0))
    call GroupRemoveUnit(udg_Proj_NotCollidable,udg_Proj_U[i])

  endif

  call SaveInteger(udg_Proj,GetHandleId(udg_Proj_U[i]),1,i)
  set udg_Proj_Y[i]         =((Sin(f*bj_DEGTORAD))*s)// setting Y coordinate speed
  set udg_Proj_X[i]         =((Cos(f*bj_DEGTORAD))*s)// setting X coordinate speed
  set udg_Proj_Life[i]      = l//setting "timed" life if you want it to travel a certain distance then the furmula would be distance/speed per second or distance/(speed/.03) 
  set udg_Proj_E[i]         = AddSpecialEffectTarget(e,udg_Proj_U[i],a)
  set udg_Proj_Target[i]    = target
  set udg_Proj_TurnSpeed[i] = rate
  set udg_Proj_Speed[i]     = s
  return i
endfunction


//=======================================================
//End of Narogog's 2d Projectile System v 0.4.0.0
//=======================================================
JASS:
function Angles_MoveAngleTowardsAngle takes real a1, real a2, real i returns real // copied from jasscraft
 local real x
    set a1=ModuloReal(a1,360)
    set a2=ModuloReal(a2,360)
    if a1>a2 then
        set x=a1-360
        if a1-a2 > a2-x then
            set a1=x
        endif
    else
        set x=a2-360
        if a2-a1 > a1-x then
            set a2=x
        endif
    endif
    if a1>a2 then
        set x=a1-i
        if x<=a2 then
            return a2
        endif
       return x
    endif
    set x=a1+i
    if x>=a2 then
        return a2
    endif
 return x
endfunction

function Trig_MS_Actions takes nothing returns boolean
   local integer this = udg_Proj_next[0] 
   local real x
   local real y
   local real xt
   local real yt
   local real a
   local real a2
   local real r
   local real r1
   local real r2
   if udg_Proj_Max == 0 then
     call DisableTrigger(gg_trg_MS)
   endif
   loop
      exitwhen 0 == this        
        set udg_Proj_Life[this]  = udg_Proj_Life[this]-.03
        if 0 > udg_Proj_Life[this] then
           set udg_Proj_CollisionUnit = udg_Proj_U[this]
           set udg_Proj_CollisionIndex = this
           set udg_Proj_CollisionEvent = 3.00
           set udg_Proj_CollisionEvent = -1.00
           call Proj_deallocate(this)
        else          
           set x             =  GetUnitX(udg_Proj_U[this])
           set y             =  GetUnitY(udg_Proj_U[this])
                      
           if null != udg_Proj_Target[this] then // this for Projectile tracking, if you don't want it delete this condition segment and all local vars other then this.
               if GetUnitState(udg_Proj_U[this], UNIT_STATE_LIFE) > 1 then
                  set xt            = GetUnitX(udg_Proj_Target[this])
                  set yt            = GetUnitY(udg_Proj_Target[this])
                  set r1            = xt-x
                  set r2            = yt-y
                  set a             = (Atan2(r2,r1)*bj_RADTODEG)
                  set a2 = Angles_MoveAngleTowardsAngle(GetUnitFacing(udg_Proj_U[this]),a,udg_Proj_TurnSpeed[this]+GetRandomReal(0.00,0.50))
                  set udg_Proj_Y[this]      =((Sin(a2*bj_DEGTORAD))*udg_Proj_Speed[this])// setting Y coordinate speed
                  set udg_Proj_X[this]      =((Cos(a2*bj_DEGTORAD))*udg_Proj_Speed[this])// setting X coordinate speed
                  call SetUnitFacing(udg_Proj_U[this],a2)
               else
                  set udg_Proj_CollisionUnit    = udg_Proj_U[this]
                  set udg_Proj_CollisionIndex   = this
                  set udg_Proj_CollidingU       = udg_Proj_Target[this]
                  set udg_Proj_CollisionEvent   = 3.50
                  set udg_Proj_CollisionEvent   =-1.00
               endif
           endif
           
           call SetUnitX(udg_Proj_U[this],x+udg_Proj_X[this])
           call SetUnitY(udg_Proj_U[this],y+udg_Proj_Y[this])
           
        endif
        set this     = udg_Proj_next[this]
   endloop
   return false
endfunction


// registers collision events for units entering the map
//made some comments here
function Proj_CreateCollision takes nothing returns nothing
   local unit u = GetTriggerUnit()

   if(IsUnitInGroup(u, udg_Proj_LeaveMap)) then // checking to see if the unit left the map.
        call GroupRemoveUnit(udg_Proj_LeaveMap, u)
   else
      if GetUnitTypeId(u) != udg_Proj_UnitId and GetUnitAbilityLevel(u,'aloc') == 0  then
         set udg_Proj_T     = CreateTrigger()
         //
         call TriggerRegisterUnitInRange( udg_Proj_T, u,60, null)// you can modify collision size here 
         call TriggerAddCondition(udg_Proj_T, Condition(function Proj_Collision))
         call SaveTriggerHandle(udg_Proj,GetHandleId(u),0,udg_Proj_T)
         call SaveUnitHandle(udg_Proj,GetHandleId(udg_Proj_T),0,u)
         //
       endif
   endif

   set u               = null
endfunction

function Proj_UnitDies takes nothing returns nothing
   local unit u = GetTriggerUnit()
   local trigger t =LoadTriggerHandle(udg_Proj,GetHandleId(u),0)
   call FlushChildHashtable(udg_Proj,GetHandleId(t))
   call DestroyTrigger(t)
   call FlushChildHashtable(udg_Proj,GetHandleId(u))
   set u = null
   call DisplayTextToPlayer(Player(0),0,0,"hello")
endfunction

function Proj_LeaveMap takes nothing returns nothing
   set udg_Proj_CollisionUnit  = GetTriggerUnit()
   call GroupAddUnit(udg_Proj_LeaveMap,udg_Proj_CollisionUnit)
   set udg_Proj_CollisionEvent = 4.00
endfunction
//function Proj_DestructableCollision takes nothing returns nothing
//    
//endfunction
//========================================================================
function InitTrig_MS takes nothing returns nothing
    local region r = CreateRegion()
    local group g
    local unit u
    set udg_Proj_UnitId = 'h000'
    call RegionAddRect(r, GetWorldBounds())
    set udg_Proj = InitHashtable()
    set gg_trg_MS = CreateTrigger(  )
    call TriggerRegisterTimerEvent(gg_trg_MS, 0.0312500, true)
    call TriggerAddCondition( gg_trg_MS, Condition(function Trig_MS_Actions) )   
    call TriggerRegisterEnterRegion(CreateTrigger(), r, Condition(function Proj_CreateCollision))
    call TriggerRegisterLeaveRegion(CreateTrigger(), r, Condition(function Proj_LeaveMap))

    set  udg_Proj_T = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ (udg_Proj_T, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(udg_Proj_T,Condition(function Proj_UnitDies))
    set g = GetUnitsInRectAll(GetPlayableMapRect())

    loop

      set u = FirstOfGroup(g)
      exitwhen u == null
      set udg_Proj_T = CreateTrigger()
      call TriggerRegisterUnitInRange( udg_Proj_T, u,60, null)// you can modify collision size here, what would be best to do is set an array or hash table with all the units collision size saved.
      call TriggerAddCondition(udg_Proj_T, Condition(function Proj_Collision))
      call SaveTriggerHandle(udg_Proj,0,GetHandleId(u),udg_Proj_T)
      call SaveUnitHandle(udg_Proj,0,GetHandleId(udg_Proj_T),u)
      call GroupRemoveUnit(g,u)

    endloop
    call DestroyGroup(g)
endfunction
if you notice any bugs please show me them.
Please look at the comparison between it and all of "the other projectile systems" some of which are "Gui and very good", "aproved" and one which is "Highly Recomended"

v0.1.0.0 uploaded for the first time had many flaws, and bugs
v0.2.0.0 reuploaded fixed bugs
v0.2.1.0 switched to "better methods"
v0.3.1.0 switced back to better method and improved test map.
v0.3.5.0.0 now destroys triggers when the unit connected to said trigger dies. also provided comparison between this and other non vJass systems. also added this change log and better documentation
added tracking, switched all of the add action to add condition, added an edge of map collision event and a targeted unit dies event(note, my "events" just set the value of a real)


Keywords:
2d,ef,unit collisions,projectile,missile
Contents

2d Projectile System v 0.4.0.0 (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 10 Nov 2011 Bribe: You have a number of errors in your code... Look at your init trigger, why do you create the trigger many different times during that process?

Moderator

M

Moderator

12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.


10 Nov 2011
Bribe: You have a number of errors in your code...

Look at your init trigger, why do you create the trigger many different times during that process?
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
I've said that to you many times. This system won't be approved in case there is too much to be improved wat will only lead to rewritting whole script.

Few of mistakes done:

- globals abuse
- SetUnitUserData == collision with any Indexings system
- save trigger handle? where is loop function? no timer, no group
- if udg_MS_Max == 0 then ->> if 0 == udg_MS_Max then (in all similar cases as well), it isn't a mistake, just speed improvement
- 3.141592/180 such things should be calculated by you instead of forcing script to do that for you; jass maths is slow even without that. To help you: it's about 0,01745
- global trigger? lol, replace it with local (InitTrig_ function in move trigger)
- TriggerRegisterTimerEventPeriodic( gg_trg_MS, 0.03 ) ->> TriggerRegisterTimerEvent(t, 0.03125, null)
- 0,03 should be changed to 0,03125 to be more accurate
- again it should be using global timer instead
- no dummy unit recycling? For such systems it's a must ;/

I don't have time now, but honestly to sum up last things: ton of trash code, low efficiency and script doesn't have readability that is for sure.

In current state it's hard to rate it even 1/5.
 
3.141592/180 such things should be calculated by you instead of forcing script to do that for you; jass maths is slow even without that. To help you: it's about 0,01745
Just to give you an idea:

JASS:
// This:
function hi takes nothing returns nothing
endfunction
call hi()
// is faster than this:
set i=i+1
// by approximately 60% according to benchmarks by Anitarf

Well, back on-topic:

- function CP takes player p, real x, real y, real f, real s, real l, string a, string e returns nothing
This function should be changed to be CreateProjectile.
- efficient projectile system capable of supporting 1000+ projectiles with out lagging -> You sure bro? 1000 units on the map lags the map heavily even without any code.
- call PauseUnit(udg_MS_U[udg_MS_Max],true)// pausing unit so user can't issu it orders, Unit in range does not detect units with 'aloc'
You don't need this
- 3.141592/180 -> bj_DEGTORAD


Also:

if udg_MS_Max == 0 then ->> if 0 == udg_MS_Max then (in all similar cases as well), it isn't a mistake, just speed improvement

Don't worry about that Spinnaker, Anitarf did some benchmarks and NO speed difference arose (with 28000 instances :p)
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
@baassee I was trying to prove author in his 2 threads on Help Zone/Triggering zone that creating one trigger per projectile stinks more than my GUI 8 years ago. however as you see, Narogog still thinks there is nothing wrong with it.

Or.. meaby thats newest speed improvement? Thousand of evaluated triggers seems to crash one lonely trigger with ease.
 
WAIT!
This creates one trigger per projectile?

That's going to KILL warcraft.

You should use a linked list instead.

JASS:
    // Variables
    integer array udg_Proj_next
    integer array udg_Proj_prev
    integer array udg_Proj_recycleNext
    integer udg_Proj_instanceCount
    integer udg_Proj_instanceRecycle
    
    function allocate takes nothing returns integer
        // allocate it
        local integer this
        if udg_Proj_instanceRecycle == 0 then
            set udg_Proj_instanceCount = udg_Proj_instanceCount + 1
            set this = udg_Proj_instanceCount
        else
            set this = udg_Proj_instanceRecycle
            set udg_Proj_instanceRecycle = udg_Proj_recycleNext[this]
        endif
        // add it to the list
        set udg_Proj_next[this] = 0
        set udg_Proj_prev[this] = udg_Proj_prev[0]
        set udg_Proj_next[udg_Proj_prev[0]] = this
        set udg_Proj_prev[0] = this
        // return the new instance
        return this
    endfunction
    
    // deallocate:
    function deallocate takes integer this returns nothing
        // deallocate it
        set udg_Proj_recycleNext[this] = udg_Proj_instanceRecycle
        set udg_Proj_instanceRecycle = this
        // remove it from the list
        set udg_Proj_next[udg_Proj_prev[this]] = udg_Proj_next[this]
        set udg_Proj_prev[udg_Proj_next[this]] = udg_Proj_prev[this]
    endfunction

Here's a quick one.
Just use arrays to store your data and to get an index, call allocate()
When a missile 'explodes', get it's index and call deallocate()

You'd loop through all the missiles in one function like this:

JASS:
local integer this = udg_Proj_next[0]
loop
    exitwhen this == 0
    // do stuff here for each missile given that 'this' is the index in the array
    set this = udg_Proj_next[this]
endloop
 
Level 10
Joined
Aug 21, 2010
Messages
316
call SaveTriggerHandle(udg_MS,0,GetHandleId(udg_MS_U[udg_MS_Max]),udg_T)
call SaveUnitHandle(udg_MS,0,GetHandleId(udg_T),udg_MS_U[udg_MS_Max])

try this

call SaveAgentHandle(udg_MS,0,GetHandleId(udg_MS_U[udg_MS_Max]),udg_T)
call SaveAgentHandle(udg_MS,0,GetHandleId(udg_T),udg_MS_U[udg_MS_Max])

and for the rest everything is already said
 
Level 7
Joined
Apr 1, 2010
Messages
289
=(
No love for the dude that wrote a super ugly linked list for you? D:

sorry about mispelling your name:goblin_cry: i was in a rush,

i do have a question for what you using a linked list, wouldn't looping through n index's and getting the distance between each index and the unit be slower the having multiple triggers, because warcraft math is rather slow and you would be doing
JASS:
set x = GetUnitX(u)-XofTarget
set y = GetUnitY(u)-YofTarget
set d = SquareRoot(x*x+y*y)
and then finding if the distance is less then whatever.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
wouldn't looping through n index's and getting the distance between each index and the unit be slower the having multiple triggers, because warcraft math is rather slow and you would be doing.
Nope ;P
If it was true, most vjass stuff had to be rewritten. I guess after all this years, most efficient ways have been found out and for sure it's not one trigger per instance. You had to upload this map into Spell section to make up your mind? I thought I told you enought things you have to improve/implement in threads you have started on Help Zone.

Or.. meaby you wanted to hear that from many users at once S;
 
i do have a question for what you using a linked list, wouldn't looping through n index's and getting the distance between each index and the unit be slower the having multiple triggers, because warcraft math is rather slow and you would be doing

Triggers are extremely slow:
Jass math is approximately 30x faster than a Trigger evaluation and 50x faster than a Trigger execution (According to Anitarf's benchmarks)
 
Level 7
Joined
Apr 1, 2010
Messages
289
Triggers are extremely slow:
Jass math is approximately 30x faster than a Trigger evaluation and 50x faster than a Trigger execution (According to Anitarf's benchmarks)

okay, i have updated it, is there a more efficient way to determine which projectile(s) are colliding? because as it is right now there is a slight lag whenever the projectiles collide of course that could be because of the multiple collisions that are occurring at a time.

please test the map.
 
Last edited:
Level 7
Joined
Apr 11, 2011
Messages
173
Too bad this wasn't 3D as in use of flying height or/ Z axis...

So.... I am looking for a way to increase the speed of a projectiles and I am guessing you didn't include a easy modification for that did you?

By the way I modified it and I am doing around 1400 projectiles, but since I can play with a simple amount of lag it would be only playable to people similar to me.

So......... I would like to help you with this for I have been trying for years to make systems for Wc3 that breaks its chains of speed... What I mean is I want to do a projectile system that can do giant scale combat.
 
Last edited:
Level 7
Joined
Apr 1, 2010
Messages
289
yes i did, you set when you create the projectile, call cp x coordinate, y coordinate, facing, speed, life, special effect attachment point, model. it is mentioned in front of the trigger that creates the projectiles.
well, you don't usually need to detect collisions constantly when you are using a 3d sytem, but i could add 3d motion by the way what did you modify?
 
allocate -> Proj_allocate
deallocate -> Proj_deallocate
Collision -> Proj_Collision
CP -> CreateProjectile

We want to avoid name collisions as much as possible ;)

Btw, your design is much faster now.
It could use more work though.

Instead of a periodic trigger, you should be using a timer that runs every 0.031250000 seconds (the zeroes are important - reals in wc3 are inaccurate)

edit
Didn't notice you were using custom values....
Just use an array and include a UnitIndexer here so you can use the custom value of the unit as the index of that array.
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
A projectile system should not have any hashtable reads.

It'll be a single timer that runs 32x a second and iterates through a linked list. It should use some arrays to store things like the target information.

For rotating projectiles, there is trig involved.

For initial movement calculation, there is trig involved.

The overhead becomes the trig, movement, and in range.

If you want to check if unit is in range more accurately, use the UnitInRange or w/e native. However, using that native will come at a cost (more overhead).

Essentially, if your script is using triggers at all (should only be the one for init), more than 1 timer, or doing anything more than a little trig + movement and iterating through a linked list, you've done it wrong and you need to start over.

If you want to do efficient in bounds checking, you'll want to add some trigger overhead to the projectiles with sad hashtable reads inside of the triggers. However, this'll remove the in range check from the timer, which is a good thing ^)^.

First of group loops are slower than unit in range events, so you'll really want to stick with unit in range events. Another downside is that you won't be able to have projectiles collide with each other ; P.

If you want projectiles to collide with each other, then you'll want to do a first of group loop, which'll incur some overhead =).

The first of group loop will remove the need for the hastable and the need for any triggers ^)^.
 
Level 7
Joined
Apr 1, 2010
Messages
289
where is the efficient part eh?

hmm, i uploaded the the wrong version reuploading... Now test again,
I do have a question for you, can you show me a system that can do 1080 projectiles? with projectile collisions and unit collisions? All of the ones i've seen can only manage 300 projectiles, of course most of those are more complex they have 3d movement, arcing xy movement but for all that you would require a insanely fast computer to manage 1080 projectiles.
 
Being able to handle 1080 projs doesn't equate to efficiency... that's more of the system being more powerful than the others

and you already also said that even though they can only handle about 300, they support 3d which is part why they can support less... so I guess you cannot say that this is more efficient than them since your system and their system are on two different fields... They play on the 3D field, and yours on the 2D field, which makes the difference...

but yeah, for just 2d, your system is indeed powerful and maybe more efficient than those other 2D which can only do 300 something... I think its better to say, more powerful and efficient than the other 2D proj systems...

and I'd certainly want to see this rise up to near perfection... (coz I don't like perfection, its a dead end)
 
Level 7
Joined
Apr 1, 2010
Messages
289
Being able to handle 1080 projs doesn't equate to efficiency... that's more of the system being more powerful than the others

and you already also said that even though they can only handle about 300, they support 3d which is part why they can support less... so I guess you cannot say that this is more efficient than them since your system and their system are on two different fields... They play on the 3D field, and yours on the 2D field, which makes the difference...

but yeah, for just 2d, your system is indeed powerful and maybe more efficient than those other 2D which can only do 300 something... I think its better to say, more powerful and efficient than the other 2D proj systems...

and I'd certainly want to see this rise up to near perfection... (coz I don't like perfection, its a dead end)

Perfection is impossible to reach, just like the speed of light it takes an infinite amount of work to gain perfection...

You say they play on 3d fields which slows them down, from my knowledge that isn't so, if you disable unit and projectile collisions on say Anachrons system it can support more projectiles then this system can. the problem for all projectile systems is detecting collisions. Most techniques are very slow, enumerating unit groups every .03 seconds slows down most projectile systems which is why my system can support more units becuase it doesn't use unit groups other then the recycle group, which is only used when needed, and never destroyed.

I Hope to improve this system enough until it becomes the standard for projectile systems, for 2d projectile systems all i will need to do is add tracking, Terrain wall Collisions, destructable collisions.
 
Level 10
Joined
Aug 21, 2010
Messages
316
Honestly, I do not like the way this is done.

1. Primarily, the approach is totally wrong.
2. The possibilities and options of this system are very poor.
3. A bunch of errors.
4. The mechanism of the system is very bad.
5. There is no kind of help to one who uses this system.
6. Missing a bunch of useful things
7. User functions are desperate.
8. Generally, this can hardly be called a system.

Maybe this is what I said a little extreme but it is nothing personal.
 
Level 7
Joined
Apr 1, 2010
Messages
289
1 explain yourself. My system can support more projectiles then any other system that does unit collisions and projectile collisions.
2 well, you could do space combat maps very well with this system, as it detects unit collisions with minimal lagg.
3 explain
4 can you show me a system that can handle 800 or even 600 projectiles while supporting unit and projectile collisions?
5 you are completely right.
6 also true
7 explain
8 look at 4

edit: updated, added a comparison
 
Last edited:
Level 7
Joined
Apr 1, 2010
Messages
289
->

非常好的系统!
但它可能使用了一些改进。

Thanks :grin: (though i am not sure if Google translator gives an accurate translation),

working on removing the trigger leaks and i have modified all of the condition functions(that are used in place of actions) so that they return false(but haven't updated yet) and have added unit tracking.
should i change the test map so that it shows this system in use? ie with units attacking, shooting projectiles as their normal weapons?
 
Level 13
Joined
Sep 13, 2010
Messages
550
Its not against you at first.

A few things... Use libraries! Don't use that much triggers, use triggers for every 10+ units to recycle. Is it fast? Nope, I don't believe. Thats sure creating those pigs periodically lagging as hell. Well my laptop is not that weak so 1400 pigs and units just made it FPS drop down to 40... API inside the map header script.. I can't even say more *clap*.( use libraries! It saves life ) It randomly crashes *clap*^10. Well uploading unstable resources is not a good choice. I'm so sorry, but this is in this state is unacceptable...

Oh and almost forgot... Syntax errors... Out of clap
 
Level 7
Joined
Apr 1, 2010
Messages
289
please explain what happened prior the random crashes, because i am guessing they occurred from a unit going off of the playable map.

also this is a jass resource, not vjass so libraries are kind of out of the picture.
i am working on updating it and have switched all of the actions to conditions instead,
but before i update i would like to know what syntax errors you found?
 
Level 7
Joined
Apr 1, 2010
Messages
289
Updated.
i have now added a check, it enables the user to trigger an event when an object leaves the playable map.
My computer can support +/-2700 projectiles now, and it won't lagg with less then 120 collisions happening at the same time. I think what is preventing more projectiles is the loop....


also, i am going to start a thread(tomorrow) to help me fix the dynamic trigger leaks Bribe mentioned.
Good night.
 
Level 13
Joined
Sep 13, 2010
Messages
550
Syntax error:
Line 1170: Functions passed to Filter or Condition must return boolean

JASS:
function Proj_CreateCollision takes nothing returns nothing
   local unit u = GetTriggerUnit()

   if(IsUnitInGroup(u, udg_Proj_LeaveMap)) then // checking to see if the unit left the map.
        call GroupRemoveUnit(udg_Proj_LeaveMap, u)
   else
      if GetUnitTypeId(u) != udg_Proj_UnitId and GetUnitAbilityLevel(u,'aloc') == 0  then
         set udg_Proj_T     = CreateTrigger()
         //
         call TriggerRegisterUnitInRange( udg_Proj_T, u,60, null)// you can modify collision size here 
         call TriggerAddCondition(udg_Proj_T, Condition(function Proj_Collision))
         call SaveTriggerHandle(udg_Proj,GetHandleId(u),0,udg_Proj_T)
         call SaveUnitHandle(udg_Proj,GetHandleId(udg_Proj_T),0,u)
         //
       endif
   endif

   set u               = null
endfunction

...

call TriggerRegisterEnterRegion(CreateTrigger(), r, Condition(function Proj_CreateCollision))
Line 1171: Functions passed to Filter or Condition must return boolean

JASS:
function Proj_LeaveMap takes nothing returns nothing
   set udg_Proj_CollisionUnit  = GetTriggerUnit()
   call GroupAddUnit(udg_Proj_LeaveMap,udg_Proj_CollisionUnit)
   set udg_Proj_CollisionEvent = 4.00
endfunction

...

call TriggerRegisterLeaveRegion(CreateTrigger(), r, Condition(function Proj_LeaveMap))
Line 1175: Functions passed to Filter or Condition must return boolean

JASS:
function Proj_UnitDies takes nothing returns nothing
   local unit u = GetTriggerUnit()
   local trigger t =LoadTriggerHandle(udg_Proj,GetHandleId(u),0)
   call FlushChildHashtable(udg_Proj,GetHandleId(t))
   call DestroyTrigger(t)
   call FlushChildHashtable(udg_Proj,GetHandleId(u))
   set u = null
   call DisplayTextToPlayer(Player(0),0,0,"hello")
endfunction

...

call TriggerAddCondition(udg_Proj_T, Condition(function Proj_UnitDies))
Hmpf. Anyway it can be caused I am using different version of pjass or Jass Helper.

Use libraries. Use the advantage of globals endglobals. Use a vJass-Jass hibrid. You are using vJass like function names... Also on a Jass resource I don't really believe to leave that much variables as GUI variable, because users copy your functions, then have to copy every variable. That is not a good idea. Also leaving that in the map header. Put it into libraries and into one directory. Anyway this version looks better now, less lagg... But crash is still here. The problem can be that if I cast on an unit a projectile, projectile not gets removed, just randomly doing circles.

Edit: Also I checked you leakings: Handles after having 3000 projectiles: over 17000 handles used. A big orpg has overall 11000-15000 handles. Having so much handles are bad cause some users save values connected to handle into arrays like set Array[0x100000 - GetHandleId( Location( 0.0 , 0.0 ) )] = 120 so if number higher than 8192 then it may cause crash, else malfunctioning cause his system can't refer to those. Also it is bad to have so much handles cause every handle takes memory. If it has to make more handles then game will eat more memory which is not good. Nulling variables( globals too ) after using solves this problem.
 
Last edited:
Level 7
Joined
Apr 1, 2010
Messages
289
@geries i am not using pJass, cJass or vJass i am using Jass, because i don't want the user to have to use Jass Helper, anyways, how are you getting 17000 handles? please explain so that i can fix, because as i see it(probably incorrectly) there is 1 unit handle per projectile and1 trigger handle per projectile with 3000 projectiles that's 6000,
though as i said earlier i am probably not seeing it right.
However the projectile will get removed after its life(well, not realy its life but a real that is reduced while the projectile runs.) expires(in this case 50 seconds)

about the projectile not getting removed, the way my system works is the user sets and integer = CreateProjectile(....) and then can use the returned integer to save array values. The user then creates 3 triggers, one that erases the users data when a projectile "dies" (using when CollisionEvent = 3.00) and one that triggers when a projectile collides with a unit, and one that detects when a projectile leaves the map, the reason i do it this way is if you make a tracking missile, you don't want it to be removed because it leaves the map to turn around

You have no support for homing missiles
i do...
although my tracking is pretty bad, it can be easily tricked avoided by standing in the middle of its arc(turning circle?), Which am going to fix next update by comparing the facing of the projectile with the angle and if the projectile is too close(with the diameter of the projectiles turn radius) and the angle is too far away then the projectile will just continue straight and then after getting far enough away turn around.
 
Level 13
Joined
Sep 13, 2010
Messages
550
i am not using pJass, cJass or vJass i am using Jass, because i don't want the user to have to use Jass Helper
Big mistake.

how are you getting 17000 handles?
You are making them.
Please explain so that i can fix, because as i see it(probably incorrectly) there is 1 unit handle per projectile and1 trigger handle per projectile with 3000 projectiles that's 6000
Nope. You are using one conditionfunc, triggercondition, one event, a trigger and an unit + one special effect. Anyway you were right... not 17000. Its 18000.

However the projectile will get removed
Handles gotta reused when you reallocate, but for example on map init user creates 1000 projectiles and removes them will return 6000 handle leak, then make one returns 5994 leak... Globals leak handles as well however when you reuse them leak got freed not like locals, cause locals got destroyed and leak remain after them. Trigger variables by this way leak 4 handles...
 
Level 7
Joined
Apr 1, 2010
Messages
289
thanks for explaining how there are that many.

are you sure teh effect leaks? It does get destroyed by the deallocate function.... that would mean its a total of 15000, still you are right that is a big ouch.
 
Top