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

Tuesday, November 24, 2015

Monkey-X - GUI - Simple Vertical Slider (Color select) - Code Example


Here a example of how to make Vertical Sliders. GUI stuff.

Import mojo

Class vslider
    Field x:Int,y:Int
    Field w:Int,h:Int
    Field slidey:Float
    Field low:Float,heigh:Float
    Field name:String
    Method New(x:Int,y:Int,w:Int,h:Int,low:Int,heigh:Int,slidey:Int,name:String)
        Self.x = x
        Self.y = y
        Self.w = w
        Self.h = h
        Self.low = low
        Self.heigh = heigh
        Self.slidey = slidey
        Self.name = name
    End Method
    Method update()
        If MouseDown(MOUSE_LEFT)
            If rectsoverlap(    MouseX(),
                                MouseY(),
                                1,
                                1,
                                x+5,y+25,
                                w/2,h-50)
                Local val:Float
                val = MouseY()-(y+25)
                slidey = val*((heigh-low)/(h-50))
                slidey+=low
            End If        
        End If
        If MouseHit(MOUSE_LEFT)
            If rectsoverlap(    MouseX(),
                                MouseY(),
                                1,1,
                                x+5,y+5,
                                w/2,20)
                If slidey>low Then slidey-=1
                Return
            End If
            If rectsoverlap(    MouseX(),
                                MouseY(),
                                1,1,
                                x+5,y+h-25,
                                w/2,20)
                If slidey<heigh Then slidey+=1
                Return
            End If
        End If
        slidey=Floor(slidey)
    End Method
    Method draw()
        SetColor 0,0,0
        DrawRect x,y,w,h
        SetColor 150,150,150
        DrawRect x+1,y+1,w-2,h-2
        SetColor 255,255,255
        DrawLine x+1,y+1,x+w-1,y+1
        DrawLine x+1,y+1,x+1,y+h-1
        SetColor 50,50,50
        DrawRect x+5,y+25,w-10,h-50
        SetColor 0,0,0
        Local val:Float
        val = (slidey-low)*((h-70)/(heigh-low))
        DrawRect x+5,y+25+val,w/2,20
        SetColor 255,255,255
        DrawText name,x+w/2,y-16,0.5
    End Method
    Method 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 Method 
End Class

Global sr:vslider
Global sg:vslider
Global sb:vslider

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(60)
        sr = New vslider(100,100,20,150,0,225,50,"R")
        sg = New vslider(148,100,20,150,0,255,50,"G")
        sb = New vslider(192,100,20,150,0,255,50,"B")
    End Method
    Method OnUpdate()        
        sr.update
        sg.update
        sb.update
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        DrawText "MonkeyX - GUI - Simple Vertical Sliders - Code Example.",10,10
        DrawText "Use the Mouse with the Sliders to change color of rect.",10,30         
        sr.draw
        sg.draw
        sb.draw
        SetColor 255,255,255
        DrawRect 320,100,100,100
        SetColor sr.slidey,sg.slidey,sb.slidey
        DrawRect 320+1,100+1,100-2,100-2
    End Method
End Class


Function Main()
    New MyGame()
End Function

Monday, November 23, 2015

Monkey-X - Platformer jumping and double jumping - code example


A few times I was asked if I knew how to do those double jumps in games. It is not that hard to program. All you need is to have a extra boolean that sees if you are not double jumping and trigger the double jump while in a regular jump. See the code.

' Doublejump and jumping example

Import mojo

Global px:Float = 320
Global py:Float = 240
Global playerjump:Bool = False
Global pincy:Float = 0
Global doublejump:Bool = False

Class MyGame Extends App
    Method OnCreate()
        SetUpdateRate(60)
    End
    Method OnUpdate()
        ' If the player is on the ground and the space bar is pressed
        If playerjump = False And KeyDown(KEY_SPACE) = True
            pincy = -3
            playerjump = True
        End
        'Double jump
        If playerjump = True And doublejump = False
               If KeyDown(KEY_SPACE)
                   If pincy < 0 And pincy >-2.0
                       pincy = -3
                       doublejump = True
                   End If
            End If
        End If
        'If the player is in the jump
        If playerjump = True
            pincy += 0.1
            'if the player is going up
            If pincy <=0
                For Local i:Int = 0 Until Abs(pincy)
                    py -= 1
                End
            End
            ' if the player if going down
            If pincy > 0
                For Local i:Int = 0 Until pincy
                    py += 1
                    'if the player touches the ground
                    If py > 240 Then 
                        playerjump = False
                        doublejump = False
                        py = 240
                        Exit
                    End
                End
            End
        End
    End
    Method OnRender()
        Cls(0,0,0)
        SetColor(255,255,255)
        DrawRect px,py,32,32
        DrawText "Press space bar to jump. Press space again in jump to double jump.",10,10
        If doublejump = True
            DrawText "Doublejump",px+16,py-10,0.5
        End If
    End
End

Function Main()
    New MyGame()
End

Tuesday, November 3, 2015

Monkey-X - FLoodFill Pathfinding moving mobs - code example


In games sometimes you want to agents to move towards the player. With Floodfill pathfinding you create a map around the player that increases in value the farther away from the player. These values van be used by the agents to count back towards the player. You can do more with the floodfill pathfinding I bet.

Import mojo

Const tilewidth = 32
Const tileheight = 32
Const mapwidth:Int=20
Const mapheight:Int=15
Global gamemap: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,1,0,0,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,1,1,1,1,0,0,0,0,0,0,0,0,1],
                            [1,0,0,0,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,1],
                            [1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1],
                            [1,0,0,1,1,1,1,1,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,0,0,0,1,1,1,1],                       
                            [1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,1],
                            [1,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,0,0,1],
                            [1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1],
                            [1,0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,1],
                            [1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1],
                            [1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,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] ]

Class openlist
    Field x:Int,y:Int
    Field val:Int
    Method New(x:Int,y:Int,val:Int)
        Self.x=x
        Self.y=y
        Self.val=val
    End Method
End Class
Class closedlist
    Field x:Int,y:Int
    Field val:Int
    Method New(x:Int,y:Int,val:Int)
        Self.x=x
        Self.y=y
        Self.val=val
    End Method    
End Class

Class agent
    Field x:Int,y:Int
    Field delay:Int    
    Field delete:Bool=False
    Method New()
        Local exitloop:Bool=False
        While exitloop = False
            Local x1:Int=Rnd(mapwidth)
            Local y1:Int=Rnd(mapheight)
            If myplayer.map[x1][y1] > 10
                x = x1
                y=y1
                exitloop=True
            End If
        Wend
    End Method
    Method update()
        delay-=1
        If delay<1
            delay = 30
            'move towards the player
            Local val:Int=myplayer.map[x][y]
            Local exitloop:Bool=False        
            Local dx:Int=x,dy:Int=y
            While exitloop = False
                Local x1:Int = x+Rnd(-1,2)
                Local y1:Int = y+Rnd(-1,2)
                If gamemap[y1][x1] = 0
                If myplayer.map[x1][y1] < val
                    dx=x1
                    dy=y1
                    val = myplayer.map[x1][y1]
                End If
                End If
                If Rnd(100)<5 Then exitloop = True
            Wend
            x = dx
            y = dy
            ' if close to the player remove
            If myplayer.map[x][y] < 2
                delete = True
            End If
        End If
    End Method
    Method draw()
        SetColor 255,0,0
        DrawOval x*tilewidth+5,y*tileheight+5,tilewidth-10,tileheight-10
    End Method
End Class

Class player
    Field ol:List<openlist> = New List<openlist>
    Field x:Int=10,y:Int=10
    Field map:Int[][]
    Method New()
        map = New Int[mapwidth][]
        For Local i = 0 Until mapwidth
            map[i] = New Int[mapheight]
        Next
        DebugLog mapwidth+","+mapheight
        makefloodmap()
    End Method
    Method update()
        If KeyHit(KEY_LEFT)
        If x-1 > 0
        If gamemap[y][x-1] = 0
            x-=1
            makefloodmap
        End If
        End If
        End If
        If KeyHit(KEY_RIGHT)
        If x+1 < mapwidth
        If gamemap[y][x+1] = 0
            x+=1
            makefloodmap
        End If
        End If
        End If
        If KeyHit(KEY_UP)
        If y-1 > 0
        If gamemap[y-1][x] = 0
            y-=1
            makefloodmap
        End If
        End If
        End If
        If KeyHit(KEY_DOWN)
        If y+1 < mapheight
        If gamemap[y+1][x] = 0
            y+=1
            makefloodmap
        End If
        End If
        End If
    End Method
    Method makefloodmap()        
        For Local y1=0 Until mapheight
        For Local x1=0 Until mapwidth
            map[x1][y1] = 0
        Next
        Next
        ol.Clear()
        ol.AddLast(New openlist(x,y,1))
        map[x][y] = 1
        While ol.IsEmpty() = False
            For Local i:=Eachin ol
                Local tx:Int=i.x
                Local ty:Int=i.y
                Local tv:Int=i.val
                ol.Remove i                
                If ty-1 > 0 
                    If map[tx][ty-1] = 0                
                    If gamemap[ty-1][tx] = 0
                        ol.AddLast(New openlist(tx,ty-1,tv+1))
                        map[tx][ty-1] = tv+1
                    End If
                    End If
                End If
                If tx+1 < mapwidth 
                    If map[tx+1][ty] = 0                
                    If gamemap[ty][tx+1] = 0                    
                        ol.AddLast(New openlist(tx+1,ty,tv+1))
                        map[tx+1][ty] = tv+1
                    End If
                    End If
                End If
                If ty+1 < mapheight 
                    If map[tx][ty+1] = 0                
                    If gamemap[ty+1][tx] = 0
                        ol.AddLast(New openlist(tx,ty+1,tv+1))
                        map[tx][ty+1] = tv+1
                    End If
                    End If
                End If
                If tx-1 > 0 
                    If map[tx-1][ty] = 0                
                    If gamemap[ty][tx-1] = 0
                        ol.AddLast(New openlist(tx-1,ty,tv+1))
                        map[tx-1][ty] = tv+1
                    End If
                    End If
                End If

            Next
        Wend
    End Method
    Method isonclosedlist:Bool(x1:Int,y1:Int)
        For Local i:=Eachin cl
            If i.x = x1 And i.y = y1 Then Return True
        Next
        Return False
    End Method
    Method draw()
        SetColor 255,255,0
        DrawRect x*tilewidth,y*tileheight,tilewidth,tileheight
        SetColor 255,255,255
        For Local y1=0 Until mapheight
        For Local x1=0 Until mapwidth
            If map[x1][y1] > 0
                DrawText map[x1][y1],x1*tilewidth,y1*tileheight
            End If
        Next
        Next
    End Method
End Class

Global myplayer:player = New player()
Global myagent:List<agent> = New List<agent>

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(60)
    End Method
    Method OnUpdate()        
        If Rnd(100) < 2
            myagent.AddLast(New agent())
        End If
        myplayer.update
        For Local i:=Eachin myagent
            i.update
            If i.delete = True
                myagent.Remove i
            End If
        Next
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        drawmap
        For Local i:=Eachin myagent
            i.draw
        Next
        myplayer.draw
        SetColor 255,255,255
        DrawText "Monkey-X - Floodfill pathfinding agents - code example.",10,2
        DrawText "Use Cursor keys to move (yellow) player.",10,16
        
    End Method
End Class

Function drawmap:Void()
    SetColor 255,255,255
    For Local y=0 Until mapheight
    For Local x=0 Until mapwidth
        If gamemap[y][x] = 1
            DrawRect x*tilewidth,y*tileheight,tilewidth,tileheight
        End If
    Next
    Next
End Function


Function Main()
    New MyGame()
End Function

Monday, November 2, 2015

Monkey-X - Smarter group movement 2d - Code Example


I made one of my older group movement examples a little bit smarter. The units will now move a short time either left or right from the target direction if their path is blocked. If all paths are blocked then it will wait a second.

Import mojo

Class ai
    ' unit locations
    Field x:Float,y:Float
    ' destination coords
    Field dx:Int,dy:Int
    ' movement speed
    Field ms:Float
    ' angle of x/y and dx/dy
    Field angle:Int
    ' state
    Field state:String="Direct Line"
    Field aroundang:Int
    Field countdown1:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
        Self.ms = Rnd(0.5,1.5)
        Self.dx = DeviceWidth()/2
        Self.dy = DeviceHeight()/2
    End Method
    Method update()
        If state = "Wait"
            countdown1-=1
            If countdown1 < 1
                state="Direct Line"
            End If
        End If    
        If state="Move Around"
            countdown1-=1
            If countdown1 < 1 
                state="Direct Line"
            End If
            Local nx:Float = x+Cos(aroundang)*(ms*4)
            Local ny:Float = y+Sin(aroundang)*(ms*4)
            Local nxt:Bool=False
            For Local i:=Eachin myai
                    If i.x <> x
                    If i.y <> y
                   If rectsoverlap(nx,ny,16,16,i.x,i.y,16,16) = True
                    nxt = True
                       state="Wait"
                End If
                End If
                End If
            Next
            If nxt = False
                x += Cos(aroundang)*ms
                y += Sin(aroundang)*ms
            End If
           End If
        If state="Direct Line"
            angle = getangle(dx,dy,x,y)
               If distance(x,y,dx,dy) > 5
                Local nx:Float = x+Cos(angle)*(ms*4)
                Local ny:Float = y+Sin(angle)*(ms*4)
                Local nxt:Bool=False
                For Local i:=Eachin myai
                        If i.x <> x
                        If i.y <> y
                       If rectsoverlap(nx,ny,16,16,i.x,i.y,16,16) = True
                        nxt = True
                           state="Move Around"
                           countdown1 = 32
                           findopenspot()                             
                    End If
                    End If
                    End If
                Next
                If nxt = False
                    x += Cos(angle)*ms
                    y += Sin(angle)*ms
                End If
            End If
        End If        
    End Method
    Method findopenspot()
        Local sel:Int=Rnd(10)
        If sel<5 Then
            If rightturn() = False
                leftturn
            End If
        Else
            If leftturn() = False
                rightturn
            End If
        End If
    End Method
    Method rightturn:Bool()
        aroundang=angle+90
        Local nx:Float = x+Cos(aroundang)*(ms*4)
        Local ny:Float = y+Sin(aroundang)*(ms*4)
           Local nxt:Bool=False
           For Local i:=Eachin myai
               If i.x <> x
               If i.y <> y
              If rectsoverlap(nx,ny,16,16,i.x,i.y,16,16) = True
                   nxt = True
                   state="Wait"
                   countdown1 = 60
                   Return False
               End If
               End If
               End If
           Next
        Return True
    End Method

    Method leftturn:Bool()    
        aroundang=angle-90
        Local nx:Float = x+Cos(aroundang)*(ms*4)
        Local ny:Float = y+Sin(aroundang)*(ms*4)
        Local nxt:Bool=False
        For Local i:=Eachin myai
                If i.x <> x
                If i.y <> y
               If rectsoverlap(nx,ny,16,16,i.x,i.y,16,16) = True
                   nxt = True
                   state = "Wait"
                   countdown1 = 60
                   Return False
            End If
            End If
            End If
        Next
        Return True
    End Method

    Method draw()
        SetColor 255,0,0
        DrawOval x,y,16,16
        If state="Move Around"
        SetColor 255,255,0
        DrawOval     x+(Cos(aroundang)*16),
                    y+(Sin(aroundang)*16),16,16
           End If
    End Method
    Method 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 Method    
    Method getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return ATan2(y1-y2, x1-x2)
    End Method    
    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function    
End Class


Global numai:Int=10
Global myai:List<ai> = New List<ai>
' waittime before random new destination
Global dxchangecountdown:Int=500
' hold the destination of the units
Global mydx:Int,mydy:Int

Class MyApp Extends App
    
    Method OnCreate()
        SetUpdateRate(60)
        For Local i=0 To numai
            Local exitloop:Bool=False
            Local nx:Int,ny:Int
            While exitloop = False
                exitloop = True
                nx=Rnd(640)
                ny=Rnd(480)            
                For Local ii:=Eachin myai
                    If distance(nx,ny,ii.x,ii.y) < 32
                        exitloop = False
                    End If
                Next
            Wend
            myai.AddLast(New ai(nx,ny))
        Next
        Local date := GetDate()
        Seed = date[6]
        
    End Method

    Method OnUpdate()
        dxchangecountdown-=1
        If dxchangecountdown < 0
            dxchangecountdown = 500
            mydx = Rnd(32,DeviceWidth()-64)
            mydy = Rnd(32,DeviceHeight()-64)
            For Local i:=Eachin myai
                i.dx = mydx
                i.dy = mydy
            Next
        End If
        For Local i:=Eachin myai
            i.update
        Next
        If MouseHit(MOUSE_LEFT)
            dxchangecountdown = 500
            For Local i:=Eachin myai
                i.dx = MouseX()
                i.dy = MouseY()
            Next
        End If
    End Method
    
    Method OnRender()
        Cls 0,0,0
        For Local i:=Eachin myai
            i.draw
            mydx = i.dx
            mydy = i.dy
        Next
        SetColor 255,255,0
        DrawLine mydx,mydy,mydx-5,mydy
        DrawLine mydx,mydy,mydx+5,mydy
        DrawLine mydx,mydy,mydx,mydy-5        
        DrawLine mydx,mydy,mydx,mydy+5
        SetColor 255,255,255
        DrawText "Monkey-X Smarter group movement ai.",10,10
        DrawText "Press the left mouse to change dx,dy",10,25
    End Method
    
End Class

    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function    


Function Main()
    New MyApp
End Function

Monkey-X - Zombies throwing body parts 2d - Code Example


Here a example where there are zombies walkig around throwing parts of their body around.

Import mojo

Class agent
    Field x:Float,y:Float
    Field w:Int=20+Rnd(20)
    Field h:Int=20+Rnd(20)
    Field incx:Float
    Method New(x:Int,incx:Float)        
        Self.x = x
        Self.y = 272-h
        Self.incx = incx
    End Method
    Method update()
        x += incx
        If Rnd(60*60) < 10 Then
            incx = -incx
        End If
        If x<100 Then incx=-incx
        If x>640-100 Then incx=-incx
        If Rnd(60*60)<10
            Local ix:Float=Rnd(-6,6)
            If ix >-0.5 And ix <0.5 Then ix = ix*2
            mybodypart.AddLast(New bodypart(x-9+Rnd(w),
                                            y-h+Rnd(h/2),
                                            ix,Rnd(-4,-2)))
        End If
    End Method
    Method draw()
        SetColor 255,255,255
        DrawRect x,y,w,h
    End Method
End Class

Class bodypart
    Field w:Int,h:Int
    Field x:Float,y:Float
    Field incx:Float,incy:Float
    Field mdf:Float
    Field stopped:Bool=False
    Field timeout:Int,delete:Bool=False
    Method New(x:Int,y:Int,incx:Float,incy:Float)
        Self.x = x
        Self.y = y
        Self.incx = incx
        Self.incy = incy
        w = Rnd(3,9)
        h = Rnd(3,9)
        mdf = 0.09
    End Method
    Method update()
        If stopped = False
            x+=incx
            y+=incy
            If incx>0 Then incx-=mdf
            If incx<0 Then incx+=mdf
            If mdf>0.01 Then mdf-=0.001
            incy+=0.1            
            If y>272 Then 
                incy=-(Rnd(incy/2))
                incx = Rnd(-incy,incy)
            End If
            
            If y>273                
                If incx >-0.2 And incx <0.2
                    If incy>-0.2 And incy<0.2
                        stopped=True
                    End If
                End If
            End If
        End If
        If stopped = True
            timeout+=1
            If timeout > 60*20
                delete = True
            End If
        End If
    End Method
    Method draw()
        SetColor 255,0,0
        DrawOval x,y,w,h
    End Method
End Class

Global mybodypart:List<bodypart> = New List<bodypart>
Global myagent:List<agent> = New List<agent>

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(60)
        For Local i=0 Until 10
            Local incx:Float=Rnd(-1.5,1.5)
            If incx>-0.3 And incx<0.3
                incx=incx*2
            End If
            myagent.AddLast(New agent(Rnd(100,640-100),incx))
        Next
    End Method
    Method OnUpdate()   
        For Local i:=Eachin myagent
            i.update
        Next     
        For Local i:=Eachin mybodypart
            i.update
            If i.delete = True
                mybodypart.Remove i
            End If
        Next
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        For Local i:=Eachin myagent
            i.draw
        Next
        For Local i:=Eachin mybodypart
            i.draw
        Next
        SetColor 255,255,255
        DrawText "Monkey-X - Zombies throwing body parts Example",10,10
    End Method
End Class


Function Main()
    New MyGame()
End Function