Print Page | Close Window

Directional Blocking (My Way)

Printed From: Mirage Source
Category: Tutorials
Forum Name: Approved Tutorials
Forum Discription: All tutorials shown to actually work with MSE are moved here.
URL: http://ms.shannaracorp.com/backup-forums/forum_posts.asp?TID=55
Printed Date: 20 December 2006 at 6:01pm
Software Version: Web Wiz Forums 8.01 - http://www.webwizforums.com


Topic: Directional Blocking (My Way)
Posted By: Sync
Subject: Directional Blocking (My Way)
Date Posted: 07 February 2006 at 6:38pm
Originally posted by FunkyNut


Directional Blocking (My way)

Difficulty 4/5(Its not difficult to understand, but It can get a bit confusing since its not like a tile attibute and adds parts everywhere)

http://img451.imageshack.us/my.php?image=directionalblockexample28bc.png">
^^^Forgot to show sample, so here is what mine finished looks like.  I can walk on all the green tiles, but they wont allow me to walk on the grey tiles


ok, This tut will give you the ability to Unblock/Block directions that a players on, if you want to stop a tile from access from all sides, its still easier to use a block attib (Which isnt removed by this tut),but this tile will allow a player to walk on a tile (Such as a ledge) but wont let them walk any further (so you dont waste a whole tile when stopping players walking over a ledge). 

Btw, I’m not sure, but I assume that this will muck up any maps you already have so you either have to redo the maps, or make a small app to convert all old maps to this new format

Ok, lets Begin, first off lets change the way Tiles  are read and saved, so find TileRec on both Client and Server and add to the bottom of the type:
    WalkUp As Boolean
    WalkDown As Boolean
    WalkLeft As Boolean
    WalkRight As Boolean


This will be used to record which directions are walkable, if a directions walkable, it will be set to true

Now, lets just add the controls we’ll be using in Map Editor, Add a Checkbox called chkDirectionView and two command buttons called cmdFillDirections and cmdClearDirections

http://img25.imageshack.us/my.php?image=directionblockmapeditor9aw.png">

Ok, now we’ve added the controls, we need the server to send us the new Tile Records to the client so find the sub SendMap, find:
 
                 Packet = Packet & .Ground & SEP_CHAR & .Mask & SEP_CHAR & .Anim & SEP_CHAR & .Fringe & SEP_CHAR & .Type & SEP_CHAR & .Data1 & SEP_CHAR & .Data2 & SEP_CHAR & .Data3 & SEP_CHAR


and replace it with:
                 Packet = Packet & .Ground & SEP_CHAR & .Mask & SEP_CHAR & .Anim & SEP_CHAR & .Fringe & SEP_CHAR & .Type & SEP_CHAR & .Data1 & SEP_CHAR & .Data2 & SEP_CHAR & .Data3 & SEP_CHAR & .WalkUp & SEP_CHAR & .WalkDown & SEP_CHAR & .WalkLeft & SEP_CHAR & .WalkRight & SEP_CHAR


Now find SendMap in the Client and replace the same thing


Now, we need the client to interpret this new data when its received so find:
                 SaveMap.Tile(x, y).Ground = Val(Parse(n))
                 SaveMap.Tile(x, y).Mask = Val(Parse(n + 1))
                 SaveMap.Tile(x, y).Anim = Val(Parse(n + 2))
                 SaveMap.Tile(x, y).Fringe = Val(Parse(n + 3))
                 SaveMap.Tile(x, y).Type = Val(Parse(n + 4))
                 SaveMap.Tile(x, y).Data1 = Val(Parse(n + 5))
                 SaveMap.Tile(x, y).Data2 = Val(Parse(n + 6))
                 SaveMap.Tile(x, y).Data3 = Val(Parse(n + 7))
                
                 n = n + 8


And after SaveMap.Tile(x, y).Data3 add:
                 SaveMap.Tile(x, y).WalkUp = Parse(n + 8)
                 SaveMap.Tile(x, y).WalkDown = Parse(n + 9)
                 SaveMap.Tile(x, y).WalkLeft = Parse(n + 10)
                 SaveMap.Tile(x, y).WalkRight = Parse(n + 11)


And change:
                 n = n + 8

To:
                 n = n + 12

So we can keep track on what we’ve received

Now we’ve done all that, we need to make the server aware of all this malarkey that the clients sending so find:
                 Map(MapNum).Tile(x, y).Ground = Val(Parse(n))
                 Map(MapNum).Tile(x, y).Mask = Val(Parse(n + 1))
                 Map(MapNum).Tile(x, y).Anim = Val(Parse(n + 2))
                 Map(MapNum).Tile(x, y).Fringe = Val(Parse(n + 3))
                 Map(MapNum).Tile(x, y).Type = Val(Parse(n + 4))
                 Map(MapNum).Tile(x, y).Data1 = Val(Parse(n + 5))
                 Map(MapNum).Tile(x, y).Data2 = Val(Parse(n + 6))
                 Map(MapNum).Tile(x, y).Data3 = Val(Parse(n + 7))


And add:
                 Map(MapNum).Tile(x, y).WalkUp = Parse(n + 8)
                 Map(MapNum).Tile(x, y).WalkDown = Parse(n + 9)
                 Map(MapNum).Tile(x, y).WalkLeft = Parse(n + 10)
                 Map(MapNum).Tile(x, y).WalkRight = Parse(n + 11) 


And again, change the n = n +8 to n = n + 12



Now the server can quite happily send and retrieve the new data, we need to allow the Client to edit this data, so let’s first make the Client Blt the arrows onto each tile by adding a new surface containing the arrows.  First, save this image to your Client Gfx Folder and call it ‘Direction’ and the extension you use. http://img363.imageshack.us/img363/4606/direction6rn.png

We want to do this neatly and as fully as possible so find
    If FileExist(FileName & "sprites" & GFX_EXT, True) = False Or FileExist(FileName & "tiles" & GFX_EXT, True) = False Or FileExist(FileName & "items" & GFX_EXT, True) = False Then

And replace it with:
    If FileExist(FileName & "sprites" & GFX_EXT, True) = False Or FileExist(FileName & "tiles" & GFX_EXT, True) = False Or FileExist(FileName & "items" & GFX_EXT, True) = False Or FileExist(FileName & "Direction" & GFX_EXT, True) = False Then


Now, we need to create the DirectDraw surface, so find
Public DDSD_Item As DDSURFACEDESC2
and underneath it add:
Public DDSD_Direction As DDSURFACEDESC2


Also find:
Public DD_ItemSurf As DirectDrawSurface7
and add underneath
Public DD_DirectionSurf As DirectDrawSurface7


Now we need to add the code that actually inits the surface, so find
    ' Init items ddsd type and load the bitmap
    With DDSD_Item
        .lFlags = DDSD_CAPS
        .ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Or DDSCAPS_VIDEOMEMORY
    End With
    Set DD_ItemSurf = DD.CreateSurfaceFromFile(FileName & "items" & GFX_EXT, DDSD_Item)
    DD_ItemSurf.SetColorKey DDCKEY_SRCBLT, Key


And add under it
    ' Init Direction ddsd type and load the bitmap
    With DDSD_Direction
        .lFlags = DDSD_CAPS
        .ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Or DDSCAPS_VIDEOMEMORY
    End With
    Set DD_DirectionSurf = DD.CreateSurfaceFromFile(FileName & "Direction" & GFX_EXT, DDSD_Direction)
    DD_DirectionSurf.SetColorKey DDCKEY_SRCBLT, Key


Lets go though this line by line, the .lFlags is telling Dx what properties to look at, so if we added, ddsd_Height, it will check the height property, in this case its checking the caps property.  The .lCaps is describing how to load the surface, in this case its placed into the video memory.  (Not 100% sure what the OffScreenPlain does, but you use it for any surface that’s in the background)

The next line tells it to load a picture from file onto the surface using the properties we’ve just set, and the line after that just tells it what colours to make invisible.

We also have to unload the surface from memory when we exit so find
    Set DD_ItemSurf = Nothing
and add
    Set DD_DirectionSurf = Nothing


Now we need to display the directions on the map when we choose to so, find:
        ' Blit out attribs if in editor
        If InEditor Then
                 For y = 0 To MAX_MAPY
                     For x = 0 To MAX_MAPX
                          With Map.Tile(x, y)
                              If .Type = TILE_TYPE_BLOCKED Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "B", QBColor(BrightRed))
                              If .Type = TILE_TYPE_WARP Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "W", QBColor(BrightBlue))
                              If .Type = TILE_TYPE_ITEM Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "I", QBColor(White))
                              If .Type = TILE_TYPE_NPCAVOID Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "N", QBColor(White))
                              If .Type = TILE_TYPE_KEY Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "K", QBColor(White))
                              If .Type = TILE_TYPE_KEYOPEN Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "O", QBColor(White))
                              If .Type = TILE_TYPE_NPCSPAWN Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "NS", QBColor(Yellow))
                          End With
                     Next x
                 Next y
        End If


And replace it with
        ' Blit out attribs if in editor
        If InEditor Then
             If frmMirage.chkDirectionView.Value = 0 Then
                 For y = 0 To MAX_MAPY
                     For x = 0 To MAX_MAPX
                          With Map.Tile(x, y)
                              If .Type = TILE_TYPE_BLOCKED Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "B", QBColor(BrightRed))
                              If .Type = TILE_TYPE_WARP Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "W", QBColor(BrightBlue))
                              If .Type = TILE_TYPE_ITEM Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "I", QBColor(White))
                              If .Type = TILE_TYPE_NPCAVOID Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "N", QBColor(White))
                              If .Type = TILE_TYPE_KEY Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "K", QBColor(White))
                              If .Type = TILE_TYPE_KEYOPEN Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "O", QBColor(White))
                              If .Type = TILE_TYPE_NPCSPAWN Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "NS", QBColor(Yellow))
                          End With
                     Next x
                 Next y
             End If
        End If

All this does is disable viewing tile attribs when viewing Tile Directions

Now to main part that displays the arrows, we need this to be displayed above everything including all text, so we need to place this just after the backbuffer is released when blting text, so find:
        Call DD_BackBuffer.ReleaseDC(TexthDC)


And add this
        
        If InEditor Then
             If frmMirage.chkDirectionView.Value = 1 Then
                 Call BltDirectionArrows
             End If
        End If
       


and then add the end of modGameLogic add this sub
Public Sub BltDirectionArrows()
Dim x As Long, y As Long
Dim Walkable As Boolean ' If tile has at least one dir, change center to circle

    For y = 0 To MAX_MAPY
        For x = 0 To MAX_MAPX
             With Map.Tile(x, y)
            
                 Walkable = False ' Reset for a new tile
                
                 ' Lets check what to Blt for the Up arrow
                 If .WalkUp Then
                     With rec
                          .top = 0
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 3
                          .Right = .Left + PIC_Y
                     End With
                     Walkable = True
                 Else
                     With rec
                          .top = PIC_X
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 3
                          .Right = .Left + PIC_Y
                     End With
                 End If
                 Call DD_BackBuffer.BltFast(x * PIC_X, y * PIC_Y, DD_DirectionSurf, rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)
                
                 ' Now lets check For Down Arrow
                 If .WalkDown Then
                     With rec
                          .top = 0
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 2
                          .Right = .Left + PIC_Y
                     End With
                     Walkable = True
                 Else
                     With rec
                          .top = PIC_X
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 2
                          .Right = .Left + PIC_Y
                     End With
                 End If
                 Call DD_BackBuffer.BltFast(x * PIC_X, y * PIC_Y, DD_DirectionSurf, rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)
                
                 ' Now lets check For Left Arrow
                 If .WalkLeft Then
                     With rec
                          .top = 0
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 0
                          .Right = .Left + PIC_Y
                     End With
                     Walkable = True
                 Else
                     With rec
                          .top = PIC_X
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 0
                          .Right = .Left + PIC_Y
                     End With
                 End If
                 Call DD_BackBuffer.BltFast(x * PIC_X, y * PIC_Y, DD_DirectionSurf, rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)
                
                 ' Now lets check For Right Arrow
                 If .WalkRight Then
                     With rec
                          .top = 0
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 1
                          .Right = .Left + PIC_Y
                     End With
                     Walkable = True
                 Else
                     With rec
                          .top = PIC_X
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 1
                          .Right = .Left + PIC_Y
                     End With
                 End If
                 Call DD_BackBuffer.BltFast(x * PIC_X, y * PIC_Y, DD_DirectionSurf, rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)
                
                 ' If tile is totally blocked, place cross in center
                 If Walkable Then
                     With rec
                          .top = 0
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 4
                          .Right = .Left + PIC_Y
                     End With
                 Else
                     With rec
                          .top = PIC_X
                          .Bottom = .top + PIC_X
                          .Left = PIC_Y * 4
                          .Right = .Left + PIC_Y
                     End With
                 End If
                 Call DD_BackBuffer.BltFast(x * PIC_X, y * PIC_Y, DD_DirectionSurf, rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)
                
                 ' We need to draw a grid so we can tell which tiles which (First set pen width to 1)
                 DD_BackBuffer.DrawLine x * PIC_X, y * PIC_Y, x * PIC_X, y * PIC_Y + (PIC_Y * MAX_MAPY) + 1
                 DD_BackBuffer.DrawLine x * PIC_X, y * PIC_Y, x * PIC_X + (PIC_X * MAX_MAPX) + 1, y * PIC_Y
                              End With
        Next x
    Next y
End Sub


All this sub does is, go though each tile, checks its walkable properties and blts the correct image, once it’s done that it blts 2 lines which will eventually create a grid.  The only other thing to explain about this sub is that it blts the center shape by checking if the tile is totally blocked, and if it is, it will blt a cross, if not, it blts a circle.

We still need to make use of them buttons we added earlier, so double click on cmdFillDirections and add:
Dim X As Long, Y As Long
   
    ' Go through each tile and set each direction to walkable
    For X = 0 To MAX_MAPX
        For Y = 0 To MAX_MAPY
             With Map.Tile(X, Y)
                 .WalkUp = True
                 .WalkDown = True
                 .WalkLeft = True
                 .WalkRight = True
             End With
        Next Y
    Next X


All this does is scan each tile and make each direction walkable

Now double click cmdClearDirections and add:
Dim X As Long, Y As Long
   
    ' Go through each tile and set each direction to walkable
    For X = 0 To MAX_MAPX
        For Y = 0 To MAX_MAPY
             With Map.Tile(X, Y)
                 .WalkUp = False
                 .WalkDown = False
                 .WalkLeft = False
                 .WalkRight = False
             End With
        Next Y
    Next X


This also scans each tile, but this time, it cuts off all directions.



Thats all for now, its 11:25pm, and i still need a bath ready for school tomoz, i'll try finish it tomoz but its not guaranteed, but i've posted it anyway incase someone wants to try finish it by themselves.  All it needs is a way to flick a single direction on/off and mod to playermove to scan directions :)


Btw, incase your wondering, this is what mine looks like so far: http://img52.imageshack.us/my.php?image=directionalblockexample5xt.png">

Direction Blocking Part 2

Finally gotten round to starting the second half :)

I better explain first what I’m going to do next for detecting which tile and where on the tile you’ve clicked, so far, i've split the tile into sections like this...
http://imageshack.us">

Each section is a different clickable area, for example, the green area is for Blocking/Unblocking walking up and if the user clicks in this area then it will toggle it, the only problem now, is the corners at each side of the green section.  The easiest way to solve this is to divide the whole tile into nine sections, like this…
http://imageshack.us">

What we need the client to do now when the mouse is clicked, is to scan which section was clicked. So, open up your client, find the sub EditorMouseDown.

Now at the top with the variables declaration, add these variables:
Dim x2 As Long, y2 As Long ' Used to record where on the tile was clicked
Dim CenterTolerence As RECT ' Controls how easy it is to press center


Now,  to make it look neat, indent this
             If (Button = 1) And (x1 >= 0) And (x1 <= MAX_MAPX) And (y1 >= 0) And (y1 <= MAX_MAPY) Then
                 If frmMirage.optLayers.Value = True Then
                     With Map.Tile(x1, y1)
                          If frmMirage.optGround.Value = True Then .Ground = EditorTileY * 7 + EditorTileX
                          If frmMirage.optMask.Value = True Then .Mask = EditorTileY * 7 + EditorTileX
                          If frmMirage.optAnim.Value = True Then .Anim = EditorTileY * 7 + EditorTileX
                          If frmMirage.optFringe.Value = True Then .Fringe = EditorTileY * 7 + EditorTileX
                     End With
                 Else
                     With Map.Tile(x1, y1)
                          If frmMirage.optBlocked.Value = True Then .Type = TILE_TYPE_BLOCKED
                          If frmMirage.optWarp.Value = True Then
                              .Type = TILE_TYPE_WARP
                              .Data1 = EditorWarpMap
                              .Data2 = EditorWarpX
                              .Data3 = EditorWarpY
                          End If
                          If frmMirage.optItem.Value = True Then
                              .Type = TILE_TYPE_ITEM
                              .Data1 = ItemEditorNum
                              .Data2 = ItemEditorValue
                              .Data3 = 0
                          End If
                          If frmMirage.optNpcAvoid.Value = True Then
                              .Type = TILE_TYPE_NPCAVOID
                              .Data1 = 0
                              .Data2 = 0
                              .Data3 = 0
                          End If
                          If frmMirage.optKey.Value = True Then
                              .Type = TILE_TYPE_KEY
                              .Data1 = KeyEditorNum
                              .Data2 = KeyEditorTake
                              .Data3 = 0
                          End If
                          If frmMirage.optKeyOpen.Value = True Then
                              .Type = TILE_TYPE_KEYOPEN
                              .Data1 = KeyOpenEditorX
                              .Data2 = KeyOpenEditorY
                              .Data3 = 0
                          End If
                          If frmMirage.optNpcSpawn.Value = True Then
                              .Type = TILE_TYPE_NPCSPAWN
                              .Data1 = SpawnNpcNum
                              .Data2 = 0
                              .Data3 = 0
                          End If
                     End With
                 End If
             End If
            
             If (Button = 2) And (x1 >= 0) And (x1 <= MAX_MAPX) And (y1 >= 0) And (y1 <= MAX_MAPY) Then
                 If frmMirage.optLayers.Value = True Then
                     With Map.Tile(x1, y1)
                          If frmMirage.optGround.Value = True Then .Ground = 0
                          If frmMirage.optMask.Value = True Then .Mask = 0
                          If frmMirage.optAnim.Value = True Then .Anim = 0
                          If frmMirage.optFringe.Value = True Then .Fringe = 0
                     End With
                 Else
                     With Map.Tile(x1, y1)
                          .Type = 0
                          .Data1 = 0
                          .Data2 = 0
                          .Data3 = 0
                     End With
                 End If
             End If


Add
        End If
after it and then, add before the section you just indented, add
        ' Check if we need to change directional block or tile attribs
        If frmMirage.chkDirectionView.Value = 1 Then
             With CenterTolerence
                 .top = 9
                 .Bottom = 22
                 .Left = 9
                 .Right = 22
                
                 If Button = 1 And (x1 >= 0) And (x1 <= MAX_MAPX) And (y1 >= 0) And (y1 <= MAX_MAPY) Then
                     x2 = x - (x1 * PIC_X)
                     y2 = y - (y1 * PIC_Y)
                    
                     ' Using CenterTolerence as a grid guide, check which part was clicked (Start from Bottom right)
                     If x2 > .Right Then ' Right side
                          If y2 > .Bottom Then ' Right Bottom
                              ' Now check which side of that small section was clicked
                              If x2 > y2 Then
                                   Map.Tile(x1, y1).WalkRight = True
                                  
                              Else
                                   Map.Tile(x1, y1).WalkDown = True
                              End If
                             
                          ElseIf y2 > .Left Then ' Right Middle
                              Map.Tile(x1, y1).WalkRight = True
                             
                          Else ' Right Top
                              ' Check which side was clicked, remember, minus from x because
                              ' its not starting from 0
                              If x2 - .Right > y2 Then
                                   Map.Tile(x1, y1).WalkUp = True
                                  
                              Else
                                   Map.Tile(x1, y1).WalkRight = True
                              End If
                             
                          End If
                         
                     ElseIf x2 > .Left Then ' Middle side
                          If y2 > .Bottom Then 'Bottom
                              Map.Tile(x1, y1).WalkDown = True
                             
                          ElseIf y2 > .Left Then ' Middle
                              Map.Tile(x1, y1).WalkUp = True
                              Map.Tile(x1, y1).WalkDown = True
                              Map.Tile(x1, y1).WalkLeft = True
                              Map.Tile(x1, y1).WalkRight = True
                             
                          Else ' Top
                              Map.Tile(x1, y1).WalkUp = True
                          End If
                         
                     Else
                          If y2 > .Bottom Then 'Left Bottom
                              If x2 > y2 - .Bottom Then
                                   Map.Tile(x1, y1).WalkDown = True
                              Else
                                   Map.Tile(x1, y1).WalkLeft = True
                              End If
                             
                          ElseIf y2 > .Left Then ' Left Middle
                              Map.Tile(x1, y1).WalkLeft = True
                             
                          Else ' Left Top
                              If x2 > y2 Then
                                   Map.Tile(x1, y1).WalkUp = True
                              Else
                                   Map.Tile(x1, y1).WalkLeft = True
                              End If
                          End If
                         
                     End If
                    
                  ElseIf Button = 2 And (x1 >= 0) And (x1 <= MAX_MAPX) And (y1 >= 0) And (y1 <= MAX_MAPY) Then
                     x2 = x - (x1 * PIC_X)
                     y2 = y - (y1 * PIC_Y)
                    
                     ' Using CenterTolerence as a grid guide, check which part was clicked (Start from Bottom right)
                &nb