Value controlled rain code: Difference between revisions
Mblackwell (talk | contribs) mNo edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
This shows how | This shows how to create a nice rain effect, allowing you to [[spawn]] and retain a certain amount of rain within a map. This works by creating both rain and a [[spawn]]er for the rain. The "rain [[spawn]]er" can then be given a [[hitag]] by the mapper, equal to the amount of rain they want to [[spawn]]. The rain itself [[spawn]]s in a limited area, but "spreads out", allowing you to easily modify overall density. | ||
First we will create the rain [[actor]] itself: | First we will create the rain [[actor]] itself: | ||
The following [[gamevar]]s will be needed during the course of this code: | |||
<pre> | <pre> | ||
gamevar TEMP 0 2 | gamevar TEMP 0 2 | ||
Line 14: | Line 14: | ||
</pre> | </pre> | ||
A couple of [[actor]] tile definitions are also required. Change these appropriately: | |||
<pre> | <pre> | ||
define RAIN1 3890 | define RAIN1 3890 | ||
Line 20: | Line 20: | ||
</pre> | </pre> | ||
Here | Here are our relevant [[move]] commands (remember, positive vertical values mean downward motion): | ||
<pre> | <pre> | ||
move RAINDOWN 0 800 | move RAINDOWN 0 800 | ||
Line 39: | Line 39: | ||
ifaction 0 | ifaction 0 | ||
{ | { | ||
cstat 32768 | |||
action INIT | |||
getactor[THISACTOR].x ORIGRAINPOSX | |||
getactor[THISACTOR].y ORIGRAINPOSY | |||
} | } | ||
</pre> | </pre> | ||
You | You may have noticed we used "ifaction 0." This allows us to do things on what is basically actor intialization without wasting an action. Note that we saved the original x/y coordinates of the actor. | ||
<pre> | <pre> | ||
sizeat 10 40 | sizeat 10 40 | ||
</pre> | </pre> | ||
This sets the size of the sprite. In this case I wanted it taller than it is wide. Adjust accordingly. | This sets the size of the sprite. In this case, I wanted it to be taller than it is wide. Adjust accordingly. | ||
<pre> | <pre> | ||
ifaction INIT | else ifaction INIT | ||
{ | { | ||
cstat 32768 | |||
ifoutside | |||
nullop | |||
else | |||
{ | |||
setactor[THISACTOR].x ORIGRAINPOSX | |||
setactor[THISACTOR].y ORIGRAINPOSY | |||
} | |||
move RAINSKY geth randomangle | |||
ifrnd 96 | |||
action RAINDROP | |||
} | } | ||
else ifaction RAINDROP | else ifaction RAINDROP | ||
{ | { | ||
ifoutside | |||
nullop | |||
else | |||
{ | |||
setactor[THISACTOR].x ORIGRAINPOSX | |||
setactor[THISACTOR].y ORIGRAINPOSY | |||
} | |||
</pre> | |||
If the rain sprite goes indoors, it resets its position. | |||
<pre> | <pre> | ||
cstat 2 | |||
move 0 fall | |||
</pre> | </pre> | ||
Setting the sprite's cstat to 2 causes the sprite to be rendered with translucency level 1, "move 0" tells the actor not to execute any movement and "fall" simply tells the actor to move downward vertically until hitting the ground. | |||
<pre> | <pre> | ||
move RAINDOWN getv | |||
iffloordistl 4 | |||
{ | |||
sizeat 20 20 | |||
action RAINSPLASH | |||
move 0 fall | |||
} | |||
} | } | ||
else ifaction RAINSPLASH | else ifaction RAINSPLASH | ||
{ | { | ||
sizeat 20 20 | sizeat 20 20 | ||
</pre> | </pre> | ||
The sizeat command alters the size of the sprite. We're changing our sprite's size to account for it now being a "splash." | |||
<pre> | <pre> | ||
cstat 2 | |||
ifactioncount 5 | |||
{ | |||
cstat 32768 | |||
ifonwater | |||
spawn RAINRIPPLE | |||
getsector[THISACTOR].ceilingz TEMP | |||
setactor[THISACTOR].z TEMP | |||
action INIT | |||
} | |||
} | } | ||
enda | enda | ||
</pre> | </pre> | ||
The rain sprite is set up to spawn a ripple when it hits the water. Here's some quick code for that: | |||
<pre> | <pre> | ||
action RIPPLING 0 9 1 1 4 | action RIPPLING 0 9 1 1 4 | ||
useractor notenemy RAINRIPPLE 0 | useractor notenemy RAINRIPPLE 0 | ||
{ | { | ||
ifaction 0 | |||
{ | |||
sizeat 20 20 | |||
cstat 34 | |||
action RIPPLING | |||
move 0 fall | |||
} | |||
ifactioncount 9 | |||
killit | |||
iffloordistl 4 nullop | |||
else killit | |||
} | } | ||
enda | enda | ||
</pre> | </pre> | ||
Now comes the part where we make the rain spawner. First we | Now comes the part where we make the rain spawner. First, we make a quick state to handle where the rain spawns: | ||
<pre> | <pre> | ||
state spawnrain | state spawnrain | ||
{ | { | ||
cstat 32768 | |||
ifvarvare MHITAG COUNT | |||
{ | |||
setvar COUNT 0 | |||
killit | |||
} | |||
{ | else | ||
{ | |||
addvar COUNT 1 | |||
addvar | espawn RAIN1 | ||
getactor[THISACTOR].pal TEMP | |||
setactor[RETURN].pal TEMP | |||
getactor[ | |||
setactor[RETURN]. | |||
ifrnd 64 | ifrnd 64 | ||
{ | { | ||
getactor[RETURN]. | getactor[RETURN].x TEMP | ||
randvar RAND_DIST 2048 | randvar RAND_DIST 2048 | ||
addvar RAND_DIST 2048 | addvar RAND_DIST 2048 | ||
addvarvar TEMP RAND_DIST | addvarvar TEMP RAND_DIST | ||
setactor[RETURN]. | setactor[RETURN].x TEMP | ||
} | } | ||
ifrnd 64 | ifrnd 64 | ||
{ | { | ||
getactor[RETURN]. | getactor[RETURN].x TEMP | ||
randvar RAND_DIST -2048 | randvar RAND_DIST -2048 | ||
subvar RAND_DIST 2048 | subvar RAND_DIST 2048 | ||
addvarvar TEMP RAND_DIST | addvarvar TEMP RAND_DIST | ||
setactor[RETURN]. | setactor[RETURN].x TEMP | ||
} | } | ||
ifrnd 64 | |||
{ | |||
getactor[RETURN].y TEMP | |||
randvar RAND_DIST 2048 | |||
addvar RAND_DIST 2048 | |||
addvarvar TEMP RAND_DIST | |||
setactor[RETURN].y TEMP | |||
} | |||
ifrnd 64 | |||
{ | |||
getactor[RETURN].y TEMP | |||
randvar RAND_DIST -2048 | |||
subvar RAND_DIST 2048 | |||
addvarvar TEMP RAND_DIST | |||
setactor[RETURN].y TEMP | |||
} | |||
} | |||
} | } | ||
ends | ends | ||
</pre> | </pre> | ||
And the actor itself: | And the actor itself: | ||
Line 175: | Line 193: | ||
action NORSPAWN 0 1 1 1 1 | action NORSPAWN 0 1 1 1 1 | ||
useractor notenemy RSPAWN 0 RNOT 0 | useractor notenemy RSPAWN 0 RNOT 0 | ||
{ | { | ||
ifaction 0 | |||
{ | |||
getactor[THISACTOR].hitag MHITAG | |||
setvar TEMP 0 | |||
setactor[THISACTOR].hitag TEMP | |||
action NORSPAWN | |||
} | |||
state spawnrain | |||
} | } | ||
enda | enda | ||
</pre> | </pre> | ||
The advantages of this method are quite obvious | The advantages of this method are quite obvious in that it lowers the amount of potential actors that will be in the map (the only time it would increase beyond what you defined is if the rain hits water, which should have a negligible effect) and makes it quite easy to edit the rain in a map. Also, rain is prevented from going indoors, except at the edges, limiting potential bugs, while providing a realistic effect. | ||
Try it yourself. | Try it yourself. |
Revision as of 16:05, 1 March 2005
This shows how to create a nice rain effect, allowing you to spawn and retain a certain amount of rain within a map. This works by creating both rain and a spawner for the rain. The "rain spawner" can then be given a hitag by the mapper, equal to the amount of rain they want to spawn. The rain itself spawns in a limited area, but "spreads out", allowing you to easily modify overall density.
First we will create the rain actor itself:
The following gamevars will be needed during the course of this code:
gamevar TEMP 0 2 gamevar RAND_DIST 0 2 gamevar COUNTER 0 2 gamevar MHITAG 0 2 gamevar ORIGRAINPOSX 0 2 gamevar ORIGRAINPOSY 0 2
A couple of actor tile definitions are also required. Change these appropriately:
define RAIN1 3890 define RAINRIPPLE 3880
Here are our relevant move commands (remember, positive vertical values mean downward motion):
move RAINDOWN 0 800 move RAINSKY 800 0
And here are our actions, including a 5 frame splash:
action INIT 0 1 1 1 1 action RAINDROP 0 1 1 1 1 action RAINSPLASH 1 5 1 1 5
And now on to the actual actor code:
useractor notenemy RAIN1 0 ifaction 0 { cstat 32768 action INIT getactor[THISACTOR].x ORIGRAINPOSX getactor[THISACTOR].y ORIGRAINPOSY }
You may have noticed we used "ifaction 0." This allows us to do things on what is basically actor intialization without wasting an action. Note that we saved the original x/y coordinates of the actor.
sizeat 10 40
This sets the size of the sprite. In this case, I wanted it to be taller than it is wide. Adjust accordingly.
else ifaction INIT { cstat 32768 ifoutside nullop else { setactor[THISACTOR].x ORIGRAINPOSX setactor[THISACTOR].y ORIGRAINPOSY } move RAINSKY geth randomangle ifrnd 96 action RAINDROP } else ifaction RAINDROP { ifoutside nullop else { setactor[THISACTOR].x ORIGRAINPOSX setactor[THISACTOR].y ORIGRAINPOSY }
If the rain sprite goes indoors, it resets its position.
cstat 2 move 0 fall
Setting the sprite's cstat to 2 causes the sprite to be rendered with translucency level 1, "move 0" tells the actor not to execute any movement and "fall" simply tells the actor to move downward vertically until hitting the ground.
move RAINDOWN getv iffloordistl 4 { sizeat 20 20 action RAINSPLASH move 0 fall } } else ifaction RAINSPLASH { sizeat 20 20
The sizeat command alters the size of the sprite. We're changing our sprite's size to account for it now being a "splash."
cstat 2 ifactioncount 5 { cstat 32768 ifonwater spawn RAINRIPPLE getsector[THISACTOR].ceilingz TEMP setactor[THISACTOR].z TEMP action INIT } } enda
The rain sprite is set up to spawn a ripple when it hits the water. Here's some quick code for that:
action RIPPLING 0 9 1 1 4 useractor notenemy RAINRIPPLE 0 { ifaction 0 { sizeat 20 20 cstat 34 action RIPPLING move 0 fall } ifactioncount 9 killit iffloordistl 4 nullop else killit } enda
Now comes the part where we make the rain spawner. First, we make a quick state to handle where the rain spawns:
state spawnrain { cstat 32768 ifvarvare MHITAG COUNT { setvar COUNT 0 killit } else { addvar COUNT 1 espawn RAIN1 getactor[THISACTOR].pal TEMP setactor[RETURN].pal TEMP ifrnd 64 { getactor[RETURN].x TEMP randvar RAND_DIST 2048 addvar RAND_DIST 2048 addvarvar TEMP RAND_DIST setactor[RETURN].x TEMP } ifrnd 64 { getactor[RETURN].x TEMP randvar RAND_DIST -2048 subvar RAND_DIST 2048 addvarvar TEMP RAND_DIST setactor[RETURN].x TEMP } ifrnd 64 { getactor[RETURN].y TEMP randvar RAND_DIST 2048 addvar RAND_DIST 2048 addvarvar TEMP RAND_DIST setactor[RETURN].y TEMP } ifrnd 64 { getactor[RETURN].y TEMP randvar RAND_DIST -2048 subvar RAND_DIST 2048 addvarvar TEMP RAND_DIST setactor[RETURN].y TEMP } } } ends
And the actor itself:
action NORSPAWN 0 1 1 1 1 useractor notenemy RSPAWN 0 RNOT 0 { ifaction 0 { getactor[THISACTOR].hitag MHITAG setvar TEMP 0 setactor[THISACTOR].hitag TEMP action NORSPAWN } state spawnrain } enda
The advantages of this method are quite obvious in that it lowers the amount of potential actors that will be in the map (the only time it would increase beyond what you defined is if the rain hits water, which should have a negligible effect) and makes it quite easy to edit the rain in a map. Also, rain is prevented from going indoors, except at the edges, limiting potential bugs, while providing a realistic effect.
Try it yourself.