Thursday, November 26, 2015

Monkey-X - Platformer with WallCrawler(wall followingz) - Code Example


I saw this enemy in a platformer game and thought it would be nice to make myself. I tried it 8 months ago and failed but today I figured out what I did wrong. (You can re-use the wallcrawler class)

Import mojo

Const tilewidth = 32
Const tileheight = 32
Const mapwidth:Int=20
Const mapheight:Int=10
Global map:Int[][] = [      [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                            [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                            [1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1],
                            [1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1],
                            [1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1],
                            [1,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1],
                            [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                            [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
                            [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
                            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] ]

Class wallcrawler
    'x and y tilepositions(cells)
    Field x:Float,y:Float
    'nx and ny is next tileposition
    Field nx:Int,ny:Int
    'offset for drawing (smooth movement)
    Field offx:Int,offy:Int
    ' direction wallcrawler is goint to
    ' 1 = up, 2 = right, 3 = down, 4 = left
    Field direction:Int
    Method New(x:Float,y:Float)
        Self.x = x
        Self.y = y
        Self.nx = x
        Self.ny = y
        'start going right
        Self.direction = 2
    End Method
    Method update()
        If x = nx And y = ny
            Else
            ' if not on next position then slowly move there
            If x<nx Then offx+=1
            If x>nx Then offx-=1
            If y<ny Then offy+=1
            If y>ny Then offy-=1
            If offx>tilewidth Then x+=1;offx=0
            If offx<-tilewidth Then x-=1;offx=0
            If offy>tileheight Then y+=1;offy=0
            If offy<-tileheight Then y-=1;offy=0
            Return 
        End If
        ' get the next directions
        Local rightd:Int=direction+1
        Local forwardd:Int=direction
        Local leftd:Int=direction-1
        ' b sure to stay in legal movement
        If rightd > 4 Then rightd = 1
        If leftd < 1 Then leftd = 4
        ' first see if we can go right
        If postaken(rightd) = True
                direction = rightd
                movepos(rightd)
                Return            
        End If
        ' then see if we can go forward
        If postaken(forwardd) = True
            direction = forwardd
            movepos(forwardd)
            Return
        End If
        'then see if we can go left
        If postaken(leftd) = True
            direction = leftd
            movepos(leftd)
            Return
        End If
    End Method
    ' get next cell position
    Method movepos(d:Int)
        nx = x
        ny = y
        Select d
            Case 1;ny-=1
            Case 2;nx+=1
            Case 3;ny+=1
            Case 4;nx-=1
        End Select
    End Method
    'see if the next possible position if a wall
    Method postaken(d:Int)
        Select d
            Case 1;If map[y-1][x] = 0 Then Return True
            Case 2;If map[y][x+1] = 0 Then Return True
            Case 3;If map[y+1][x] = 0 Then Return True
            Case 4;If map[y][x-1] = 0 Then Return True
        End Select
        Return False
    End Method
    Method draw()
        SetColor 255,0,0
        DrawRect x*tilewidth+offx,y*tileheight+offy,tilewidth,tileheight
    End Method
End Class

Class players
    Field x:Float = 640/2-16
    Field y:Float = 480/2
    Field pw:Int=32
    Field ph:Int=32
    Field incy:Float
    Field jump:Bool=False
    Method New()
    End Method
    Method update()
        playermovement
        playergravity
    End Method
    Method playergravity()
        ' If the player is on the ground and the space bar is pressed
        If jump = False And playertc(0,1) = False
            jump = True
            incy = 0
        End If
        If jump = False And KeyDown(KEY_SPACE) = True
            incy = -4
            jump = True
        End
        'If the player is in the jump
        If jump = True
            incy += 0.1
            'if the player is going up
            If incy <=0
                For Local i:Int = 0 Until Abs(incy)                
                    y -= 1
                    If playertc(0,-1) = True
                        incy = 0
                        Exit
                    End If
                End
            End
            ' if the player if going down
            If incy > 0
                For Local i:Int = 0 Until incy
                    y += 1
                    'if the player touches the ground
                    If playertc(0,1) = True
                        jump = False                        
                        Exit
                    End
                End
            End
        End
    End Method
    Method playermovement()
       If KeyDown(KEY_RIGHT)
           For Local i=0 Until 2
            If playertc(1,0) = False
                   x+=1
            End If
           Next
       End If
       If KeyDown(KEY_LEFT)
           For Local i=0 Until 2    
               If playertc(-1,0) = False
                   x-=1
               End If
           Next
       End If        
    End Method
    Method playertc:Bool(x1:Int,y1:Int)
        Local cx = (x + x1) / tilewidth
           Local cy = (y + y1) / tileheight
        For Local y2=cy-1 Until cy+2
        For Local x2=cx-1 Until cx+2
            If x2>=0 And x2<mapwidth And y2>=0 And y2<mapheight
                If map[y2][x2] > 0
                    If rectsoverlap(x+x1,y+y1,pw,ph,x2*tilewidth,
                                    y2*tileheight,tilewidth,tileheight) = True
                        Return True
                    End If
                End If
            End If
        Next
        Next
        Return False
    End Method
    Method draw()
        ' draw the player
        SetColor 255,255,0        
        DrawOval x,y,pw,ph        
    End Method
End Class

Global player:List<players> = New List<players>
Global wallcrawlers:List<wallcrawler> = New List<wallcrawler>

Class MyGame Extends App
    Method OnCreate()
        SetUpdateRate(60)
        player.AddLast(New players())
        createwallcrawlers
    End
    Method OnUpdate()
        ' Player left and right movement
        For Local i:=Eachin player
            i.update
        Next
        For Local i:=Eachin wallcrawlers
            i.update
        Next
    End
    Method OnRender()
        Cls(0,0,0)
        SetColor(255,255,255)
        ' draw the map
        For Local y:Int = 0 Until mapheight
        For Local x:Int = 0 Until mapwidth
            If map[y][x] = 1 Then DrawRect(x*tilewidth,y*tileheight,tilewidth,tileheight)
        End
        End
        DrawText "Platformer Example with Wallcrawlers(wall following)",10,10
        DrawText "Use cursor left/right and space bar to move player",160,10
        For Local i:=Eachin player
            i.draw
        Next
        For Local i:=Eachin wallcrawlers
            i.draw
        Next
    End
End

Function createwallcrawlers:Void()
    For Local y=0 Until mapheight
    For Local x=0 Until mapwidth
        If map[y][x] = 2
            map[y][x] = 0
            wallcrawlers.AddLast(New wallcrawler(x,y))        
        End If
    Next
    Next
End Function

Function rectsoverlap:Bool(x1:Int, y1:Int, w1:Int, h1:Int, x2:Int, y2:Int, w2:Int, h2:Int)
    If x1 >= (x2 + w2) Or (x1 + w1) <= x2 Then Return False
    If y1 >= (y2 + h2) Or (y1 + h1) <= y2 Then Return False
    Return True
End

Function Main()
    New MyGame()
End

No comments:

Post a Comment