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.
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;Aloc039;)
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;Aloc039;)
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<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;rain039;,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. =]