HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Need help with a "Locust Swarm" like concept for a system !

10-30-2009, 11:42 PM#1
Komaqtion
Ok, so I'm trying to make a system which will work like the "Locust Swarm" ability, meaning that some creatures will come out of the caster, and "circulate" him within a specific range...
(By "circulate" I mean they will move around randomly until they spot an enemy etc... You know how I mean ;))

So, this is what I have atm:
Collapse JASS:
library EntityCol requires AutoIndex
    
    globals
        private constant integer MAX_ENTITIES = 20
    endglobals

    /*struct Entity
    
        unit Entity
        unit Owner
        
        static method create takes unit owner, integer amount, real x, real y, integer unitId returns Entity
            local Entity a = Entity.allocate()
            local player p = GetOwningPlayer( owner )
            
            
            set a.Owner = owner
            
            set a.Entity = CreateUnit( p, unitId, x, y, bj_UNIT_FACING )
            
            return a
        endmethod
        
    endstruct*/
    
    struct EntityCollection// extends Entity
    
        //group Entities = CreateGroup()
        unit array Entity [ MAX_ENTITIES ]
        unit Caster
        
        integer array ID [ MAX_ENTITIES ]
        
        static method create takes unit caster, integer number, integer unitId, real radius returns thistype
            local real x = GetUnitX( caster )
            local real y = GetUnitY( caster )
            local thistype this = thistype.allocate(/* caster, number, x, y, unitId */)
            local integer loops = 1
            local player p = GetOwningPlayer( caster )
            local real x2 = x + GetRandomReal( x - radius, x + radius )
            local real y2 = y + GetRandomReal( y - radius, y + radius )
            
            set this.Caster = caster
            
            loop
            exitwhen loops >= number
            
                set Entity[ ID[ loops ]] = CreateUnit( p, unitId, x, y, bj_UNIT_FACING )
                
                set ID[loops] = GetUnitId( caster )
                
                call IssuePointOrder( Entity[GetUnitId( caster )], "move", x2, y2 )
                //call GroupAddUnit( d.Entities, u )
                
            endloop
            
            return this
        endmethod
        
    endstruct

endlibrary

And as you can see, I had a struct for the "Entity Collection", meaning the whole group on entities (Locusts) a unit "owns", but also a struct for each entity...

I could not get this to work, because I thought i'd need to extend the EntityCollection struct, and I didn't know how that works :(

I haven't yet tested what I have now, but I'd believe it wouldn't work very well...

And also, as you can see by the unit arrays and integer arrays, I've tried to "link" the entities of a specific cast to their caster, but I'm very unsure if I've done it correctly :S

And, I think I still need to extend EntityCollection... (Or I at least want to have a stand-alone struct for each entity so you can change their flying height and many more features for them ;))

Anyone want to help me change it so it'll work as intended ? :S

(Note: I searched the forums TheHelper.net, WC3C.net and TheHiveWorkshop.com before I started working on this and I couldn't find anything like this anywhere :S If you know of a system like this, please let me know so I don't waste my time with this :D)

If you need more information, or you think I've been unclear on anything please let me know and I'll fix it :D
11-02-2009, 02:09 PM#2
Komaqtion
Ok, so I have rewritten this now, and it looks like this:
Collapse JASS:
library EntityCol requires TimerUtils
    
    globals
        private constant integer MAX_ENTITIES = 100     // Is what it says, the maximum amount of "entities" which will be attached to a single unit at any time !
        
        private constant real MOVE_INTERVAL = 0.03125   // Interval of the "entities" movement...
        private constant real DMG_INTERVAL = 1.0        // Interval of the entities damaging...
        
        private constant integer CROW_ID = 'Arav'       // "Storm Crow Form" ability's ID, for height-changing purposes... Shouldn't need changing :D
        private constant integer LOCUST_ID = 'Aloc'     // "Locust" ability's ID... Shouldn't need changing either ;)
    endglobals

    struct Entity
        real angle = 0.0        // Current angle of movement for the "entity"
        real currentX = 0.0     // Current X position of the "entity"
        real currentY = 0.0     // Current Y position of the "entity"
        real radius = 0.0       // The range from the caster 
        real casterX = 0.0
        real casterY = 0.0
    
        timer array t [ 2 ]

        unit u = null // The "entity" unit...
        unit c = null // The caster that all of the creatures will circulate around...

        static method create takes unit c, integer entityID, real height, real radius returns Entity
            local thistype this = thistype.allocate()
            local player p = GetOwningPlayer( c )

            set this.currentX = GetUnitX( c )
            set this.currentY = GetUnitY( c )
            set this.casterX = GetUnitX( c )
            set this.casterY = GetUnitY( c )
            set this.t[ 0 ] = NewTimer() // Some TimerUtils magic ! ;)
            set this.t[ 1 ] = NewTimer() // Some TimerUtils magic ! ;)
            set this.c = c          // The owner of this "entity" !
            set this.u = CreateUnit( p, entityID, currentX, currentY, bj_UNIT_FACING ) // Creating the "entity"
            set this.angle = GetRandomReal( 0.0, 360.0 )
            set this.radius = radius
            
            //call DisplayTextToPlayer( Player( 0 ), 0.0, 0.0, R2S( this.currentX ) )
            //call DisplayTextToPlayer( Player( 0 ), 0.0, 0.0, R2S( this.currentY ) )
            
            call UnitAddAbility( this.u, CROW_ID )
            call UnitRemoveAbility( this.u, CROW_ID )
            call SetUnitFlyHeight( this.u, height, 0.0 )
            call UnitAddAbility( this.u, LOCUST_ID )
            
            call SetTimerData( this.t[ 0 ], this ) // TimerUtils' magic again ! :D
            call TimerStart( this.t[ 0 ], MOVE_INTERVAL, true, function thistype.Move ) // Putting the TimerUtils' magic to use :P
            
            call SetTimerData( this.t[ 1 ], this ) // TimerUtils' magic again ! :D
            call TimerStart( this.t[ 1 ], DMG_INTERVAL, true, function thistype.Damage ) // Putting the TimerUtils' magic to use :P
            
            set p = null

            return this
        endmethod

        static method Move takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local thistype this = GetTimerData( t )
            local real x
            local real y
            local real distance
            
            set this.angle = GetRandomReal( this.angle - 30.0, this.angle + 30.0 )
            set this.casterX = GetUnitX( this.c )
            set this.casterY = GetUnitY( this.c )
            
            set x = currentX + 5.0 * Cos( this.angle * ( bj_PI / 180.0 ) )
            set y = currentY + 5.0 * Sin( this.angle * ( bj_PI / 180.0 ) )
            set distance = SquareRoot( ( ( casterX - x ) * ( casterX - x ) ) + ( ( casterY - y ) * ( casterY - y ) ) )
            
            //call DisplayTextToPlayer( Player( 0 ), 0.0, 0.0, R2S( distance ) )
            //call DisplayTextToPlayer( Player( 0 ), 0.0, 0.0, R2S( x ) )
            //call DisplayTextToPlayer( Player( 0 ), 0.0, 0.0, R2S( y ) )
            
            if distance > this.radius then
            
                loop
                    exitwhen distance < this.radius
                        set this.angle = this.angle - GetRandomReal( 0.0, 360.0 )
                        set this.casterX = GetUnitX( this.c )
                        set this.casterY = GetUnitY( this.c )
                        
                        set x = currentX + 5.0 * Cos( this.angle * ( bj_PI / 180.0 ) )
                        set y = currentY + 5.0 * Sin( this.angle * ( bj_PI / 180.0 ) )
                        set distance = SquareRoot( ( ( casterX - x ) * ( casterX - x ) ) + ( ( casterY - y ) * ( casterY - y ) ) )
                endloop
                
            endif
            
            call SetUnitX( this.u, x )
            call SetUnitY( this.u, y )
            
            set this.currentX = x
            set this.currentY = y
            
            set t = null
        endmethod
        
        static method Damage takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local thistype this = GetTimerData( t )
        endmethod

        method onDestroy takes nothing returns nothing
            //some cleaning here, for example killing the unit, destroying the timer...
        endmethod
        
    endstruct

    struct EntityCollection
        Entity array e [ MAX_ENTITIES ] // All "entities" are here...
        
        real duration = 0.
        
        static method create takes unit caster, integer amount, integer entityID, real entityHeight, real maxRadius, real duration returns thistype
            local thistype this = thistype.allocate()
            local integer i = 1
            
            loop
                exitwhen i == amount
                
                set this.e[ i ] = Entity.create( caster, entityID, entityHeight, maxRadius )
                
                set i = i + 1
            endloop
            
            //set this.duration = duration + MOVE_INTERVAL
            
            return this
        endmethod
        
    endstruct

endlibrary

And this actually works just fine, accept for a few flaws...
  1. As soon as I move the caster, just a little, it'll start lagging and freeze WC3
  2. There is no duration for it yet XD
  3. I think it's unecessary to use 2 timers for each "entity", is there some way to maybe use 2 timers per "EntityCollection" ?
  4. A lot of more stuff, which I'll have to deal wth after the above is done XD

Anyone have any idea of how to fix these problems ? :S
11-02-2009, 02:25 PM#3
Anachron
Collapse JASS:
           if distance > this.radius then 
                loop
                    exitwhen distance < this.radius
                        set this.angle = this.angle - GetRandomReal( 0.0, 360.0 )
                        set this.casterX = GetUnitX( this.c )
                        set this.casterY = GetUnitY( this.c )
                        
                        set x = currentX + 5.0 * Cos( this.angle * ( bj_PI / 180.0 ) )
                        set y = currentY + 5.0 * Sin( this.angle * ( bj_PI / 180.0 ) )
                        set distance = SquareRoot( ( ( casterX - x ) * ( casterX - x ) ) + ( ( casterY - y ) * ( casterY - y ) ) )
                endloop
                
            endif

Because of this, obviously.
11-02-2009, 02:34 PM#4
Komaqtion
Huh ?!

Is that an answer to a question ? :S
11-02-2009, 02:39 PM#5
Anachron
Quote:
1. As soon as I move the caster, just a little, it'll start lagging and freeze WC3
The loop is the reason

Quote:
2. There is no duration for it yet XD
...
Quote:
3. I think it's unecessary to use 2 timers for each "entity", is there some way to maybe use 2 timers per "EntityCollection" ?
Do static?

Quote:
4. A lot of more stuff, which I'll have to deal wth after the above is done XD
...
11-02-2009, 03:31 PM#6
Komaqtion
Quote:
The loop is the reason

Well, ok... Thanks for that info :P
Though it didn't really help, as I still don't know how to fix it XD

Quote:
Do static?

Huh ?!
11-02-2009, 03:33 PM#7
Anachron
Collapse JASS:
f distance > this.radius then 
                loop
                    exitwhen distance < this.radius
                        set this.angle = this.angle - GetRandomReal( 0.0, 360.0 )
                        set this.casterX = GetUnitX( this.c )
                        set this.casterY = GetUnitY( this.c )
                        
                        set x = currentX + 5.0 * Cos( this.angle * ( bj_PI / 180.0 ) )
                        set y = currentY + 5.0 * Sin( this.angle * ( bj_PI / 180.0 ) )
                        set distance = SquareRoot( ( ( casterX - x ) * ( casterX - x ) ) + ( ( casterY - y ) * ( casterY - y ) ) )
                endloop
                
            endif

This loop never finishes. Try to get information why.

Quote:
Huh?!
Well, you could save all instances into an array of thistype and create a static method that runs though all instances with a loop.
11-02-2009, 03:37 PM#8
Komaqtion
Quote:
This loop never finishes. Try to get information why.

Well, wouldn't that make it never work ? :S
Or, does it only "not-finish" when the caster move ?

Quote:
Well, you could save all instances into an array of thistype and create a static method that runs though all instances with a loop.

Using a global, or what ?
11-02-2009, 04:37 PM#9
Anachron
Quote:
Well, wouldn't that make it never work ? :S
Or, does it only "not-finish" when the caster move ?
It means that the exitwhen function will never be runned and the loop will be executed everytime. Really ugly.
Quote:
Using a global, or what ?
Static members in structs can be called with structname.membername, if they are public.
11-02-2009, 07:42 PM#10
Komaqtion
Quote:
It means that the exitwhen function will never be runned and the loop will be executed everytime. Really ugly.

Why not ?!
It is becoming true, as long as it doesn't move because the "entitys" will turn around when they come too far away...
Sorry, but please explain a bit more :D

Quote:
Static members in structs can be called with structname.membername, if they are public.

So normal members can't be accessed then ?
They need to be static ?
11-02-2009, 07:59 PM#11
Anachron
Quote:
Why not ?!
It is becoming true, as long as it doesn't move because the "entitys" will turn around when they come too far away...
Sorry, but please explain a bit more :D
If wc3 crashes because of your script, its 99% caused of an infinitive loop, that's the only reason I can see from the library.

Quote:
So normal members can't be accessed then ?
They need to be static ?
Ehrm? Static members are shared for each instance, meaning it will be the same value for every object.

I still don't get what you are trying to do.
11-02-2009, 08:21 PM#12
Komaqtion
You don't get what I'm trying to do with the whole script, or just with the "Single-Timer-Per-Group" stuff ? :S
11-02-2009, 08:26 PM#13
Anitarf
So, you're trying to do something like this?
11-03-2009, 06:33 AM#14
Komaqtion
No...

You don't know what "Locust Swarm" is ? :S

You create a few creatures, which hover around you, and when enemies appear, they'll start to attack, a little at a time ;)
11-03-2009, 08:23 AM#15
Anachron
Actually he does.

What I don't understand is:
What are you trying to do with this system?

How should it work?

What does(n't) work?