System Rain

Jesus4Lyf

Good Idea™
Reaction score
397
Rain.

They say, "when it rains, it pours". I've heard of rain in America and England recently, quite heavy rain, too, apparently. Today it rained here where I am. For those who don't know, we've had an epic drought for a long time, and well, it still hasn't broken. But I went for walk in the rain, and as I watched it gather in streams on the road and in the gutters, I smiled and thought to myself...

Rain.

:thup:

I took a couple of "screenshots" for you all, too. I know some of you won't even bother to try this out. :)
rain1.jpg
rain2.jpg
rain3.jpg
rain4.jpg

Code:
JASS:
library Rain initializer OnInit
    globals
        private constant real INITIAL_HEIGHT=1100.
        private constant real FALL_SPEED=20. // Divided by 32.
        private constant real RUN_SPEED=.4 // Divided by 32, dependant on smoothing, also.
        private constant real SMOOTHING=74.
        private constant integer LIFESPAN_TICKS=400 // Max raindrops, also.
        // ====
        private boolean Raining=true
        // ====
        private real MinX
        private real MaxX
        private real MinY
        private real MaxY
    endglobals
    public function Start takes nothing returns nothing
        set Raining=true
    endfunction
    public function Stop takes nothing returns nothing
        set Raining=false
    endfunction
    
    struct raindrop
        unit u
        real x=GetRandomReal(MinX,MaxX)
        real y=GetRandomReal(MinY,MaxY)
        real z=INITIAL_HEIGHT // also z for falling
        
        integer index // For the very end, removing from "Running"...
    endstruct
    
    private function RainHandler takes nothing returns nothing
        //====================================================
        // A different way to code...
        //====================================================
        globals//locals
            private integer i
            private raindrop Current
        endglobals
        
        //====================================================
        globals
            private raindrop array Remove
            private integer tick=0
            private integer later=LIFESPAN_TICKS
        endglobals
        
        // "later" must be always LIFESPAN_TICKS ahead of tick.
        set tick=tick+1
        if tick>8190 then
            set tick=1
        endif
        set later=later+1
        if later>8190 then
            set later=1
        endif
        
        //====================================================
        globals
            private raindrop array Running
            private integer RunningMax=0
        endglobals
        
        //====================================================
        globals
            private raindrop array Falling
            private integer FallingMax=0
        endglobals
        
        //====================================================
        // Timeout the old drops.
        //====================================================
        //  How to time out a vast number of objects with O(1)
        //  compelxity... <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" />
        set Current=Remove[tick]
        if Current!=0 then
            // When I first did this, this next line was missing.
            // Needless to say, if you understand the code, you
            // could guess it took me a little while to figure out.
            set Running[RunningMax].index=Current.index
            
            set Running[Current.index]=Running[RunningMax]
            set RunningMax=RunningMax-1
            
            call ShowUnit(Current.u,false)
            call UnitRemoveAbility(Current.u,&#039;Aloc&#039;)
            call Current.destroy()
            
            set Remove[tick]=0
        endif
        
        //====================================================
        // Creation.
        if Raining then
            // Create a raindrop.
            set FallingMax=FallingMax+1
            set Current=raindrop.create()
            set Falling[FallingMax]=Current
            
            set Remove[later]=Current // So very efficient...
            
            call ShowUnit(Current.u,true)
            call SetUnitPosition(Current.u,Current.x,Current.y)
            call UnitAddAbility(Current.u,&#039;Aloc&#039;)
            call SetUnitFlyHeight(Current.u,INITIAL_HEIGHT,0)
        endif
        
        //====================================================
        // Falling.
        set i=FallingMax
        loop
            exitwhen i==0
            set Current=Falling<i>
            set Current.z=Current.z-FALL_SPEED
            if Current.z&lt;0. then
                // ====
                set Falling<i>=Falling[FallingMax]
                set FallingMax=FallingMax-1
                
                call SetUnitFlyHeight(Current.u,0,0)
                
                set RunningMax=RunningMax+1
                set Running[RunningMax]=Current
                
                set Current.index=RunningMax // To remove from running.
                // ====
            else
                call SetUnitFlyHeight(Current.u,Current.z,0)
            endif
            
            set i=i-1
        endloop
        
        //====================================================
        // Running.
        globals
            private location l=Location(0,0)
            private real rainx // JassHelper error if renamed to x.
            private real rainy // JassHelper error if renamed to y.
            private real thisz
        endglobals
        
        set i=RunningMax
        loop
            exitwhen i==0
            set Current=Running<i>
            
            // Update velocities.
            set rainx=Current.x
            set rainy=Current.y
            call MoveLocation(l,rainx,rainy)
            set thisz=GetLocationZ(l)
            call MoveLocation(l,rainx+SMOOTHING,rainy)
            set Current.x=rainx+(thisz-GetLocationZ(l))*RUN_SPEED
            call MoveLocation(l,rainx,rainy+SMOOTHING)
            set Current.y=rainy+(thisz-GetLocationZ(l))*RUN_SPEED
            
            // Move raindrop.
            call SetUnitX(Current.u,Current.x)
            call SetUnitY(Current.u,Current.y)
            
            set i=i-1
        endloop
    endfunction
    
    private function OnInit takes nothing returns nothing
        local raindrop r=LIFESPAN_TICKS
        set MinX=GetCameraBoundMinX()
        set MaxX=GetCameraBoundMaxX()
        set MinY=GetCameraBoundMinY()
        set MaxY=GetCameraBoundMaxY()
        call TimerStart(CreateTimer(),0.03125,true,function RainHandler)
        loop
            exitwhen r==0
            set r.u=CreateUnit(Player(15),&#039;rain&#039;,MinY,MinX,0)
            call ShowUnit(r.u,false)
            set r=r-1
        endloop
    endfunction
endlibrary
</i></i></i>

In regards to real use... You probably want Bound Sentinel or a carefully created terrain, copy the dummy "Rain Drop" unit in the map as well as the code, and be warned that any terrain effects at runtime like shockwave and thunderclap will very likely desynch people.

Oh, and I enjoyed my walk very much. :)

PS.
If you think you have a good computer, see how high you can bump up "LIFESPAN_TICKS" and have the map run for at least a minute (if it can last that long, it should last forever probably). Tell us how high you got and what your fps was! (Use /fps in chat to find this out.) This can be some kinda test as to how well WC3 runs on your computer. And for anyone who previously thought moving 200 units around 32 times a second based on terrain was laggy... think twice, hey? :)

I've very tightly optimised this. =]
 

Attachments

  • Rain.w3x
    47.6 KB · Views: 555

wellwish3r

wishes wells.
Reaction score
52
wow now this is something original :thup:

i like, however i think it would only be useful in cinematics?
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
I adjusted to 500, fps drops to 45.

I think dummies can be recycled..

Original :
JASS:
set Current.u=CreateUnit(Player(15),&#039;rain&#039;,Current.x,Current.y,0)

JASS:
call RemoveUnit(Current.u)


Recycle :
JASS:
if Current.u == null then
    set Current.u=CreateUnit(Player(15),&#039;rain&#039;,Current.x,Current.y,0)
else
    call ShowUnit(Current.u,true)
    call SetUnitPosition(Current.u,Current.x,Current.y)
endif

JASS:
    call ShowUnit(Current.u,false)
 

Jesus4Lyf

Good Idea™
Reaction score
397
i like, however i think it would only be useful in cinematics?
Pretty much. But I couldn't like... leave it in my maps folder and go "well I reckon that was epic, but no one shall ever know of it". I'm sure someone may find some use for it, even if its only to sit in their room occasionally and stare at the drops running down the streams... :thup: XD

I think dummies can be recycled..
And this would benefit... what? (I don't believe this would bring an efficiency increase, but I DO know that it would leave a few hundred dummy units sitting in the background if the Rain_Stop and Rain_Start functions were used. ;))

Well. I've gotten the same amount of +rep for this and AIDS so far... o.o -.-

Edit: More posts before I posted! :O
I tried 2000, and it kinda died after 40seconds or so
2000 takes 62 seconds to reach and stabilise. Try 1000. Should even work on your computer.

By the way, at 200 my computer runs on about 25 fps... lol :p

I'd love to see a screenshot of 1000... <3
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
And this would benefit... what? (I don't believe this would bring an efficiency increase, but I DO know that it would leave a few hundred dummy units sitting in the background if the Rain_Stop and Rain_Start functions were used. )

In this case... You had to remove all dummies... T.T

Offtopic:)P) : Huh? Can the "pro" projectile system greatly reduce the length of code?

2000?!, Warcraft die after 35s with the value. FPS drops to 1.4 only. lol.

1000 raindrops :
rains.jpg
 

Jesus4Lyf

Good Idea™
Reaction score
397
Offtopic:)P) : Huh? Can the "pro" projectile system greatly reduce the length of code?
=/ You mean Gwypaas's? This probably wouldn't even run 200 with his.

Turns out it runs 400 smoothly on mine. There ya go. The screenies are only with 200. :)

Hmm. I could put recycling in. But I don't know that CreateUnit is really that much slower than ShowUnit and SetUnitPos. But I suppose it is probably worthwhile.

Disappointingly enough, the system's complexity seems to... unpredictably falter after a certain amount of time. Maybe recycling could fix this. Hmm. Unsure what that is. :)

>2000?!, Warcraft die after 35s with the value. FPS drops to 1.4 only. lol.
That means it only reached about 1100, and hasn't destroyed a single unit. :p
 
Reaction score
91
This is really awesome but I think it's a little laggy (from stable 64 fps to 57-61) but it's quite normal for such a big amount of moved units. I like it. :thup:
 

wellwish3r

wishes wells.
Reaction score
52
Well here is one at 1000 (ran perfectly fine):

Rain1.bmp

On a side note, i have to say that this was taken at all wc3 settings at mac with a resolution of 1920x1200, so if i went a little lower, i could maybe get to 2000 :p
 

wellwish3r

wishes wells.
Reaction score
52
Hawt.

I updated the code to preload all units, and then recycle them. It screwed with locust so I had to fix that too. :)

Runs epic smooth now. By the way, not sure that having more than 1000 units serves a point. Does it look any better to you changing from like... 600 to 1000? XD lol

to be honest, i saw now real different, except for maybe there bing more dummies running down the hills^^
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
200 works good for me. No fps drops. 200 is sufficient and optimum, but not for beginner class graphic cards..

The new version.... My fps increased by 5 compared with old version.
 

wellwish3r

wishes wells.
Reaction score
52
Well i think this is a lot more awesome xD

Rain2.bmp

Btw: I can't see the updated version attached anywhere?

EDIT: Lol no its there >.>
 

Jesus4Lyf

Good Idea™
Reaction score
397
How about simulate other weather effects, like snow?
When I walk outside one day and see snow falling and gathering on fresh ground, maybe I'll be inspired to do that. :thup:

But it doesn't snow here.

And I don't usually speak in full caps but OMG THAT LOOKS AWESOME LOL.

PS. It didn't attach for some reason, but I did re-attach it. :p lol

Feel free to post your map for that fire one just for kicks, if you like... XD :)

Edit: Actually, I might do snow one day. But really it's just a case of removing the "running" in this and changing the projectile to frostwyrm breath... o.o
 

wellwish3r

wishes wells.
Reaction score
52
you know i just had an idea, how about making the raindrops get continuously smaller as they run down the terrain? Sort of like what real streams do when running a hill. Just an idea tho^^

EDIT: One comment for the snow: Make the dummies smaller, right now it looks like friggn comets rain from the sky (and then probably spawn them more frequently, since you have a lot less dummies on the map compared to rain.)
EDIT: Snow usually doesn't fall down straight, it sort of moves about randomly (like a falling paper)
 
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