System Projectile

Troll-Brain

You can change this now in User CP.
Reaction score
85
Since creating/removing an unit is the highest operation possible in wc3, recycling projectiles would be good, so i suggest to use the SetUnitLookAt stuff.
 

Kenny

Back for now.
Reaction score
202
I've been testing out [ljass]SetUnitLookAt()[/ljass] with homing and arcing missiles, and to be honest it looks like crap.

I will attach a map so anyone can test it out. Basically either cast Hurl Boulder on a unit and then make the unit run away from the projectile, or get an archer to attack a unit and do the same.

If you know anything that might help, don't hesitate to comment.

Edit:

Kinda fixed the projectiles looking crap when they are homing. But I still can't fix arcing projectiles.
 

Attachments

  • Projectile [v1.0.1].w3x
    191.9 KB · Views: 302

BlackRose

Forum User
Reaction score
239
Yes. It does. That's all I can say. It does look crappy. You wanted comments right, lol? But I'm pretty sure anything I said you already thought. But I guess negative ressaurance =)

Talk on Facebook :nuts:
 

D.V.D

Make a wish
Reaction score
73
When I open the map, it shows me errors with the vector system. Here are the errors:

Undeclared variable loc
JASS:

        function s__vector_createTerrainPoint takes real x,real y returns integer
            local integer v= s__vector__allocate()
            call MoveLocation(s__vector_loc , x , y)
            set s__vector_x[v]=x
            set s__vector_y[v]=y
            set s__vector_z[v]=GetLocationZ(loc)//This one is causing the error
            return v
        endfunction

Undeclared variable loc
JASS:

        function s__vector_getTerrainPoint takes integer this,real x,real y returns nothing
            call MoveLocation(s__vector_loc , x , y)
            set s__vector_x[this]=x
            set s__vector_y[this]=y
            set s__vector_z[this]=GetLocationZ(loc)//This one is causing the error
        endfunction


Any help?
 

Nestharus

o-o
Reaction score
84
When I look at projectile systems, the main thing I worry about is how many projectiles it can handle without bogging down the map (causing lag).

That means 0 extra operations, including function calls (all done via macro).

It also means minimizing cluttering of global scope (the more it's cluttered, the longer it takes for JASS to find a variable or function).

I'm looking through the systems that it uses and I can already tell that it probably wouldn't be able to handle near the amount of projectiles I would like it to handle ; ).

I personally wouldn't use this ; P. I believe a good number for homing projectiles is around 650 or so on a mediocre computer with 0 lag.

Anyways, when i think of a map, I typically think of things like footmen wars, so around 200*12 units at a time each having around 4-5 projectiles at around 12000 possible projectiles on the map.

For this reason, I myself kind of stopped dreaming about trying to do a good projectile system on wc3 because it's not possible : ). Even simple projectiles won't reach those numbers. It's not even feasible to have 12k units + 2400 units on the map, lol. Really, I think we'll have to wait for Starcraft 2's built in projectile stuff to have any decent projectile system. Warcraft 3 just can't handle it : |, even if it's 100% optimum.


So while this looks interesting and appears to do a lot, it can't handle the projectile counts that I myself would prefer it to handle, and it's obviously impossible to apply this to any wartime map with a decent sized unit count on it.
 

Kenny

Back for now.
Reaction score
202
Dude... You are asking way to much of the wc3 engine. As mappers we just try to deal with the limitations we are given (or in some cases go beyond the limitations, although these are normally minor limitations).

I don't think I would ever want to play a map with 650 homing projectiles active at any give moment. That is just cluttering.

As stated in the documentation somewhere, this is meant for small maps (I think it is perfect for a 4v4 hero area with minimal creeps).

What you are after is just stupid. You probably should mod with the editor if you want so much out of it.

Edit:

@ D.V.D:

That is probably a JassHelper issue. Make sure you have have the latest version.

If it isn't a JassHelper issue, do the following:

1. Locate the vector library.

2. Find this part within the library:

JASS:
...
        static method createTerrainPoint takes real x, real y returns vector
            local vector v = vector.allocate()
            call MoveLocation(vector.loc,x,y)
            set v.x=x
            set v.y=y
            set v.z=GetLocationZ(loc)
            return v
        endmethod
        method getTerrainPoint takes real x, real y returns nothing
            call MoveLocation(vector.loc,x,y)
            set this.x=x
            set this.y=y
            set this.z=GetLocationZ(loc)
        endmethod
...


3. Replace those two methods with these two:

JASS:
...
        static method createTerrainPoint takes real x, real y returns vector
            local vector v = vector.allocate()
            call MoveLocation(vector.loc,x,y)
            set v.x=x
            set v.y=y
            set v.z=GetLocationZ(vector.loc)
            return v
        endmethod
        method getTerrainPoint takes real x, real y returns nothing
            call MoveLocation(vector.loc,x,y)
            set this.x=x
            set this.y=y
            set this.z=GetLocationZ(vector.loc)
        endmethod
...


4. Save the map and see how you go.
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
@Nestharus, yep, I agree with you: this system is no good for map with many units or map with less units but they shot projectiles like crazy (some kind of insane AS :nuts:)
BUT I won't ever play map like that. (and many people do)

@Kenny, it's perfect for small maps :D

p.s: if you find my comment stupid, please ignore it
 

Kenny

Back for now.
Reaction score
202
Your comment isn't stupid. If Nestharus said that he needed 150-250 projectiles and that my system wouldn't suffice. I would have agreed completely. However, what he is asking of the wc3 engine isn't possible. So it isn't really relevant.

Little bit of an update:

I have implemented [ljass]SetUnitLookAt()[/ljass] into my latest build for the upcoming update, however there is no way for it to work with arcing projectiles.

So that sucks...

Not sure what to do with the next update now.
 

Nestharus

o-o
Reaction score
84
Uhm.. I've done projectile systems with 650 with 0 lag kenny -.-... so it's possible, otherwise I wouldn't have thrown that number in there = ).

And I was on a pretty bleh laptop too ><. I think my desktop could probably get away with 1k.

And btw, 150-250, even 350 is really low for a projectile system... really low ><. For simple projectiles, I'd expect 900+ on my dinky laptop without lag.

Homing 650.

I haven't done any others so I don't know besides those 2 =P.
 

Viikuna

No Marlo no game.
Reaction score
265
Little bit of an update:

I have implemented [ljass]SetUnitLookAt()[/ljass] into my latest build for the upcoming update, however there is no way for it to work with arcing projectiles.

So that sucks...


?
 

Deaod

Member
Reaction score
6
JASS:
            local real tempX  = xPos - this.pos.x
            local real tempY  = yPos - this.pos.y
            local real tempZ  = zPos - this.pos.z
            
            set this.angle    = Atan2(tempY,tempX)
            set this.pitch    = Atan2(SquareRoot(tempX * tempX + tempY * tempY),tempZ)
            set this.speed    = speed * T32_PERIOD
            set this.vel      = vector.create(Sin(this.pitch) * Cos(this.angle) * this.speed,Sin(this.pitch) * Sin(this.angle) * this.speed,Cos(this.pitch) * this.speed)


do this instead:

JASS:
            local real tempX  = xPos - this.pos.x
            local real tempY  = yPos - this.pos.y
            local real tempZ  = zPos - this.pos.z
            local real tempDist = SquareRoot(tempX*tempX+tempY*tempY+tempZ*tempZ)
            
            set this.speed    = speed * T32_PERIOD
            set this.vel      = vector.create(tempX/tempDist * this.speed, tempY/tempDist * this.speed, tempZ/tempDist * this.speed)


You dont need angles when you have vectors.

I dont like the usage of T32. What if i have multiple libraries using T32 and i want to reduce the resource usage for one of those without affecting the other libraries depending on T32?
I dont like the usage of dynamic triggers. Use something else (GroupEnums, for example). Ill guarantee you its faster than what youre doing now.
 

Kenny

Back for now.
Reaction score
202
@ Nestharus:

I have to agree with Narks here: show me your projectile system that can handle 650+ projectiles and I might start taking what you say into consideration.

For now though, all you are doing is saying it is possible without providing evidence or even giving me hints on how to make mine more efficient, therefore what you are saying is irrelevant. Please, come back with proof and then I will gladly think about what you say.

And for small maps, I do not consider 100+ projectiles to be too low. Lets say I have a 4-6 player hero arena map. And lets say that each hero/player has around 6-8 projectiles at any one time, plus another 10 or so from creeps that may have been aggro'ed. That is still only around 66 projectiles max at any given time. And if that may seem too small, there is still room to bump it to 80 or so.

If you are playing a footman wars type map, you are already doing it wrong. Those games are lame, they have no strategy and would not really benefit from a system like this. I made this for small maps that want to incorporate strategy into their metagame, I believe I accomplished that.

@ Viikuna:

I believe what I said was pretty clear... So is there something your not telling me about [ljass]SetUnitLookAt()[/ljass]? Have you got it to work with arcing projectiles?

@ Deaod:

Thanks for your suggestion concerning vectors. I will definitely try that out when I have time. :)

As for T32: the system documentation itself (for T32 that is) clearly states the reasons why one would use the library, and the downsides of using it as well. I have tested my system with TimerUtils and there was a significant drop in performance. I believe T32 is the best option for this so far.

And I can guarantee that GroupEnums are not faster then dynamic triggers. If you read over my discussion thread in the Jass Help Section, you would realise that a bit of thought went into using dynamic triggers before they were implemented.

If I use GroupEnums for both unit and projectile collisions, it is only possible to handle around 30 or so units on my laptop. While the current method is able to handle over 100 projectiles.

I found that significant enough to keep dynamic triggers (I still wish there was a better way that didn't make the system impossible to implement).

Thanks for all the replies people. :)
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
the use of [ljass]SetUnitPosition[/ljass] right after [ljass]SetUnitLookAt[/ljass] only work with the model dummyRoll.mdx in the map Flight Sim
but something are still wrong with the ribbon of the special effect attached to the model :banghead: I don't know why :(
 

Nestharus

o-o
Reaction score
84
... you guys want proof eh?

Just wrote this using my old test code from a long time ago : )

JASS:
include &quot;cj_types.j&quot; 
//include &quot;cj_typesEx.j&quot; 
//include &quot;cj_types_priv.j&quot;  
//include &quot;cj_typesEx_priv.j&quot;
//include &quot;cj_order.j&quot;  
//include &quot;cj_antibj_base.j&quot;
include &quot;cj_print.j&quot;

library Particle uses T32 {}

//very quick homing demo

//ON_HIT_CODE_REF should refer to a boolexpr var
//PERIODICE_CODE refers to non-static code that goes into a method

//Periodic layout-
    //move/align projectile and update vars
    //PERIODIC_CODE (if special conditions fail, return false)
    //check for collision and run aoe etc
    
define &lt;Particle.Start&gt;(ON_HIT_CODE_REF, PERIODIC_CODE, DESTROY_CODE) = {
    scope PrivateParticle##COUNTER
    
    private module Particle {
        private static group particleGroup = CreateGroup()
        
        private unit projectile //projectile unit
        private real x //projectile x coord
        private real y //projectile y coord
        private real facing //projectile facing
        private real translationX
        private real translationY
        private real angle
        private real angleOffset
        
        private unit target //target unit
        private real targetX
        private real targetY

        public real speed //projectile speed
        public real turnRate //projectile turn rate
        public real duration //how long projectile lasts before poofing
        public real collision //projectile collision
        public real aoe //aoe, will hit more than one unit!
        
        #if ON_HIT_CODE_REF !=
            private static thistype triggerProjectile__S
            
            public static thistype operator triggerProjectile() {
                return thistype.triggerProjectile__S
            }
        #endif
        
        public bool periodic() {
            real targetX = GetUnitX(.target)
            real targetY = GetUnitY(.target)
            
            real distX = targetX - .x
            real distY = targetY - .y
            
            real facing

            //target moved or alignment necessary
            if (targetX != .targetX || targetY != .targetY || .angleOffset != 0) {
                .targetX = targetX
                .targetY = targetY
                
                .angle = 57.2958279*Atan2(distY, distX)
                
                if (.angle &lt; 0) {
                    .angle+=360
                }
                
                .angleOffset = .angle-.facing
                
                if (.angleOffset &lt; 0) {
                    if (.angleOffset &lt; -180) {
                        .angleOffset+=360
                        if (.turnRate &lt; 0) {.turnRate = -.turnRate}
                    }
                    else {
                        if (.turnRate &gt; 0) {.turnRate = -.turnRate}
                    }
                }
                elseif (.angleOffset &gt; 180) {
                    .angleOffset -= 360
                    if (turnRate &gt; 0) {.turnRate = -.turnRate}
                }
                else {
                    if (turnRate &lt; 0) {.turnRate = -.turnRate}
                }
                
                if (RAbsBJ(.angleOffset) &lt;= RAbsBJ(.turnRate)) {
                    .facing = .angle
                    .angleOffset = 0
                }
                else {
                    .facing+=.turnRate
                    .angleOffset-=.turnRate
                }
                if (.facing &gt; 360) {.facing -=360}
                elseif (.facing &lt; 0) {.facing += 360}
                SetUnitFacing(.projectile, .facing)
                
                facing = .facing*0.01745327
                .translationX = Cos(facing)*.speed
                .translationY = Sin(facing)*.speed
            }
            
            .x+=.translationX
            .y+=.translationY
            SetUnitX(.projectile, .x)
            SetUnitY(.projectile, .y)
            
            .duration-=T32_PERIOD
            
            if (distX &lt; 0) {distX = -distX}
            if (distY &lt; 0) {distY = -distY}
        
            PERIODIC_CODE
            
            if (distX &lt;= .collision &amp;&amp; distY &lt;= .collision) {
                UnitRemoveAbility(.projectile, &#039;Aloc&#039;)
                
                #if ON_HIT_CODE_REF !=
                    thistype.triggerProjectile__S = this
                    GroupEnumUnitsInRange(thistype.particleGroup, .x, .y, .aoe, ON_HIT_CODE_REF)
                #endif
                DESTROY_CODE
                
                thistype.mallocRelease[thistype.mallocReleaseCount++] = this
                
                return true
            }
            elseif (.duration &lt;= 0) {
                DESTROY_CODE
                
                thistype.mallocRelease[thistype.mallocReleaseCount++] = this
                return true
            }
            return false
        }
        
        implement T32
        
        private static int mallocCount = 0
        private static int mallocRelease[]
        private static int mallocReleaseCount = 0
        
        public static thistype create(unit projectile, unit target, real speed, real turnRate, real duration, real collision, real aoe) {
            thistype this
            if (thistype.mallocReleaseCount &gt; 0) {
                this = thistype.mallocRelease[--thistype.mallocReleaseCount]
            }
            else
            {
                this = ++thistype.mallocCount
            }
            
            .projectile = projectile
            .x = GetUnitX(projectile)
            .y = GetUnitY(projectile)
            .facing = GetUnitFacing(projectile)
            if (.facing &gt; 360) {.facing -=360}
            elseif (.facing &lt; 0) {.facing +=360}
            
            .target = target
            .targetX = GetUnitX(target)-5000 //make sure not equal
            
            .speed = speed * T32_PERIOD
            .turnRate = turnRate * T32_PERIOD
            .duration = duration
            .collision = collision
            .aoe = aoe
            
            UnitAddAbility(.projectile, &#039;Aloc&#039;)
            UnitAddAbility(.projectile, &#039;Avul&#039;)
            
            .startPeriodic()
            
            return this
        }
    }
}

define &lt;Particle.End&gt; = endscope


And here is the demo

JASS:
library Tester initializer Ini uses Particle {
    private int count = 650
    private int iterator
    private unit target
    
    Particle.Start(,,PeasantShooter.OnDestroy)
        define private &lt;PeasantShooter.OnDestroy&gt; = {
            //KillUnit(.projectile)
            RemoveUnit(.projectile)
            .projectile = null
        }
        
        define private &lt;PeasantShooter.OnPeriodic&gt; = {
        }
            
        struct PeasantShooter extends array {
            private static boolexpr onHit

            implement Particle
        }
    Particle.End
    
    private void Ini() {
        target = CreateUnit(Player(0), &#039;hfoo&#039;, -4500, 0, 0)
        trigger spawnStuff = CreateTrigger()
        
        //call CreateProjectile(Player(0), &#039;ewsp&#039;, -2000, -2000, 11., projectileTarget, 300, 9000, 180, 500., 70., null)
        
        TriggerAddCondition(spawnStuff, Condition(lambda bool() {
            iterator = 60
            do {PeasantShooter.create(CreateUnit(Player(0), &#039;ewsp&#039;, -2000, -2000, 11), target, 10, 80, 9000, 30, 31)}
                whilenot (--count == 0 || --iterator == 0)
            
            if (count == 0) {return true}
            return false
        }))
        
        whilenot (TriggerEvaluate(spawnStuff)) {}
    }
}



650 homing projectiles without lag -.-, at least on my dinky laptop ; ). It can probably go up to 1k on my desktop : D.

There you go, there's your proof -.-. Obviously it'll lag while they're changing direction, but it converts complex projectiles into simple projectiles as quickly as possible if you look through the code ^_^.

I think while changing direction, it can handle like 450 =), but as soon as they have direction set it jumps to 650 ^^.


Also as you see, recycling and etc is totally up to the user =).


Now as I've said in the past, I'll make a spiffy projectile system, but only once I finish Spawn >.<. I want to do something really really crazy and I need Spawn for it. The latest I was getting into with Spawn was eye candy stuff, developing algorithms to make pretty shapes. Particle will obviously be about moving the particles that make up those shapes along paths to make other shapes or w/e ^_^.

An example could be like... spawns all spawning in the same little dot and then the particle portion moving them around to form a square or something that bounces. Another one would be possibly 2 vertical lines that begin to spiral about and pulsate or something : P. My goal is making this annoying stuff as easy as possible so I can focus on these awesome effects ^_^.
 

Kenny

Back for now.
Reaction score
202
I would really like to see a demo map for that.

Also: are you sure your projectile on projectile collision works properly like that? From my tests, just removing [ljass]'Aloc'[/ljass] from a unit doesn't mean it will be detected by GroupEnums.

And that doesn't adjust positioning for terrain changes or arcing projectiles (I do realise it is only an example).

I do like the math work you did for homing projectiles though. I saw something similar in xe collider but had no idea how to replicate it.
 

Nestharus

o-o
Reaction score
84
Also: are you sure your projectile on projectile collision works properly like that? From my tests, just removing 'Aloc' from a unit doesn't mean it will be detected by GroupEnums.

the purpose of removing 'Aloc' is because the system is no longer using the unit, that is it...

I shoulda removed invulnerable too...

The GroupEnum has nothing to do with it... it's actually good that it doesn't get picked up on the enumeration ><.

>And that doesn't adjust positioning for terrain changes or arcing projectiles (I do realise it is only an example).
I don't believe in 3D projectiles unless you have 3D terrain, = ).


>I would really like to see a demo map for that.
Get latest cJASS and cnp into map : P. Lol


Anyways... the fact is that what i wrote is still garbage... it needs to be reformatted using different concepts, like allowing for positional and movement algorithms as well as groups of projectiles :\. Yea, what I wrote will get the job done, but it doesn't do what I personally need it to do = ).

Oh yea, did you notice this?

JASS:
private void Ini() {
        //.........

        //this line here
        TriggerAddCondition(spawnStuff, Condition(lambda bool() {
            iterator = 60
            do {PeasantShooter.create(CreateUnit(Player(0), &#039;ewsp&#039;, -2000, -2000, 11), target, 10, 80, 9000, 30, 31)}
                whilenot (--count == 0 || --iterator == 0)
            
            if (count == 0) {return true}
            return false
        }))
        //......
}



That feature made me insta use cJASS permanently : ), but I think it should be ~ instead of lambda ; ).
 

Kenny

Back for now.
Reaction score
202
Nestharus, I can't download the cJass installer. There seems to be a problem.

Mind uploading a test map for me?

Also, I believe that if you added proper projectile collision, terrain change detection, arcing projectiles and the other features mine has, you would see the limit to the system decrease quite a bit (keep in mind I am trying to keep an intuitive interface for the system).
 

Nestharus

o-o
Reaction score
84
Well.. that was homing projectiles, but proper projectile collision would still be very easy unless you wanted to collide with other projectiles as well :eek:... in which case you'd probably need a BST because of locust : P.

Projectile collisions between other projectiles would probably be a good thing, but it also needs to maintain modularity, meaning it'd end up looking more and more like the latest design of Spawn, lol, which it is already starting to look like a little bit : P.


and here's a quick demo using 650 projectiles
http://www.filefront.com/15833723/ProjectileSystem~1.w3x

Keep in mind that computers vary in power, so that might lag you a little to a lot (that was edge on my laptop), or it might be absolutely 0 lag. Depends on where you computer lies in relation to my laptop ; P. All I know is 650 to 651 went from no lag to hardcore lag ;D.

That's made in a map that Sevion had sent me a long time ago when he pleaded me to make him a good projectile system for a friend of his : P
 

Kenny

Back for now.
Reaction score
202
Lol... I tested the map.

I got about 0.1 FPS for 5 seconds, then it paused for 30 seconds, then crashed warcraft.

Seems that your laptop is way better then mine.

It also probably means that my system could handle around 450+ projectiles on your laptop.

I really want to download cJass so I can test the limits of my laptop with your system. Do you know of a download mirror I could use or something?
 
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