Yes kids, I decided to make a weather tutorial because I love you guys.
First off, this is only going to be the client-side part. Making the server send the client what the weather is, is very simple and I'm not going to go there. Hell, I may add it later if this tutorial is really popular. Also, unlike a simple, "Here's the code, copy/paste it.", I'm going to explain everything here. Lets get down to the brass tax, shall we?
1. Finding/Making the tiles. You'll need to make or find rain tiles, snow tiles, or whatever other types of weather you want. The cool thing about this weather system is you can add as much weather effects as you'd like. I made these rain tiles in paint. Took 2 seconds, looks decent enough. (NOTE: This is a JPEG format because these forums don't allow BMP posting. You're going to have to convert it or make your own!)
3 Tiles wide. Black is the "invisible" part. Make sure to name your .bmp Weather as well.
2. Initializing the Weather surface in DX. If you didn't know, all graphics are stored on surfaces. Think of these as canvases that can stretch and shrink to any artwork. We need to make a canvas that will hold all our weather.
First, add the Surface variable. (The name of our "canvas".) This should be added to the list in the DirectX Module:
Public DD_WeatherSurf As DirectDrawSurface7
Now, lets initialize this puppy. This part won't make sense to you and it really doesn't matter. Just know that this basically prepares our surface and makes it useable. It also loads our Weather Tiles onto the canvas so they can be ready to use! Put the following code in the InitSurfaces sub under the other ones in the DirectX Module.
' Init weather ddsd type and load the bitmap DDSD_Weather.lFlags = DDSD_CAPS DDSD_Weather.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Or DDSCAPS_SYSTEMMEMORY Set DD_WeatherSurf = DD.CreateSurfaceFromFile(App.Path & "\Weather.bmp", DDSD_Weather) DD_WeatherSurf.SetColorKey DDCKEY_SRCBLT, key
Now what happens when we want the game to close. It's proper to "clear" our "canvases". In the DestroyDirectX sub in the DirectX Module, add this line:
Set DD_WeatherSurf = Nothing
Before moving on, make sure you have these constants. If you didn't delete them, you still have them. I added thunder to the list. You can add whatever you want. I'm not sure where they originally start out, for I made a modConstants and stuck all the constants in there. Just hit Control & F and search for "WEATHER_".
' Weather constants Public Const WEATHER_NONE = 0 Public Const WEATHER_RAINING = 1 Public Const WEATHER_SNOWING = 2 Public Const WEATHER_THUNDER = 3
Now the fun part... :D
3. Drawing the weather tiles onto the screen In the game loop (In modGameLogic) is where we want to check if the weather isn't set to 0 (WEATHER_NONE). If it's not 0, do something about it! Since we want this weather to be drawn above the highest layer, we must put the "Check" after all other layers. I'm assuming your highest layer is Fringe. Finding the right spot to put it in is kind of tricky. I took the liberty of taking a screen shot to ease your efforts a bit. Paste this code in the right spot:
' Check for weather and draw if necessary If Map.Weather > 0 Then Call BltWeather(Map.Weather) End If
Now guess what folks, we're asking the computer to do something it can't find. BltWeather() Doesn't exist! Lets make it. You can basically throw this sub anywhere in the gameLogic module. I just stuck it at the bottom, no biggie. After I post the code, I'm going to break it down and explain it line by line:
Sub BltWeather(weatherType As Byte)
Static weatherFrame As Byte, lightCount As Byte Dim rTemp As RECT, x As Integer, y As Integer, weatherTemp as Byte
If weathertype = WEATHER_THUNDER then weatherTemp = WEATHER_RAINING Else weatherTemp = weatherType End If
With rTemp .top = (weatherType - 1) * PIC_Y .Bottom = .top + PIC_Y .Left = weatherFrame * PIC_X .Right = .Left + PIC_X End With ' Check if it's raining and draw it ' I decided to have rain with my thunder If weatherType = WEATHER_RAIN Or weatherType = WEATHER_THUNDER Then For y = 0 To MAX_MAPY For x = 0 To MAX_MAPX Call DD_BackBuffer.BltFast(x * PIC_X, y * PIC_Y, DD_WeatherSurf, rTemp, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY) Next x Next y If weatherFrame = 2 Then weatherFrame = 0 Else weatherFrame = weatherFrame + 1 End If End If ' If it's thunder, make the screen randomly flash blue If weatherType = WEATHER_THUNDER Then If Int((60 - 1 + 1) * Rnd) + 1 = 8 Then DD_BackBuffer.SetFillColor (16327202) Call DD_BackBuffer.DrawBox(0, 0, (MAX_MAPX + 1) * PIC_X, (MAX_MAPY + 1) * PIC_Y) End If End If
End Sub
Ok, ok, don't freak out. Let me explain. :)
Sub BltWeather(weatherType As Byte) That's simple enough. I'm telling the computer to create a sub called BltWeather. It requires a WeatherType to be passed. (ex: WEATHER_THUNDER)
Static weatherFrame As Byte Dim rTemp As RECT, x As Integer, y As Integer These are the variables I use to make this happen properly. First off, a Static variable is a normal variable except, unlike other variables, it keeps its Data even after you leave the sub. rTemp, x, and y, will be erased once this sub is through. rTemp is the Temporary Rectangle that I'm using. What it does is it tells the computer what "Chunk" I want of the Weather Surface drawn on the screen. (In this case, a tile.) X and Y tell the computer where on the screen to stick this "Chunk" (Tile).
With rTemp .top = (weatherType - 1) * PIC_Y .Bottom = .top + PIC_Y .Left = weatherFrame * PIC_X .Right = .Left + PIC_X End With If you've never seen a With statement, it's basically saying, "Computer, the next attributes I give you are attributes from this variable: rTemp." So .top is actually rTemp.top. Just a lil' shortcut I used, don't freak out if you don't understand. Now, we only need to find the top and left coordinates of where on the Weather.Bmp is the Chunk we want. Then we simply add 32 to find the bottom and right.
If it's raining for example (That makes weatherType = 1). Since it's the first row of tiles, 1 * 32 doesn't work because that skips the first row. So we need to shift all the rows back one. (weatherType - 1) * PIC_Y
Now for the frame part, it's simple. Whatever frame it's in, the beginning has to that number times PIC_X (32).
Kapeesh?
' Check if it's raining and draw it ' I decided to have rain with my thunder If weatherType = WEATHER_RAIN Or weatherType = WEATHER_THUNDER Then For y = 0 To MAX_MAPY For x = 0 To MAX_MAPX Call DD_BackBuffer.BltFast(x * PIC_X, y * PIC_Y, DD_WeatherSurf, rTemp, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY) Next x Next y If weatherFrame = 2 Then weatherFrame = 0 Else weatherFrame = weatherFrame + 1 End If End If
This is the rain-drawing part. I only have rain-drawing. If you want snow, add the same exact code but just change it to:
If weatherType = WEATHER_SNOW Same thing for any other weather form you can think of.
Now it's saying, if it IS raining, lets scroll through every tile on the map, and paste our "Chunk" (Tile) that we got earlier onto the screen. Now we want to change the frame of the weather or else it would sit at the same frame and look dumb. If the frame hits 2 (The last frame), set it back to 0.
' If it's thunder, make the screen randomly flash blue If weatherType = WEATHER_THUNDER Then If Int((60 - 1 + 1) * Rnd) + 1 = 8 Then DD_BackBuffer.SetFillColor (16327202) Call DD_BackBuffer.DrawBox(0, 0, (MAX_MAPX + 1) * PIC_X, (MAX_MAPY + 1) * PIC_Y) End If End If This is a little complicated bonus I added to add the effect of lightning on your screen. It first generates a random number. In this case 1-60. If the number is 8 (My lucky number), draw a fat blue square on the whole screen. Since the sub is called 16 times a second (16 FPS), eventually, the random number WILL be 8. To make the lightning flash less or more, modify the '60' in this line:
If Int((60 - 1 + 1) * Rnd) + 1 = 8 Then (The higher the number, the less lightning there will be.)
That about wraps it up! :D
If you encounter any errors or have any problems, please post or contact me, I'd be more than happy to help. If you see any mistakes I made, let me know as well. For an unworking-tutorial isn't a good one at all. :wink:
- Mr.Muffles
UPDATES AND BUG FIXES: - In the modTypes, look for the type MapRec and add this if it isn't there:
Weather As Byte Now, either code your own server-side way of determining the weather OR just give it a test. I put something like this right before the game loop:
Map.Weather = WEATHER_RAINING ' Whatever type you want.
|