This tutorial will attempt to explain how to create a rain effect, using multiple vents inside of a VentGroup and onDeath execution for vents. If you have any questions at the end, feel free to ask in a comment.
Things you’ll need before doing this tutorial:
- A glow texture (I used “glow-1.png” from CBTextures)
- A cloud texture (I used “cloud-1.png” from CBTextures)
- A copy of CBEffects, put into your root folder and require()-ed at the top of your code
- Basic knowledge of using CBEffects
- The following configuration values for your project:
FPS - 60
Screen Width - 768
Screen Height - 1024
Orientation - Landscape (either direction)
To begin with, you’ll need to create a VentGroup. We’ll start with a single vent - the rain - to make things easier.
[lua]
local heavy_rain=CBE.VentGroup{
{
preset=“rain”,
title=“rain”, – Make sure you title your vents!
build=function()
return display.newImageRect(“glow-1.png”, 10, 80)
end
}
}
heavy_rain:start(“rain”)
[/lua]
Reload the Corona simulator, and there you have it. Some rain! Because of the nature of the “rain” preset, there is a bit of motion variation - you should notice some particles going a bit farther to the left or right than others. We don’t want that. It’s easily set, using the “angles” parameter in the physics table.
[lua]
physics={
autoAngle=false,
angles={260}
}
[/lua]
Now you can stick that bit into your main vent parameters to get this:
[lua]
local heavy_rain=CBE.VentGroup{
{
preset=“rain”,
title=“rain”, – Title all vents, every time!
build=function()
return display.newImageRect(“glow-1.png”, 10, 80)
end,
physics={
autoAngle=false,
angles={260}
}
}
}
[/lua]
Note the “autoAngle” parameter. If you set that to false, the angles in the angle table are single values (like our angle - 260). Otherwise, CBEffects automatically creates an angle range. You can use that to get things like the angles from 0-180, for example, which would be a pain to write out manually.
If you reload the simulator at this time, you’ll notice that now all the raindrops are falling in a uniform direction. Double the amount of them with this:
[lua]
perEmit=2
[/lua]
Now we have a uniform rainfall, but it stops at that. You could make do with that (if you’re doing something like “rain through a window” for your app), but why not enhance it some more? What we’ll do is add a “plink” effect at the end of each raindrop.
Firstly, you’ll never see the plink effect if you can’t see the particles get removed. So let’s set the life delay to a bit higher, and the life span to a bit lower, so that particles die right at the edge of the screen. Playing around a bit with the numbers, I got 1000 and 100.
[lua]
lifeStart=1000,
lifeSpan=100
[/lua]
Add that into your vent parameters somewhere, reload, and you’ll see particles die near the bottom edge of the screen. We want a bit of dying position variation, so make them appear in a randomized location from the top. That way, particles have the same life span (there’s an issue with using variated life spans that I’m currently looking into), but some are in a different position, so they die above others. For that, we’ll need to set the position type, and some positioning parameters.
[lua]
positionType=“inRect” – Particles will appear inside a rectangle
rectLeft=50, – A little over to accommodate the movement angle
rectTop=-150,
rectWidth=1024,
rectHeight=150
[/lua]
Now particles will appear inside a 1024x150 px rectangle that’s above the screen. You’ll have a 150 px variation for the dying position for each particle, if you reload and check.
They’re still a little slow, though. So a simple speeding up (doubling the velocity and halving the life span and life start delay) should do it.
[lua]
{
preset=“rain”,
title=“rain”,
positionType=“inRect”,
rectLeft=50,
rectTop=-150,
rectWidth=1024,
rectHeight=150,
perEmit=2,
build=function()
return display.newImageRect(“glow-1.png”, 10, 80)
end,
lifeStart=500,
lifeSpan=50,
physics={
autoAngle=false,
angles={260},
velocity=20 – Rain preset velocity is 10
}
}
[/lua]
To catch up, here should be your complete code so far:
[lua]
local CBE=require(“CBEffects.Library”)
local heavy_rain=CBE.VentGroup{
{
preset=“rain”,
title=“rain”,
positionType=“inRect”,
rectLeft=50,
rectTop=-150,
rectWidth=1024,
rectHeight=150,
perEmit=2,
build=function()
return display.newImageRect(“glow-1.png”, 10, 80)
end,
lifeStart=500,
lifeSpan=50,
physics={
autoAngle=false,
angles={260},
velocity=20
}
}
}
heavy_rain:start(“rain”)
[/lua]
Now we’ve got our rainfall, so let’s add the plink part. Easily done with another vent. When you’ve gotten familiar with CBEffects (as I, the author, have!), it’s easier to find what preset to use. For this, we’ll use the “rain” preset (not necessarily the best one, but good enough for this tutorial). We’ll call this vent “plink”.
[lua]
local heavy_rain=CBE.VentGroup{
{
preset=“rain”,
title=“plink”
},
{rain} – I’ve collapsed the rain vent for ease of viewing
}
[/lua]
We want the plink to occur at the end of each raindrop, so we’ll go into the rain vent parameters and add a trigger for it.
[lua]
onDeath=function(particle, vent)
heavy_rain:translate(“plink”, particle.x, particle.y) – The “translate” command moves a vent to a specific X,Y position
heavy_rain:emit(“plink”)
end
[/lua]
Notice how now we have some code that says, “when a particle dies, move the plink effect to its position and emit a plink”. Pretty cool. However, if you reload the simulator, you’ll get the message “attempt to index global ‘heavy_rain’”. That can be remedied by pre-declaring the storm vent group at the top of your code:
[lua]
local heavy_rain
heavy_rain=CBE.VentGroup{…}
[/lua]
Now reload it, and you’ll get rain that triggers more rain when it dies. Not very impressive.
That means we’ll have to edit the plink to stop being rain and start being a plink. Playing around with the parameters, I got this for the plink effect:
[lua]
preset=“rain”,
title=“plink”,
positionType=“atPoint”, – Appear directly at the vent’s X,Y position
build=function()
return display.newImageRect(“glow-1.png”, 10, 10)
end,
alpha=0.3, – Remain at constant alpha
startAlpha=0.3,
endAlpha=0.3,
lifeStart=0, – No delay before life span
fadeInTime=0, – No fade in time
lifeSpan=100,
physics={
sizeX=1.5,
velocity=0 – Don’t move
}
[/lua]
Use that as the plink vent parameters, reload, and you should have a nice little “plink” at the end of each raindrop.
Catch up with the code:
[lua]
local CBE=require(“CBEffects.Library”)
local heavy_rain
heavy_rain=CBE.VentGroup{
{
preset=“rain”,
title=“plink”,
positionType=“atPoint”,
build=function()
return display.newImageRect(“glow-1.png”, 10, 10)
end,
alpha=0.3,
startAlpha=0.3,
endAlpha=0.3,
lifeStart=0,
fadeInTime=0,
lifeSpan=100,
physics={
sizeX=1.5,
velocity=0
}
},
{
preset=“rain”,
title=“rain”,
positionType=“inRect”,
rectLeft=50,
rectTop=-150,
rectWidth=1024,
rectHeight=150,
perEmit=2,
build=function()
return display.newImageRect(“glow-1.png”, 10, 80)
end,
onDeath=function(particle, vent)
heavy_rain:translate(“plink”, particle.x, particle.y)
heavy_rain:emit(“plink”)
end,
lifeStart=500,
lifeSpan=50,
physics={
autoAngle=false,
angles={260},
velocity=20
}
}
}
heavy_rain:start(“rain”)
[/lua]
Now we have a beautiful rainfall, but if you really want heavy rain, it needs clouds.
Make a new vent and title it “clouds”. We’ll use the “fluid” preset for it. Here’s the cloud configuration I came up with:
[lua]
{
preset=“fluid”,
title=“clouds”,
color={
{70}, – Dark grays
{60},
{50}
},
positionType=“inRect”,
rectLeft=0,
rectTop=0,
rectWidth=1024,
rectHeight=60, – Create a blanket of clouds at the top of the screen
fadeInTime=500, – Low fade in time and life span
lifeSpan=500,
lifeStart=1000, – High life start delay
build=function()
local size=math.random(480, 512) – Particles are quite large
return display.newImageRect(“cloud-1.png”, size, size)
end,
propertyTable={
blendMode=“normal” – Normal fluid preset uses additive blending via the property table
},
physics={
velocity=1.1, – Some minor velocity in left-right direction
autoAngle=false,
angles={180, 0}
}
}
[/lua]
Now, at the bottom, where you start the rain vent, add in a “clouds” argument:
[lua]
heavy_rain:start(“rain”, “clouds”)
[/lua]
That starts both the rain and the clouds.
Reload and you’ll have a thick bank of dark gray clouds up at the top.
Full code:
[lua]
local CBE=require(“CBEffects.Library”)
local heavy_rain
heavy_rain=CBE.VentGroup{
{
preset=“rain”,
title=“plink”,
positionType=“atPoint”,
build=function()
return display.newImageRect(“glow-1.png”, 10, 10)
end,
alpha=0.3,
startAlpha=0.3,
endAlpha=0.3,
lifeStart=0,
fadeInTime=0,
lifeSpan=100,
physics={
sizeX=1.5,
velocity=0
}
},
{
preset=“rain”,
title=“rain”,
positionType=“inRect”,
rectLeft=50,
rectTop=-150,
rectWidth=1024,
rectHeight=150,
perEmit=2,
build=function()
return display.newImageRect(“glow-1.png”, 10, 80)
end,
onDeath=function(particle, vent)
heavy_rain:translate(“plink”, particle.x, particle.y)
heavy_rain:emit(“plink”)
end,
lifeStart=500,
lifeSpan=50,
physics={
autoAngle=false,
angles={260},
velocity=20
}
},
{
preset=“fluid”,
title=“clouds”,
color={
{70}, – Dark grays
{60},
{50}
},
positionType=“inRect”,
rectLeft=0,
rectTop=0,
rectWidth=1024,
rectHeight=60, – Create a blanket of clouds at the top of the screen
fadeInTime=500, – Low fade in time and life span
lifeSpan=500,
lifeStart=1000, – High life start delay
build=function()
local size=math.random(480, 512) – Particles are quite large
return display.newImageRect(“cloud-1.png”, size, size)
end,
propertyTable={
blendMode=“normal” – Normal fluid preset uses additive blending via the property table
},
physics={
velocity=1.1, – Some minor velocity in left-right direction
autoAngle=false,
angles={180, 0}
}
}
}
heavy_rain:start(“rain”, “clouds”)
[/lua]
Well, now we’re at the end of this tutorial. I hope it’s taught you something about creating VentGroups. Play around with the parameters, edit this or that - if you create a really cool effect, please post in the CBEffects forum. It’s always cool to see what the users have created!
Caleb
April 16, 2013