System Projectile

Kenny

Back for now.
Reaction score
202
Glad everything worked out..

I am currently working on completing the 0.2.4 version. I want to add some more improvements though before I release it. I am trying to fix up some stuff with the projgroups to make them a bit more efficient, and I am working on different ways to make the core of the system more efficient while keeping the interface user friendly.

I am hoping to get it up in a couple of days. :)

JASS:
.
    struct projgroup
        implement LinkedList

        private projectile array list[MAX_PROJGROUP_SIZE]
        private integer count = 0
        
        //------------------------------------------------------------\\
        //  Destroy method: Clear all data and destroy the struct.
        method destroy takes nothing returns nothing
            call this.clear()
            call this.detachThis()
            call this.deallocate()
        endmethod
        
        //------------------------------------------------------------\\
        //  ForGroup method: Execute function for all projectiles.
        method forGroup takes EnumEvents whichFunc returns nothing
            local integer i = this.count - 1
            
            loop
                exitwhen i < 0
                set EnumProjectile = this.list<i>
                call whichFunc.evaluate()
                set i = i - 1
            endloop          
        endmethod
        
        //------------------------------------------------------------\\
        //  Enum method: Group all nearby projectiles.
        method enumNearby takes real x, real y, real z, real radius returns nothing
            local projectile p = ProjectileList.head
            local vector     v = vector.create(x,y,z)
            
            call this.clear()
            
            loop
                exitwhen p == 0
                if p.posVect.isInSphere(v,radius) then
                    call this.add(p)
                endif
                set p = p.next
            endloop
            
            call v.destroy()
        endmethod
        
        //------------------------------------------------------------\\
        //  Remove method: Remove a projectile from a projgroup.
        method remove takes projectile whichProj returns boolean
            local integer i = this.count - 1
            
            if whichProj != null and this.isInGroup(whichProj) then
                call RemoveSavedBoolean(StorageHash,integer(this),integer(whichProj))
                loop
                    exitwhen i &lt; 0
                    if this.list<i> == whichProj then
                        set this.count = this.count - 1
                        set this.list<i> = this.list[this.count]
                        return true
                    endif
                    set i = i - 1
                endloop
            endif
            
            return false
        endmethod
        
        //------------------------------------------------------------\\
        //  Add method: Add a projectile to a projgroup.
        method add takes projectile whichProj returns boolean
            if this.count &lt; MAX_PROJGROUP_SIZE and whichProj != null and not this.isInGroup(whichProj) then
                call SaveBoolean(StorageHash,integer(this),integer(whichProj),true)
                set this.list[this.count] = whichProj
                set this.count = this.count + 1
                return true
            endif
            
            return false
        endmethod
        
        //------------------------------------------------------------\\
        //  Clear method: Clear all data from a projgroup.
        method clear takes nothing returns nothing
            local integer i = this.count - 1
            
            loop
                exitwhen i &lt; 0
                set this.list<i> = 0
                set i = i - 1
            endloop
            
            set this.count = 0
            
            call FlushChildHashtable(StorageHash,integer(this))
        endmethod
        
        //------------------------------------------------------------\\
        //  IsInGroup method: Check if a projectile is in a projgroup.
        method isInGroup takes projectile whichProj returns boolean
            return HaveSavedBoolean(StorageHash,integer(this),integer(whichProj))
        endmethod
        
        //------------------------------------------------------------\\
        //  FirstOfGroup method: Retrieve first projectile.
        method firstOfGroup takes nothing returns projectile
            return this.list[0]
        endmethod
        
        //------------------------------------------------------------\\
        //  Count method: Retrieve number of projectiles in projgroup.
        method getCount takes nothing returns integer
            return this.count
        endmethod
        
        //------------------------------------------------------------\\
        //  Projgroup creation.
        static method create takes nothing returns thistype
            return ProjGroupList.addToStart(thistype.allocate())
        endmethod
        
    endstruct
</i></i></i></i>


JASS:
.
    private function ForProjGroupCallback takes nothing returns nothing
        set EnumProjectile = projectile[GetEnumUnit()]
        call EnumEvents(ForGroupStack.top.callback).evaluate()
    endfunction
    
    struct projgroup
        implement LinkedList

        private integer max = 0
        private group   grp
        
        //------------------------------------------------------------\\
        //  Destroy method: Clear all data and destroy the struct.
        method destroy takes nothing returns nothing
            static if LIBRARY_Recycle then
                call Group.release(this.grp)
                set this.grp = null
            elseif LIBRARY_GroupUtils then
                call ReleaseGroup(this.grp)
                set this.grp = null
            else
                call GroupClear(this.grp)
            endif
            
            call this.detachThis()
            call this.deallocate()
        endmethod
        
        //------------------------------------------------------------\\
        //  ForGroup method: Execute function for all projectiles.
        method forGroup takes EnumEvents whichFunc returns nothing
            call ForGroupStack.increment()
            set ForGroupStack.top.callback = whichFunc
            call ForGroup(this.grp,function ForProjGroupCallback)
            call ForGroupStack.decrement()
        endmethod
        
        //------------------------------------------------------------\\
        //  Enum method: Group all nearby projectiles.
        method enumNearby takes real x, real y, real z, real radius returns nothing
            local projectile p = ProjectileList.head
            local vector     v = vector.create(x,y,z)
            
            call this.clear()
            
            loop
                exitwhen p == 0
                if p.posVect.isInSphere(v,radius) then
                    call this.add(p)
                endif
                set p = p.next
            endloop
            
            call v.destroy()
        endmethod
        
        //------------------------------------------------------------\\
        //  Remove method: Remove a projectile from a projgroup.
        method remove takes projectile whichProj returns boolean            
            if whichProj != 0 then // and IsUnitInGroup(whichProj.dummy,this.grp) then
                call GroupRemoveUnit(this.grp,whichProj.dummy)
                set this.max = this.max - 1
                return true
            endif
            
            return false
        endmethod
        
        //------------------------------------------------------------\\
        //  Add method: Add a projectile to a projgroup.
        method add takes projectile whichProj returns boolean
            if whichProj != 0 then // and not IsUnitInGroup(whichProj.dummy,this.grp) then
                call GroupAddUnit(this.grp,whichProj.dummy)
                set this.max = this.max + 1
                return true
            endif
            
            return false
        endmethod
        
        //------------------------------------------------------------\\
        //  Clear method: Clear all data from a projgroup.
        method clear takes nothing returns nothing
            call GroupClear(this.grp)
            set this.max = 0
        endmethod
        
        //------------------------------------------------------------\\
        //  IsInGroup method: Check if a projectile is in a projgroup.
        method isInGroup takes projectile whichProj returns boolean
            return IsUnitInGroup(whichProj.dummy,this.grp)
        endmethod
        
        //------------------------------------------------------------\\
        //  FirstOfGroup method: Retrieve first projectile.
        method firstOfGroup takes nothing returns projectile
            return projectile[FirstOfGroup(this.grp)]
        endmethod
        
        //------------------------------------------------------------\\
        //  Count method: Retrieve number of projectiles in projgroup.
        method getCount takes nothing returns integer
            return this.max
        endmethod
        
        //------------------------------------------------------------\\
        //  Projgroup creation.
        static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
            
            static if LIBRARY_Recycle then
                set this.grp = Group.get()
            elseif LIBRARY_GroupUtils then
                set this.grp = NewGroup()
            else
                if this.grp == null then
                    set this.grp = CreateGroup()
                endif
            endif
            
            return ProjGroupList.addToStart(this)
        endmethod
        
    endstruct
 

xombie

New Member
Reaction score
2
I don't know how serious this is, but isn't it bad to use dynamic triggers? The collision detection seems to be done with the an event; also to mention that this method will avoid detecting collision on units that are already in the projectile's collision radius when the event is registered.

I'm really curious as to where you got the Slow Time model from though it is really nice.

I actually have a system of my own that handles projectiles; and while I really like how many features you've implemented properly it seems that when you're running a lot of projectiles (hundreds) it starts really lagging up my computer. Here's mine :p

http://www.hiveworkshop.com/forums/jass-functions-413/custom-projectiles-162121/

It's not nearly as in-depth as yours is; lately I've just been trying to clean up the features that I didn't fully complete in the initial release and then I was going to work from there.
 

Kenny

Back for now.
Reaction score
202
Ahh so you're Berb! Nice to see you on thehelper. :)

I think I know your system back to front by now, I actually got the idea for projectile time scales from you (you have been credited).

About dynamic triggers. I am pretty sure that after debates and discussions with some members here (I think there was something over at wc3c as well) people came to the conclusion that dynamic triggers were safe as long as they were dealt with properly, which means avoiding trigger actions, properly clearing trigger conditions and disabling triggers before destroying them.

I ended up using this method for collision detection because (from my tests) it appeared to be more efficient. I know it has its drawbacks, but when used correctly it gives a noticeable efficiency increase (I haven't run into any troubles with it yet as well).

The Slow Time model was made by Vestras I think, but I did a lot of editing to it myself so get it how I wanted it (basically did everything besides the mesh).

I have tested your system many times and I really like it. I currently have test maps for both mine and yours to compare performance levels.

With your system (v2.0) and mine (v2.4.0) I have come to the conclusion that they are very similar in terms of efficiency. On my crappy laptop, my system handles approximately 150 projectiles at around 15 FPS (which is good for me) while yours handles around 140 with the same FPS. And with projectile recycling, my system can handle a few more as well.

I know it is biased of me to say that mine tested better then yours (I do not have any substantial proof), however it is what I've seen so far, but only by a tiny margin. Although, I could see that with a larger amount of projectiles (250+) my system would probably start to lose efficiency due to trigger, group, rect and region creation. But with a smaller number it seems to work better.

Putting efficiency aside, I think the major benefit from this system is the standardised interface. Users cannot extend structs and create similar projectile all with different names. Coding a projectile becomes simple and easy, and is the same every time. I think that is a huge thing for people who don't fully understand vJass. I also extended the projgroup interface to ensure it was similar to that of wc3 group natives.

Oh and by the way, you may want to looks into your projectile groups, I don't think they work correctly when a projectile that was just added is destroyed then recreated using the same projectile instance and added again..

For example:

(Say we are only using one projectile here)

You create a projectile -> it becomes projectile(1)

You add the projectile to a projectilegroup.

You destroy projectile(1), but there is no way to detect this and remove it from the projectilegroup.

You create another projectile -> this becomes projectile(1) again.

The projectile is already seen as in the projectilegroup when it should not be.

It is a problem and I have tested it numerous times. I have come up with a solution for it in my system, but it isn't great. It makes projectile destruction slow..
 

xombie

New Member
Reaction score
2
Really? When I tested your system on my laptop I was experiencing a drop to 40 FPS when roughly 150~160 projectiles were in flight while my system was able to do that without even dropping to 55 FPS. I don't know, I'm not going to get into it. I was just recently informed of this system and I really like the amount of work that was put into all of its functionality.

In terms of the group problem I will try to look into a good approach of solving that problem, I can see why it would be a problem.
 

Kenny

Back for now.
Reaction score
202
Yeah, I know what you mean. I don't really feel like starting something like that. I read your thread on the hive..

I am still looking to improve this as much as possible, I have reduced the periodic method down as much as possible. I will look for a solution to the group problem as well.
 

xombie

New Member
Reaction score
2
Okay I think I may have come up with a solution to the group problem. In order to keep the amount of groups that a projectile can be kept in unlimited I had to use hashtables, and in order to eliminate any necessity of loops I had to use an additional two. Well that is a lie, there is a necessity for a loop in the [ljass]onDestroy[/ljass] method to clean out projectiles being destroyed from any groups they may have been in.

This is how the add/remove methods are looking:

JASS:
        method add takes projectile p returns boolean                 
        if size &lt; ENUM__storageMax and not inGroup(p) then           
            call SaveInteger(thistype.table, this, p, size)  
            set indexOf[size] = p                                  
            set size = size + 1    
            
            if not HaveSavedInteger(projGroupTable, p, 0) then          
                call SaveInteger(projGroupTable, p, 0, this)
                call SaveInteger(projGroupTableReverse, p, this, 0)
                call SaveInteger(projGroupTable, p, -1, 1)
            else
                call SaveInteger(projGroupTable, p, LoadInteger(projGroupTable, p, -1), this)
                call SaveInteger(projGroupReverse, p, this, LoadInteger(projGroupTable, p, 0))
                call SaveInteger(projGroupTable, p, -1, LoadInteger(projGroupTable, p, -1) + 1)
            endif
            
            return true                                           
        endif                                                      
        return false
    endmethod
    method remove takes projectile p returns boolean               
        local integer index 
        local integer length
        if inGroup(p) then           
            set size = size - 1
            set indexOf[LoadInteger(thistype.table, this, p)] = indexOf[size]
            call RemoveSavedInteger(thistype.table, this, p)
        
            set length = LoadInteger(projGroupTable, p, -1) - 1
            call SaveInteger(projGroupTable, p, -1, length)
            call SaveInteger(projGroupTable, p, LoadInteger(projGroupTableReverse, p, this), length)
            call SaveInteger(projGroupTableReverse, p, length, length)
            if length == 0 then
                call FlushChildHashtable(projGroupTable, p)
                call FlushChildHashtable(projGroupTableReverse, p)
            endif
        
            return true
        endif
        return false
    endmethod


And this is what I've done when projectiles are destroyed:

JASS:
            if HaveSavedInteger(projGroupTable, this, 0) then
            set i = LoadInteger(projGroupTable, this, -1)
            loop
                exitwhen i &lt; 0
                call projectilegroup(LoadInteger(projGroupTable, this, i)).remove(this)
                set i = i - 1
            endloop
        endif


It still needs work though the projectile group's [ljass]onDestroy[/ljass] method is going to need to have some operations that clear the indexes of hashtables for projectiles that were included in the destroyed group - if that makes sense.

The "reverse" hashtable is for referencing the index of a group hashed to a projectile when the projectile is being removed from the group. If a projectile is destroyed then these hashtables automatically clean the child hashtable associated with the projectile, in addition to the projectile being removed from any groups that it may have been apart of.

I'm thinking the projectile-group destructer is also going to have to have a loop that iterates through its members and removes them from the group appropriately. Before I didn't even bother doing this. I must have overlooked it.

I found something else that overlooked; the [ljass]kill( )[/ljass] method before wouldn't do anything if a projectile hadn't been launched. Since I restrict access to the [ljass]onDestroy[/ljass] method (so they can't call it at weird times) I added the method, though after looking at the code it is never evaluated unless the projectile is "active". That's another fix for 2.0b.

Okay so now I've got this executing at map initialization:

JASS:
private function init takes nothing returns nothing
    local projectilegroup pg = projectilegroup.create( )
    local projectile p = projectile.create(null)
    
    call pg.add(p)
    if not pg.add(p) then
        call BJDebugMsg(&quot;Didn&#039;t add. This is correct.&quot;)
    endif
    
    call p.kill( )
    set p = projectile.create(null)
    
    if pg.inGroup(p) then
        call BJDebugMsg(&quot;Projectile is in group, but shouldn&#039;t be.&quot;)
    endif

endfunction


I also made it so that if the [ljass]kill( )[/ljass] method is called while the projectile is not active (it hasn't been launched) then it will proceed to destroy the projectile immediately. Anyways, this script displayed the first message but not the second. I'll run some more tests to see if it was successful, what I was doing with the hashtables seems like it was way too complex for me to have worked it out on the first try.

I need to work on clarifying my interface. I find it so ridiculous how I've got a [ljass]kill( )[/ljass] method in substitute for [ljass]destroy( )[/ljass], it doesn't even seem completely necessary. I could probably add a flag that notifies the iteration loop when a projectile has already been destroyed so it ignores the index - that seems like a better approach than causing the confusion that my [ljass]kill( )[/ljass] method does (to me at least).

Eh, there's still bugs; I'll sort through it tomorrow it's already 7AM, I've really got to think about heading to bed.
 

Anachron

New Member
Reaction score
53
I never understood why you need to loop through anything when you remove something from an index. Why don't you use a second table to store the index that the missile is using?
 

muzk

Member
Reaction score
3
If you use recycle, the misil will show his rotation (ex. launch to 45º then to 0º) ... is this a war3 problem?
 

Kenny

Back for now.
Reaction score
202
I've been working pretty hard on the next version of this (v0.2.4). I have revised a lot of the aspects that have been in the system since day one to see if they can be improved and I have spent a lot of time trying to cut down the periodic method to a bare minimum, making this system the most efficient projectile system out there.

Changes for the next version will include:

  • Added two new general methods: [ljass]this.refresh()[/ljass] and [ljass]this.removeAll()[/ljass]. Read documentation for details.
  • Added projectile data attachment. Basically just hashtable wrappers, but they give an easy interface for storing extra data in a projectile.
  • Data attachment methods: [ljass]this.attachData()[/ljass], [ljass]this.getData()[/ljass], [ljass]this.hasData()[/ljass] and [ljass]this.detachData()[/ljass]. Details in documentation.
  • Removed some unneeded multiplications, divisions and variable sets/retrievals in the periodic method (tiny, tiny efficiency increase).
  • Added safety to [ljass]this.addUnit()[/ljass] and [ljass]this.removeUnit()[/ljass].
  • Added [ljass]this.arcSize[/ljass] as a readonly member to retrieve a projectiles arc size when it was created.
  • Renamed [ljass]this.setTargetPoint()[/ljass] to [ljass]this.setTargPoint()[/ljass] and [ljass]this.setProjectilePoint()[/ljass] to [ljass]this.setProjPoint()[/ljass].
  • Added a user event for when a projectiles timed life expires ([ljass]this.onExpire[/ljass]). This allows for some pretty cool things to be done.
  • The user event for when a projectile hits the ground will only when it first hits the ground, not repeatedly as it use to.
  • Inlined a method used in the core of the system for a small efficiency gain.
  • Added a max projectile limit and max projgroup limit (8190 each) for the sake of it. They will never need to be changed.
  • Completely rewrote projgroups. Same interface, just more efficient. There is now no limit to how many projectiles can be in a projgroup.
  • Changed around the [ljass]this.projectNormal()[/ljass] and [ljass]this.projectArcing()[/ljass] methods to make them neater and work properly with [ljass]this.refresh()[/ljass].
  • Added two more configurables for the max projectile and projgroup limits. Again, these won't need to be changed.
  • Removed some useless function calls and stuff from the [ljass]this.targetUnit[/ljass] method operator.
  • Removed [ljass]this.setTargPoint()[/ljass] from [ljass]this.disjoint()[/ljass], as it was pointless and looked bad.
  • Renamed [ljass]this.projectileSpeed[/ljass] to [ljass]this.currentSpeed[/ljass].
  • Cleaned up some parts of the system script.
  • Updated documentation.

As you can see, it is quite an extensive list of changes. I have tried to go over everything in the system to improve on three main aspects:

  • Efficiency
  • Ease of use
  • Simplicity

The addition of the new methods recently is to create an easy to use interface for users that covers all aspects of projectile manipulation. Data attachment will allow users to attach an additional struct to a projectile to carry extra data.

The unit group methods added ([ljass]this.addUnit()[/ljass] etc.) can be used to manually manipulate which units have been hit and which haven't. This can come in handy if a user wants a particular projectile to hit a unit twice, or hit units once on the way out (away from the caster) and once on return.

I believe the API for the system is still very simple (albeit quite huge), making it pretty easy to understand. I think the API is probably the easiest to understand out of all projectile systems (with the inclusion of the detailed documentation).

And when I talk about simplicity, I am also talking about the system is written. Currently it is quite maintainable, which is excellent for future updates.

So yeah, I am pretty happy with where this is heading. :)

I hope to update this pretty soon.

Edit:

About the new projgroups:

The current version of projgroups has a limit to how many projectiles can be in a single projgroup (and therefore a more realistic limit to how many projgroups there can be). This is a very annoying drawback that I am very determined to get rid of.

The new version of projgroups that is currently in the works removes the limit of how many projectiles can be in a projgroup (and the projgroup limit) and has also increased efficiency in regards to the add, remove, clear, isInGroup and destroy methods.

However, the forGroup, create and firstOfGroup methods are now a little slower (it isn't anything noticeable for create and firstOfGroup, however it is a little noticeable in the forGroup method). I am looking at ways of fixing this as well.
 

xombie

New Member
Reaction score
2
Kenny I just wanted to post back and tell you that I have solved the problem regarding projectile ghosts remaining in groups. As I said before, it really doesn't affect the efficiency of anything because the only loop that is required is in the projectile destroy method (to remove the projectile from any groups it may have been a part of) but other than that I haven't noticed any drop. There are a couple of hash-table calls but those are not terribly slow. I'll post my destroy method, and the group methods that were affected in case you need them:

** Edit - Some corrections were necessary **

JASS:
    method add takes projectile p returns boolean    
        local integer indexOfLast
        if size &lt; ENUM__storageMax and not inGroup(p) then           
            call SaveInteger(thistype.table, this, p, size)  
            set indexOf[size] = p                                  
            set size = size + 1    
    
            set indexOfLast = 0
            if HaveSavedInteger(projGroupTable, p, -1) then
                set indexOfLast = LoadInteger(projGroupTable, p, -1)
            endif
            call SaveInteger(projGroupTable, p, indexOfLast, this)
            call SaveInteger(projGroupTableRev, p, this, indexOfLast)
            call SaveInteger(projGroupTable, p, -1, indexOfLast + 1)
            
            return true                                           
        endif                                                      
        return false
    endmethod
    method remove takes projectile p returns boolean 
        local integer indexOfLast
        local integer indexOfThis
        if inGroup(p) then           
            set size = size - 1
            set indexOf[LoadInteger(thistype.table, this, p)] = indexOf[size]
            call RemoveSavedInteger(thistype.table, this, p)
        
            set indexOfLast = LoadInteger(projGroupTable, p, -1) - 1
            set indexOfthis = LoadInteger(projGroupTableRev, p, this)
            call SaveInteger(projGroupTable, p, -1, indexOfLast)
            call SaveInteger(projGroupTable, p, indexOfThis, LoadInteger(projGroupTable, p, indexOfLast))
            call SaveInteger(projGroupTableRev, p, LoadInteger(projGroupTable, p, indexOfThis), indexOfThis)
            
            if indexOfLast &lt; 1 then
                call FlushChildHashtable(projGroupTable, p)
                call FlushChildHashtable(projGroupTableRev, p)
                
            endif
            return true
        endif
        return false
    endmethod


I'm too lazy to post the onDestroy method, but I'm sure you get the picture from here.

Oh and I would really like to use the same "Slow Time" special effect model that you use in your test-map I was wondering if you were okay with that?
 

Kenny

Back for now.
Reaction score
202
Oh and I would really like to use the same "Slow Time" special effect model that you use in your test-map I was wondering if you were okay with that?

Yeah go ahead and use it :). Just be sure to credit Vestras (I think that is his name), as he made the mesh and original animations for it. I only redid the textures, colours and materials (and slighty changed the animations).

Nice work fixing the ghost projectile issue as well. I wish there was a less complicated way of doing it though..

Edit:

Back to the system: I am still working on some things to try and squeeze everything out of it that I can, but there should be an update soon.

Edit 2:

Version 0.2.4 (Beta) is now out. Heaps of changes! Read the change log for details.
 

xombie

New Member
Reaction score
2
I've already implemented it in my map, so I'll be sure to credit Vestras; it should appear in my next version update, whenever that may be.

Nice work fixing the ghost projectile issue as well. I wish there was a less complicated way of doing it though..

It's not that complicated, and it conserves the efficiency that is outlined in my projectile-group struct. It would have been easier to just use a projectile-group array within the projectile struct but then the projectile would be limited to how many groups it was added to. I was actually thinking about implementing a similar technique to eliminate the size-limit to the amount of projectiles that can be included in a projectile-group.

Let me try to explain it in 2D-array syntax (which is how I was sketching it out on a notepad):

Let's say you have your "hashtable" or "2D array", let's call that "P". The amount of groups that the projectile is stored in will be referenced as "m". Now let's say you add a projectile to a group. I will be using "p" to reference the projectile that has been added, and "g" as the group it is being added to:

Code:
P[ p ][ m ] = g

Now you need to cross-reference this so that given "p" and "g" you can derive "m" (which is the second index; for this I will be using "R" as the secondary hashtable that cross references the index value.

Code:
R[ p ][ g ] = m

Now you've got two "arrays" set up:

Code:
P[ p ][ m ] = g
R[ p ][ g ] = m

Now notice:

Code:
P[ p ][ R[ p ][ g ] ] = g

See how we didn't actually need the value of "m" to reference it's index? Instead we were able to do it simply with the "p" and "g" values.

If you care for me to explain further, the removal process gets a little bit trickier.
 

Kenny

Back for now.
Reaction score
202
It is a pretty clever idea. I had a similar one (using hashtables as arrays) but I could not implement it correctly with how my projgroups worked. However I was able to make yours work, so if you don't mind, I would like to implement it into my next version. It is a lot better than looping through every existing projgroup and checking...

More on topic:

I am currently working on version 0.2.5 (Beta). It will feature:

  • An efficiency increase that allows my laptop to handle 25+ more projectiles than the previous versions with a similar FPS drops.
  • The removal of Vector as a required library.
  • Faster projectile grouping (via [ljass]this.enumNearby[/ljass]).
  • Better projgroup removal on termination (if xombie allows it). It is WAY better.
  • Collision triggers will no longer be disabled and destroyed if they are not active.
  • Removal of the linked list implementation from the projgroup struct.
  • Small scripting changes and polishing.
  • Updated documentation.

In my tests this system is now capable of handling approximately 200 non-homing, arcing projectiles with unit collision active (projectile and destructable collision not active) with an average FPS of around 21.

That is an increase of around 120 projectiles (with the same conditions) compared to the very first version of this system, which could only handle around 80 or so with an average FPS of 20-23.

I think that is pretty awesome! :D
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
Kenny, have you re-considered of using two dummies? one for projectile, one for projectile's "look at" ?

I think it will works well with recycling.

the performance would be reduced a little but I think it's worth using with recycle
 

Kenny

Back for now.
Reaction score
202
Honestly, I don't think that is something I want to do..

On paper, the efficiency decrease would be something like 40-50% and something tells me there will be troubles with that method as well.

I would rather easily handle 100 projectiles than moderately handle 50.

I am slowly making progress on 0.2.5 (Beta), some more changes include:

  • An efficiency increase that allows my laptop to handle 25+ more projectiles than the previous versions with a similar FPS drops.
  • Added ProjBounces as an optional module, allowing projectiles to bounce off terrain! Fun stuff.
  • Fixed ProjShadows so that shadows aren't displayed through fog of war.
  • Fixed an oversight on my behalf that lead to the unit leaves rect event firing every time a projectile was recycled.
  • Implemented xombie's fix for projectile removal (thanks xombie).
  • Renamed a fair few members for a more consistent interface.
  • The removal of Vector as a required library.
  • Faster projectile grouping (via [ljass]this.enumNearby[/ljass]).
  • Collision triggers will no longer be disabled and destroyed if they are not active.
  • Removal of the linked list implementation from the projgroup struct.
  • Small scripting changes and polishing.
  • Updated documentation.
  • More polishing off.

I am also thinking about turning the global projectile collision event into an optional 'module' (it wouldn't actually use vJASS modules). That would mean the removal of Event as a required library, so I'll see how that goes.

I think this is getting much closer to something I can consider a non-beta system. Not long to go now.
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
40-50% :eek:
here is a test map that has the "two dummies" method and Recycle ON.
can you test how many projectiles this can handle? :)
 

Attachments

  • [Test Map] Projectile.w3x
    294 KB · Views: 329
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top