| Mirage Source http://miragesource.net/forums/ |
|
| Pushbocks Tutorial http://miragesource.net/forums/viewtopic.php?f=210&t=3452 |
Page 1 of 1 |
| Author: | Ambientiger [ Wed Mar 05, 2008 1:26 pm ] |
| Post subject: | Pushbocks Tutorial |
Pushable Blocks (originally requested of me by Gameboy) ********************************************************** Difficulty (1/5 for copy and paste) - (3/5 to understand it!) Client side code changes First of all we'll set up the variables we are going to use to handle our pushblocks. It's based the door tile system already in mirage, so you may notice a few similarities. modGlobals - Add these new variable declarations. Code: ' Used for map PushBlock editor Public PushDir1 As Byte Public PushDir2 As Byte Public PushDir3 As Byte Code: Public PushTile(0 To MAX_MAPX, 0 To MAX_MAPY) As PushTileRec modConstants - Just an extra TILE_TYPE constant here. Code: Public Const TILE_TYPE_PUSHBLOCK = 7 modTypes - Add the TypeRec that holds the info about our pushblocks. Code: Type PushTileRec Pushed As Byte Dir As Byte Moving As Byte XOffset As Integer YOffset As Integer End Type Next We'll need to add the new editor sections to help us define how each pushblock will move. frmMirage: Add an option button called 'optPushBlock' to the Attributes frame. Then add the following code to the form near the other Attribute orientated Subs. Code: Private Sub optPushBlock_Click() frmPushBlock.Show vbModal End Sub frmPushBlock: A new form Make frmPushBlock. Create three frames - fraDir1 / fraDir2 / fraDir3 With the captions set to - Direction 1 / Direction 2 / Direction 3 Add five option buttons to each frame named - optDir#None / optDir#Up / optDir#Down / optDir#Left / optDir#Right - where # is the number of frame. Set the Value of - optDir1None / optDir2None / optDir3None to True. And of course, create the OK and Cancel buttons - cmdPushBlockOK / cmdPushBlockCancel Code: Option Explicit Private Sub cmdPushBlockOK_Click() If optDir1None.Value = True Then PushDir1 = 0 ElseIf optDir1Up.Value = True Then PushDir1 = 1 ElseIf optDir1Down.Value = True Then PushDir1 = 2 ElseIf optDir1Left.Value = True Then PushDir1 = 3 ElseIf optDir1Right.Value = True Then PushDir1 = 4 Else PushDir1 = 0 End If If optDir2None.Value = True Then PushDir2 = 0 ElseIf optDir2Up.Value = True Then PushDir2 = 1 ElseIf optDir2Down.Value = True Then PushDir2 = 2 ElseIf optDir2Left.Value = True Then PushDir2 = 3 ElseIf optDir2Right.Value = True Then PushDir2 = 4 Else PushDir2 = 0 End If If optDir3None.Value = True Then PushDir3 = 0 ElseIf optDir3Up.Value = True Then PushDir3 = 1 ElseIf optDir3Down.Value = True Then PushDir3 = 2 ElseIf optDir3Left.Value = True Then PushDir3 = 3 ElseIf optDir3Right.Value = True Then PushDir3 = 4 Else PushDir3 = 0 End If Unload Me End Sub Private Sub cmdPushBlockCancel_Click() Unload Me End Sub The extra code and new subs in modGameLogic prepare the map, blit the pushblocks in the game loop and deal with how a pushblock should move when pushed. modGameLogic *Sub Main - Add along with the ClearTempTile call. Code: Call ClearPushTile *Sub GameLoop - Add underneath the For loop that Calls BltTile Code: ' Blit out pushblock movement For y = 0 To MAX_MAPY For x = 0 To MAX_MAPX If PushTile(x, y).Moving > 0 Then Call BltPushBlock(x, y) End If Next x Next y The next one is quite self explanatory. If your not sure, check a little further down in the game loop for a block of code commented ' Blit out attribs if in editor. Code: If .Type = TILE_TYPE_PUSHBLOCK Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "P", QBColor(White)) Add this next piece of code underneath the code block commented ' Process player movements (actually move them) Code: ' Process pushblock movements (actually move them) For y = 0 To MAX_MAPY For x = 0 To MAX_MAPX If PushTile(x, y).Moving > 0 Then Call ProcessPushBlock(x, y) End If Next x Next y *Sub BltTile - You'll need to change this Sub slightly to add in the pushblocks, directly after the ' Is there an animation tile to plot? comment change the line of code to this. Code: If Anim1 > 0 And TempTile(x, y).DoorOpen = NO And PushTile(x, y).Pushed = NO And PushTile(x, y).Moving = 0 Then These next two Subs are new, I put the first one in after Sub BltTile, and the second after Sub ProcessMovement. Code: Public Sub BltPushBlock(ByVal x As Integer, ByVal y As Integer) Dim x1 As Long, y1 As Long ' Only used if ever want to switch to blt rather then bltfast 'With rec_pos '.top = GetPlayerY(Index) * PIC_Y + Player(Index).YOffset '.Bottom = .top + PIC_Y '.Left = GetPlayerX(Index) * PIC_X + Player(Index).XOffset '.Right = .Left + PIC_X 'End With With rec .top = Int(Map.Tile(x, y).Mask / 7) * PIC_Y .Bottom = .top + PIC_Y .Left = (Map.Tile(x, y).Mask - Int(Map.Tile(x, y).Mask / 7) * 7) * PIC_X .Right = .Left + PIC_X End With x1 = x * PIC_X + PushTile(x, y).XOffset y1 = y * PIC_Y + PushTile(x, y).YOffset ' Check if its out of bounds because of the offset If y1 < 0 Then y1 = 0 With rec .top = .top + (y1 * -1) End With End If Call DD_BackBuffer.BltFast(x1, y1, DD_TileSurf, rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY) End Sub Code: Sub ProcessPushBlock(ByVal x As Integer, ByVal y As Integer) ' Check if player is walking, and if so process moving the pushblock over If PushTile(x, y).Moving = MOVING_WALKING Then If PushTile(x, y).Pushed = YES Then Select Case PushTile(x, y).Dir Case DIR_UP PushTile(x, y).YOffset = PushTile(x, y).YOffset - WALK_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 0) And (PushTile(x, y).YOffset = -32) Then PushTile(x, y).Moving = 0 Map.Tile(x, y - 1).Mask = Map.Tile(x, y).Mask End If Case DIR_DOWN PushTile(x, y).YOffset = PushTile(x, y).YOffset + WALK_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 0) And (PushTile(x, y).YOffset = 32) Then PushTile(x, y).Moving = 0 Map.Tile(x, y + 1).Mask = Map.Tile(x, y).Mask End If Case DIR_LEFT PushTile(x, y).XOffset = PushTile(x, y).XOffset - WALK_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = -32) And (PushTile(x, y).YOffset = 0) Then PushTile(x, y).Moving = 0 Map.Tile(x - 1, y).Mask = Map.Tile(x, y).Mask End If Case DIR_RIGHT PushTile(x, y).XOffset = PushTile(x, y).XOffset + WALK_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 32) And (PushTile(x, y).YOffset = 0) Then PushTile(x, y).Moving = 0 Map.Tile(x + 1, y).Mask = Map.Tile(x, y).Mask End If End Select Else Select Case PushTile(x, y).Dir Case DIR_UP PushTile(x, y).YOffset = PushTile(x, y).YOffset + WALK_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 0) And (PushTile(x, y).YOffset = 0) Then PushTile(x, y).Moving = 0 'Map.Tile(x, y - 1).Mask = Map.Tile(x, y).Mask End If Case DIR_DOWN PushTile(x, y).YOffset = PushTile(x, y).YOffset - WALK_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 0) And (PushTile(x, y).YOffset = 0) Then PushTile(x, y).Moving = 0 'Map.Tile(x, y + 1).Mask = Map.Tile(x, y).Mask End If Case DIR_LEFT PushTile(x, y).XOffset = PushTile(x, y).XOffset + WALK_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 0) And (PushTile(x, y).YOffset = 0) Then PushTile(x, y).Moving = 0 'Map.Tile(x - 1, y).Mask = Map.Tile(x, y).Mask End If Case DIR_RIGHT PushTile(x, y).XOffset = PushTile(x, y).XOffset - WALK_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 0) And (PushTile(x, y).YOffset = 0) Then PushTile(x, y).Moving = 0 'Map.Tile(x + 1, y).Mask = Map.Tile(x, y).Mask End If End Select End If End If ' Check if player is running, and if so process moving the pushblock over If PushTile(x, y).Moving = MOVING_RUNNING Then Select Case PushTile(x, y).Dir Case DIR_UP PushTile(x, y).YOffset = PushTile(x, y).YOffset - RUN_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 0) And (PushTile(x, y).YOffset = -32) Then PushTile(x, y).Moving = 0 Map.Tile(x, y - 1).Mask = Map.Tile(x, y).Mask End If Case DIR_DOWN PushTile(x, y).YOffset = PushTile(x, y).YOffset + RUN_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 0) And (PushTile(x, y).YOffset = 32) Then PushTile(x, y).Moving = 0 Map.Tile(x, y + 1).Mask = Map.Tile(x, y).Mask End If Case DIR_LEFT PushTile(x, y).XOffset = PushTile(x, y).XOffset - RUN_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = -32) And (PushTile(x, y).YOffset = 0) Then PushTile(x, y).Moving = 0 Map.Tile(x - 1, y).Mask = Map.Tile(x, y).Mask End If Case DIR_RIGHT PushTile(x, y).XOffset = PushTile(x, y).XOffset + RUN_SPEED ' Check if completed walking over to the next tile If (PushTile(x, y).XOffset = 32) And (PushTile(x, y).YOffset = 0) Then PushTile(x, y).Moving = 0 Map.Tile(x + 1, y).Mask = Map.Tile(x, y).Mask End If End Select End If End Sub *Sub EditorMouseDown - It should be fairly easy to see where this code slots into the Sub. Code: If frmMirage.optPushBlock.Value = True Then .Type = TILE_TYPE_PUSHBLOCK .Data1 = PushDir1 .Data2 = PushDir2 .Data3 = PushDir3 Map.Tile(x1, y1 - 1).Type = TILE_TYPE_NPCAVOID Map.Tile(x1, y1 + 1).Type = TILE_TYPE_NPCAVOID Map.Tile(x1 - 1, y1).Type = TILE_TYPE_NPCAVOID Map.Tile(x1 + 1, y1).Type = TILE_TYPE_NPCAVOID End If *Sub CanMove - Pay attention here, or you'll get it wrong. This piece of code needs to go into each of the directions mentioned in Sub CanMove. I've put mine in directly after the block of code commented ' Check to see if the key door is open or not. Remember, once for each direction, eg, If DirUp then, etc. Code: ' If there's a pushblock there, see if we can push it If Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) - 1).Type = TILE_TYPE_PUSHBLOCK Then If PushTile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) - 1).Pushed = NO Then If (Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) - 1).Data1 <> DIR_UP + 1) And (Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) - 1).Data2 <> DIR_UP + 1) And (Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) - 1).Data3 <> DIR_UP + 1) Then CanMove = False ' Set the new direction if they weren't facing that direction If d <> DIR_UP Then Call SendPlayerDir End If Exit Function End If End If End If The Sub to clear the pushblocks can be added in with the other clearing subs. Code: Sub ClearPushTile() Dim x As Long, y As Long For y = 0 To MAX_MAPY For x = 0 To MAX_MAPX PushTile(x, y).Pushed = 0 Next x Next y End Sub The last addition deals with the packet the client receives to tell it to move a pushblock. A Blocked attribute needs to be added if it is moving or an Npc_Avoid if not. modHandledata - Add a new variable declaration at the top of the sub. Code: Dim f As Long Then add this in the sub along with the other packet descriptions. I've added mine in just after the Map Key Packet. Code: ' :::::::::::::::::::::: ' :: PushBlock packet :: ' :::::::::::::::::::::: If (LCase(Parse(0)) = "pushblock") Then x = Val(Parse(1)) 'x co-ordinate y = Val(Parse(2)) 'y co-ordinate n = Val(Parse(3)) 'Pushed Value i = Val(Parse(4)) 'Player Direction f = Val(Parse(5)) 'Movement PushTile(x, y).Pushed = n PushTile(x, y).Moving = f If PushTile(x, y).Pushed = NO Then Select Case PushTile(x, y).Dir Case DIR_UP Map.Tile(x, y - 1).Mask = 0 Map.Tile(x, y - 1).Type = TILE_TYPE_NPCAVOID PushTile(x, y).XOffset = 0 PushTile(x, y).YOffset = -32 Case DIR_DOWN Map.Tile(x, y + 1).Mask = 0 Map.Tile(x, y + 1).Type = TILE_TYPE_NPCAVOID PushTile(x, y).XOffset = 0 PushTile(x, y).YOffset = 32 Case DIR_LEFT Map.Tile(x - 1, y).Mask = 0 Map.Tile(x - 1, y).Type = TILE_TYPE_NPCAVOID PushTile(x, y).XOffset = -32 PushTile(x, y).YOffset = 0 Case DIR_RIGHT Map.Tile(x + 1, y).Mask = 0 Map.Tile(x + 1, y).Type = TILE_TYPE_NPCAVOID PushTile(x, y).XOffset = 32 PushTile(x, y).YOffset = 0 End Select Exit Sub End If PushTile(x, y).Dir = i If PushTile(x, y).Pushed = YES Then Select Case PushTile(x, y).Dir Case DIR_UP Map.Tile(x, y - 1).Type = TILE_TYPE_BLOCKED Case DIR_DOWN Map.Tile(x, y + 1).Type = TILE_TYPE_BLOCKED Case DIR_LEFT Map.Tile(x - 1, y).Type = TILE_TYPE_BLOCKED Case DIR_RIGHT Map.Tile(x + 1, y).Type = TILE_TYPE_BLOCKED End Select End If PushTile(x, y).XOffset = 0 PushTile(x, y).YOffset = 0 Exit Sub End If Pushable Blocks - Server side changes ******************************************* Once again we need to set up the variables for our new pushblocks. modGlobals Code: Public PushTile(1 To MAX_MAPS) As PushTileRec modConstants Code: Public Const TILE_TYPE_PUSHBLOCK = 7 modTypes Code: Type PushTileRec Pushed(0 To MAX_MAPX, 0 To MAX_MAPY) As Byte PushedTimer As Long End Type modGeneral - As the comment in the code says, this closes any open pushblocks from a timer. *Sub GameAI - Add underneath section of code used for closing doors Code: ' ///////////////////////////////////////// ' // This is used for closing pushblocks // ' ///////////////////////////////////////// If TickCount > PushTile(y).PushedTimer + 5000 Then For y1 = 0 To MAX_MAPY For x1 = 0 To MAX_MAPX If Map(y).Tile(x1, y1).Type = TILE_TYPE_PUSHBLOCK And PushTile(y).Pushed(x1, y1) = YES Then If PushBlockBlocked(y, x1, y1) = False Then PushTile(y).Pushed(x1, y1) = NO Call SendDataToMap(y, "PUSHBLOCK" & SEP_CHAR & x1 & SEP_CHAR & y1 & SEP_CHAR & 0 & SEP_CHAR & 0 & SEP_CHAR & 1 & SEP_CHAR & END_CHAR) Else PushTile(y).PushedTimer = GetTickCount End If End If Next x1 Next y1 End If modGameLogic *Sub PlayerMove - Add after the block of code commented ' Check for key trigger open Code: ' Check for pushblock trigger If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index)).Type = TILE_TYPE_PUSHBLOCK Then x = GetPlayerX(Index) y = GetPlayerY(Index) If Map(GetPlayerMap(Index)).Tile(x, y).Type = TILE_TYPE_PUSHBLOCK And PushTile(GetPlayerMap(Index)).Pushed(x, y) = NO Then PushTile(GetPlayerMap(Index)).Pushed(x, y) = YES PushTile(GetPlayerMap(Index)).PushedTimer = GetTickCount Call SendDataToMap(GetPlayerMap(Index), "PUSHBLOCK" & SEP_CHAR & x & SEP_CHAR & y & SEP_CHAR & 1 & SEP_CHAR & GetPlayerDir(Index) & SEP_CHAR & Movement & SEP_CHAR & END_CHAR) Call MapMsg(GetPlayerMap(Index), "A block is being pushed.", White) End If End If Lastly we need to add a function to check if there is someone on the other side of the pushblock the player wants to push stopping them doing so, I added this with the other Functions at the top of modGameLogic. Code: Function PushBlockBlocked(ByVal MapNum As Long, ByVal x As Integer, ByVal y As Integer) As Boolean Dim i As Long PushBlockBlocked = False For i = 1 To MAX_PLAYERS If Player(i).Char(Player(i).CharNum).Map = MapNum Then If Player(i).Char(Player(i).CharNum).x = x And Player(i).Char(Player(i).CharNum).y = y Then PushBlockBlocked = True End If End If Next i End Function To use the pushblocks in your game, enter the editor, place a MASK layer tile where you want the block. Select the Pushblock option from the attributes section of the map editor and select the directions it can move. Click on the map where you placed the MASK tile, et voila, a working pushblock. There is a slight issue I noticed while running the server and client of a much larger game than Mirage on the same PC. At times of lag a player could push a block and move over it but the client didn't move the block over. Chances are it won't happen too often with a dedicated server, or a little twiddling with the code should sort it out. Enjoy. |
|
| Author: | genusis [ Wed Mar 05, 2008 5:27 pm ] |
| Post subject: | Re: Pushbocks Tutorial |
hmm this idea is very good =] we can use this to make mazes and stuff where thye have to move blocks to get through. haha |
|
| Author: | genusis [ Wed Mar 05, 2008 5:27 pm ] |
| Post subject: | Re: Pushbocks Tutorial |
hmm this idea is very good =] we can use this to make mazes and stuff where thye have to move blocks to get through. haha |
|
| Author: | Joost [ Wed Mar 05, 2008 7:17 pm ] |
| Post subject: | Re: Pushbocks Tutorial |
Unfair. I was just about to code this. (NoRlly) |
|
| Author: | Forte [ Thu Mar 06, 2008 12:18 am ] |
| Post subject: | Re: Pushbocks Tutorial |
ooh nice, I have this in my engine, it's made basically the same way, Well, Nice job on the tut. I'll read through it when I get the chance |
|
| Author: | Joost [ Thu Mar 06, 2008 8:50 am ] |
| Post subject: | Re: Pushbocks Tutorial |
After looking trough your tutorial, I've decided Im not gonna use it ;p. Instead of using a mask tile, I'll use an actual block tile, that animates when you push it. It looks cooler, and otherwise the tutorial won't work with optimized surfaces. (Unless you 'drefresh the map every time you push) |
|
| Author: | Ambientiger [ Thu Mar 06, 2008 11:28 am ] |
| Post subject: | Re: Pushbocks Tutorial |
I had to modify my original code so that this tutorial works with MSE1, I haven't added optimized surfaces to any of my projects yet so didn't know about the possible problem, thanks for the warning Joost. |
|
| Author: | Rian [ Fri Mar 07, 2008 6:24 pm ] |
| Post subject: | Re: Pushbocks Tutorial |
I added this to a fresh MSE. I don't really understand how the actual pushblock editor is supposed to work. also, im not sure if it's the tutorial, or if I did it wrong (I probably did it wrong, I did this tutorial with much haste) but I noticed that the block would sometimes move when I walked next to it, not necessarily in front of it. |
|
| Author: | Ambientiger [ Fri Mar 07, 2008 8:23 pm ] |
| Post subject: | Re: Pushbocks Tutorial |
I stripped the code from cerberus, made up the tutorial and then dropped it into a fresh MSE1 to test it. PushBlocks Tutorial Package The way I recommend you add pushblocks to the game is: go to the map editor place a Mask Layer tile where you want the block click the Attributes option click the PushBlock option then click ontop of the brick that you placed select the directions the block can move in from the popup (none/left/right/up/down) and click okay SPOILER: (click to show)
the left one moves left and down the middle one moves left and right to give access to the blocked in area - there is a key attribute in the blocked area that opens the darker middle brick the middle brick can also move up incase a player gets stuck in the blocked area SPOILER: (click to show)
a player can also stand in the way of a pushblock to stop them closing if they move away after the 5 or so second reset time the block moves back instantly. these blocks are the only ones i've tested with this tutorial, Sonire, were the blocks you tested near the edge of the map maybe? might be a bug I hadn't spotted. |
|
| Page 1 of 1 | All times are UTC |
| Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |
|