Monday, October 23, 2017

Monkey-x - Generator - 2d flasks and bottles - code example

 Import mojo  
   
 Class tile  
      Field width:Int,height:Int  
      Field map:Int[][]  
      Method New(w:Int,h:Int)  
           Self.width = w  
           Self.height = h  
           map = New Int[width][]  
           For Local i:Int=0 Until width  
                map[i] = New Int[height]  
           Next            
      End Method  
      ' Here we create the flasks or bottles  
      ' or what else.  
      Method generate()  
           'make right side  
           ' from the center top to center bottom   
           Local x:Float=width/2  
           Local y:Float=0  
           Local angle:Int=0  
           While y<=height  
           For Local i:Int=0 Until 20  
                x+=Cos(angle)*.5  
                y+=Sin(angle)*.5  
                If x>=width Then x-=1  
                If x<0 Or y<0 Or x>=width Or y>=height Then Exit  
                map[x][y] = 1 ' create border point  
                fillleftside(x-1,y) ' fill left side  
           Next  
           angle=Rnd(0,120)  
           Wend  
           If y>height Then y=height-1  
           For Local x1:Int=x Until width/2-1 Step -1  
                map[x1][y] = 1  
           Next  
           'make left side (mirror right side)  
           For y = 0 Until height  
           For x = width/2 Until width  
                map[width-x][y] = map[x][y]  
           Next  
           Next  
           Return  
      End Method  
      ' here we put the value of  
      ' 2 inside the map from inputted  
      ' coords to most left position  
      Method fillleftside(fx:Int,fy:Int)  
           For Local x:Int=fx Until 0 Step -1  
                map[x][fy] = 2  
           Next  
      End Method  
      Method draw(sx:Int,sy:Int,ar:Int,ag:Int,ab:Int)  
           Local c:Int  
           Local g:Int  
           Local b:Int  
           Local lightpointx:Int=Rnd(5,width-5)  
           For Local y:Int=0 Until height  
           For Local x:Int=0 Until width  
                If map[x][y] = 0 Then   
                     c=0+((ag/height)*y)  
                     g=0+((ab/height)*y)  
                     b=0+((ar/height)*y)  
                     If c>255 Then c=255  
                     If g>255 Then g=255  
                     If b>255 Then b=255  
                     If c<0 Then c=0  
                     If g<0 Then g=0  
                     If b<0 Then b=0  
   
                     SetColor c,g,b  
                       
                     DrawRect sx+x,sy+y,1,1  
                     Continue  
                End If  
                ' here we draw the border   
                ' and the red (rainbowish color)  
                Select map[x][y]  
                     Case 1'border   
                     c = 255-((255/height)*y)  
                     If x>width/2 Then c/=2  
                     SetColor c,c,c  
                     Case 2                      
                     c = ar-((ar/height)*y)  
                     g = ag-((ag/height)*y)  
                     b = ab-((ab/height)*y)  
                       
                     c=-distance(lightpointx,0,x,0)+c  
                     g=-distance(lightpointx,0,x,0)+g  
                     b=-distance(lightpointx,0,x,0)+b                                     
                     If c>255 Then c=255  
                     If g>255 Then g=255  
                     If b>255 Then b=255  
                     If c<0 Then c=0  
                     If g<0 Then g=0  
                     If b<0 Then b=0  
   
                     SetColor c,g,b  
                       
                       
                End Select  
                DrawRect sx+x,sy+y,1,1                 
           Next  
           Next  
      End Method  
   Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)  
     Return Abs(x2-x1)+Abs(y2-y1)  
   End Function       
 End Class  
   
 Class MyGame Extends App  
      Field mytile:tile  
   Method OnCreate()  
        Seed = GetDate[4]*GetDate[5]  
     SetUpdateRate(1)  
   End Method  
   Method OnUpdate()      
   End Method  
   Method OnRender()  
     Cls 0,0,0   
     SetColor 255,255,255  
     For Local y:Int=0 Until DeviceHeight Step 55  
     For Local x:Int=0 Until DeviceWidth Step 55  
     mytile = New tile(48,48)  
     mytile.generate()       
     mytile.draw(x,y,Rnd(24,255),Rnd(24,255),Rnd(24,255))  
     Next  
     Next  
   End Method  
 End Class  
   
   
 Function Main()  
   New MyGame()  
 End Function  

Monkey-X - Generator - 2d Maps using Lines - code example

 ' Create a map with lines.  
 ' It works by randomly selecting a point on the map  
 ' and the drawing into a random direction. We stop  
 ' drawing if we are close to a previously drawn line.  
 '  
   
 Import mojo  
   
 Class map  
      Field screenwidth:Int  
      Field screenheight:Int  
      Field mapwidth:Int  
      Field mapheight:Int  
      Field tilewidth:Float  
      Field tileheight:Float  
      Field map:Int[][]  
      Method New(sw:Int,sh:Int,mw:Int,mh:Int)  
           Self.screenwidth = sw  
           Self.screenheight = sh  
           Self.mapwidth = mw  
           Self.mapheight = mh  
           Self.tilewidth = Float(sw) / Float(mw)  
           Self.tileheight = Float(sh) / Float(mh)  
           map = New int[mapwidth][]  
           For Local i:Int=0 Until mapwidth  
                map[i] = New Int[mapheight]  
           Next  
           createmap()  
      End Method  
      Method createmap()  
           ' Loop a number of times  
           For Local i:Int=0 Until (mapwidth+mapheight)  
                ' Get a random x and y spot on the map  
                Local x:Float=Rnd(mapwidth)  
                Local y:Float=Rnd(mapheight)  
                ' Chose an angle  
                Local angle:Int=Rnd(360)  
                ' We will draw d into angle it's direction  
                Local d:Int=Rnd(3,35)  
                Local xitloop:Bool=False  
                ' We change the angle and distance 3 times  
                For Local iii:Int=0 Until 3  
                ' Loop the distance  
                For Local ii:Int=0 Until d  
                     ' If spot taken with 1 or out of screen   
                     ' then exit the loop  
                     If maptaken(x-4,y-4,8,8) Then xitloop=True ; Exit  
                     ' Put value 2 into the map  
                     map[x][y] = 2  
                     ' Next x and y position  
                     x+=Cos(angle)*1  
                     y+=Sin(angle)*1                      
                Next  
                ' Exit the loop(spot taken)  
                If xitloop=True Then Exit  
                ' Change angle and distance  
                angle+=Rnd(-90,90)  
                d=Rnd(3,35)  
                Next  
                ' Turn all new drawn 2 value's into  
                ' value of 1  
                For Local y:Int=0 Until mapheight  
                For Local x:Int=0 Until mapwidth  
                     If map[x][y] = 2 Then map[x][y] = 1  
                Next  
                Next  
           Next  
      End Method  
      ' See if the area selected is outside the  
      ' screen or if the map value is 1  
      Method maptaken:Bool(x:Int,y:Int,w:Int,h:Int)  
           For Local y2:Int=y Until y+h  
           For Local x2:Int=x Until x+w  
                If x2<0 Or x2>=mapwidth Or y2<0 Or y2>=mapheight Then Return True  
                If map[x2][y2] = 1 Then Return True  
           Next  
           Next  
           Return False  
      End Method  
      ' Draw the map  
      Method draw()  
           For Local y:Int=0 Until mapheight  
           For Local x:Int=0 Until mapwidth  
                If map[x][y] = 0 Then Continue  
                SetColor 255,255,255                      
                Local x2:Int=x*tilewidth  
                Local y2:Int=y*tileheight  
                DrawRect x2,y2,tilewidth+1,tileheight+1  
           Next  
           Next  
      End Method  
 End Class  
   
 Class MyGame Extends App  
      Field mymap:map  
      Field cnt:Int=0  
   Method OnCreate()  
        Seed = GetDate[4] * GetDate[5]  
     SetUpdateRate(1)  
     createrandommap()  
   End Method  
   Method OnUpdate()  
        cnt+=1  
        If KeyHit(KEY_SPACE) Or cnt > 1  
             cnt=0  
             createrandommap()  
        End If    
   End Method  
   Method OnRender()  
     Cls 0,0,0   
     ' Draw the map  
     mymap.draw()  
     SetColor 255,255,255  
           Local mw:Int=mymap.mapwidth  
           Local mh:Int=mymap.mapheight  
           DrawText "Width : "+mw+" Height : "+mh,0,0  
   End Method  
      Method createrandommap()  
           Local size:Int=Rnd(20,200)  
           mymap = New map(DeviceWidth,DeviceHeight,size,size)  
      End Method  
 End Class  
   
   
   
 Function Main()  
   New MyGame()  
 End Function  

Monkey-X - Breath First Search(bfs) - code example


 'Is this the breath first search? Not to familiar with it.  
   
 Import mojo  
   
 Class search  
      Field screenwidth:Int,screenheight:Int  
      Field mapwidth:Int,mapheight:Int  
      Field tilewidth:Float,tileheight:Float  
      Field sx:Int,sy:Int  
      Field ex:Int,ey:Int  
      Field map:Int[][]  
      Field myopenlist:List<node>  
      Field myclosedlist:List<node>  
      Field mypath:List<path>  
      Field mx:Int[]=[0,-1,1,0]  
      Field my:Int[]=[-1,0,0,1]  
      Method New(screenwidth:Int,screenheight:Int,mapwidth:Int,mapheight:Int)  
           Self.screenwidth = screenwidth  
           Self.screenheight = screenheight  
           Self.mapwidth = mapwidth  
           Self.mapheight = mapheight  
           Self.tilewidth = Float(screenwidth) / Float(mapwidth)  
           Self.tileheight = Float(screenheight) / Float(mapheight)  
           map = New Int[mapwidth][]  
           For Local i:Int=0 Until mapwidth  
                map[i] = New Int[mapheight]  
           Next  
           makemap()  
      End Method  
      Method makemap:Void()  
           For Local i:Int=0 Until mapwidth/3  
                Local x1:Float=Rnd(0,mapwidth)  
                Local y1:Float=Rnd(0,mapheight)  
                Local angle:Int=Rnd(360)  
                Local dist:Int=Rnd(3,7)  
                For Local ii:Int=0 Until dist  
                     x1+=Cos(angle)*1  
                     y1+=Sin(angle)*1  
                     If x1<0 Or y1<0 Or x1>=mapwidth Or y1>=mapheight Then Exit  
                     map[x1][y1] = 1  
                Next  
           Next  
      End Method  
      Method search:Bool(sx:Int,sy:Int,ex:Int,ey:Int)  
           If sx=ex And sy=ey Then Return False  
           If map[sx][sy] <> 0 Or map[ex][ey] <> 0 Then Return False  
           Self.sx = sx  
           Self.sy = sy  
           Self.ex = ex  
           Self.ey = ey  
           myopenlist = New List<node>  
           myclosedlist = New List<node>  
           mypath = New List<path>  
           myopenlist.AddFirst(New node(sx,sy,sx,sy))  
           ' the search  
           While Not myopenlist.IsEmpty  
                Local cx:Int=myopenlist.First.x  
                Local cy:Int=myopenlist.First.y  
                Local px:Int=myopenlist.First.parentx  
                Local py:Int=myopenlist.First.parenty  
                myclosedlist.AddFirst(New node(cx,cy,px,py))  
                If cx = ex And cy = ey Then   
                     findpathback()  
                     Return True  
                End If  
                myopenlist.RemoveFirst()  
                For Local i:Int=0 Until mx.Length  
                     Local nx:Int=cx+mx[i]  
                     Local ny:Int=cy+my[i]  
                     If nx<0 Or ny<0 Or nx>=mapwidth Or ny>=mapheight Then Continue  
                     If map[nx][ny] = 0 'if the map is not obstructed  
                     If isonclosedlist(nx,ny) = False And isonopenlist(nx,ny) = False  
                     myopenlist.AddLast(New node(nx,ny,cx,cy))                      
                     End If  
                     End If  
                Next  
           Wend  
           Return False  
      End Method  
        
   ' Here we calculate back from the end back to the  
   ' start and create the path list.  
   Method findpathback:Bool()  
     Local x:Int=ex  
     Local y:Int=ey  
     mypath.AddFirst(New path(x,y))  
     Repeat  
       For Local i:=Eachin myclosedlist  
         If i.x = x And i.y = y  
           x = i.parentx  
           y = i.parenty  
           mypath.AddFirst(New path(x,y))  
         End If  
       Next  
       If x = sx And y = sy Then Return True  
     Forever    
   End Method  
   
      Method drawpath()  
           If Not mypath Then Return  
           For Local i:=Eachin mypath  
                SetColor 255,0,0  
                DrawOval i.x*tilewidth+(tilewidth/4),i.y*tileheight,tilewidth/4,tileheight/2  
           Next  
      End Method  
        
      Method drawclosedlist()  
           If Not myclosedlist Then Return  
           For Local i:=Eachin myclosedlist  
                DrawText "loc:"+i.x+","+i.y,                    i.x*tilewidth,i.y*tileheight+15  
                DrawText "par:"+i.parentx+","+i.parenty,     i.x*tilewidth,i.y*tileheight+30  
           Next  
      End Method  
   
      Method isonopenlist:Bool(x:Int,y:Int)  
           For Local i:=Eachin myopenlist  
                If x = i.x And y = i.y Then   
                Return True  
                End If  
           Next  
           Return False  
      End Method  
   
      Method isonclosedlist:Bool(x:Int,y:Int)  
           For Local i:=Eachin myclosedlist  
                If x = i.x And y = i.y Then   
                Return True  
                End If  
           Next  
           Return False  
      End Method  
      Method draw()  
           SetColor 255,255,255  
           For Local y:Int = 0 Until mapheight  
           For Local x:Int = 0 Until mapheight  
                  
                If map[x][y] = 1  
                     SetColor 155,155,155  
                     DrawRect x*tilewidth,y*tileheight,tilewidth,tileheight       
                End If  
                If sx = x And sy = y  
                     SetColor 255,0,0  
                     DrawOval x*tilewidth+10,y*tileheight,10,10  
                End If  
                If ex = x And ey = y  
                     SetColor 255,255,0  
                     DrawOval x*tilewidth+10,y*tileheight,10,10  
                End If  
           Next  
           Next  
      End Method  
 End Class  
   
 Class node  
      Field x:Int  
      Field y:Int  
      Field parentx:Int  
      Field parenty:Int  
      Method New(x:Int,y:Int,parentx:Int,parenty:Int)  
           Self.x = x  
           Self.y = y  
           Self.parentx = parentx  
           Self.parenty = parenty  
      End Method  
 End Class  
   
 Class path  
      Field x:Int  
      Field y:Int  
      Method New(x:Int,y:Int)  
           Self.x = x  
           Self.y = y  
      End Method  
 End Class  
   
 Class MyGame Extends App  
      Field pathfound:Bool=False  
      Field mysearch:search  
      Field cnt:Int=0  
   Method OnCreate()  
        Seed = GetDate[5] * GetDate[4]  
     SetUpdateRate(10)  
     mysearch = New search(DeviceWidth,DeviceHeight,10,10)  
     pathfound = mysearch.search(2,2,6,6)  
   End Method  
   Method OnUpdate()   
        cnt+=1  
        If KeyHit(KEY_SPACE) Or cnt>15  
             pathfound=False  
             cnt=0  
             Local w:Int=Rnd(10,50)  
             mysearch = New search(DeviceWidth,DeviceHeight,w,w)  
             pathfound = mysearch.search(Rnd(w),Rnd(w),Rnd(w),Rnd(w))  
        End If   
   End Method  
   Method OnRender()  
     Cls 0,0,0   
     mysearch.drawclosedlist  
     mysearch.draw  
     mysearch.drawpath  
     SetColor 255,255,255  
           If pathfound  
                DrawText "Path Found",0,0  
           End If  
   End Method  
 End Class  
   
   
 Function Main()  
   New MyGame()  
 End Function  

Thursday, October 19, 2017

Monkey-X - Ai Taking Cover - Shooter - code example


Import mojo

Class enemy
    Field x:Int,y:Int
    Field w:Int,h:Int
    Field state:String
    Field deleteme:Bool
    Field cooldown:Int
    Field waittime:Int
    Field path:List<pathnode> = New List<pathnode>    
    Method New()
        w = mymap.tilewidth-4
        h = mymap.tileheight-4
        findstartpos()

    End Method
    Method update()
        ' enemy shoot diagnal
        If Rnd(100)<2 Then
            Local px:Int=myplayer.x
            Local py:Int=myplayer.y
            If distance(px,py,x,y) < 200
                If px<x And py<y And mymap.mapcollide(x-5,y-5,w/3,h/3) = False 
                    mybullet.AddLast(New bullet(x,y,"leftup","enemy"))
                End If
                If px>x And py<y And mymap.mapcollide(x+5,y-5,w/3,h/3) = False 
                    mybullet.AddLast(New bullet(x,y,"rightup","enemy"))
                End If
                If px<x And py>y And mymap.mapcollide(x-5,y+5,w/3,h/3) = False 
                    mybullet.AddLast(New bullet(x,y,"leftdown","enemy"))
                End If
                If px>x And py>y And mymap.mapcollide(x+5,y+5,w/3,h/3) = False 
                    mybullet.AddLast(New bullet(x,y,"rightdown","enemy"))
                End If

            End If
        End If
        'enemy shoot horizontal vertical
        If Rnd(100)<2 Then
            Local px:Int=myplayer.x
            Local py:Int=myplayer.y
            If distance(px,py,x,y) < 200
                If px<x And mymap.mapcollide(x-5,y,w/3,h/3) = False 
                    mybullet.AddLast(New bullet(x,y,"left","enemy"))
                End If
                If px>x And mymap.mapcollide(x+5,y-5,w/3,h/3) = False 
                    mybullet.AddLast(New bullet(x,y,"right","enemy"))
                End If
                If py>y And mymap.mapcollide(x,y+5,w/3,h/3) = False 
                    mybullet.AddLast(New bullet(x,y,"down","enemy"))
                End If
                If py<y And mymap.mapcollide(x,y-5,w/3,h/3) = False 
                    mybullet.AddLast(New bullet(x,y,"up","enemy"))
                End If

            End If
        End If


        ' move around the enemy
        If path.IsEmpty = False
        ' add 2 to the destination coords or gets stuck
        Local dx:Int=path.First.x*mymap.tilewidth+2
        Local dy:Int=path.First.y*mymap.tileheight+2
        If x<dx And mymap.mapcollide(x+1,y,w,h) = False Then x+=1
        If x>dx And mymap.mapcollide(x-1,y,w,h) = False Then x-=1
        If y<dy And mymap.mapcollide(x,y+1,w,h) = False Then y+=1
        If y>dy And mymap.mapcollide(x,y-1,w,h) = False Then y-=1

        'if near destination 
        If distance(x,y,dx,dy) < 2 Then 
            path.RemoveFirst
            x = dx
            y = dy
        End If
        End If
        
        'if no more moves left find new cover spot
        If path.IsEmpty
            If waittime>0 Then waittime-=1
            If waittime<=0
            For Local i:Int=0 Until 100
                Local dx:Int=Rnd(2,mymap.mapwidth-2)
                Local dy:Int=Rnd(2,mymap.mapheight-2)
                If mymap.covermap[dx][dy] = 1 Then 
                    createpath(dx,dy)
                    waittime=200
                    Exit    
                End If
            Next
            End If
        End If
        
        'if player is nearby then move to closest cover spot
        If distance(myplayer.x,myplayer.y,x,y) < 160
            If cooldown>0 Then cooldown-=1
            If cooldown=0
            cooldown=100
            Local d:Int=10000
            Local destx:Int,desty:Int
            Local fnd:Bool=False
            ' random spots until coverspot, log closest
            For Local i:Int=0 Until 250
                Local dx:Int=Rnd(2,mymap.mapwidth-2)
                Local dy:Int=Rnd(2,mymap.mapheight-2)
                If mymap.covermap[dx][dy] = 1 Then 
                    Local d2:Int = distance(dx,dy,x/mymap.tilewidth,y/mymap.tileheight)
                    If d2 < d Then
                        d = d2
                        destx = dx
                        desty = dy
                        fnd=True
                    End If
                End If
            Next
            ' if we have a new dest then plan it
            If fnd=True Then createpath(destx,desty)
            End If
        End If

    End Method
    Method createpath(ex:Int,ey:Int)
        path = New List<pathnode>
        Local dx:Int=x/mymap.tilewidth
        Local dy:Int=y/mymap.tileheight
'        x = dx*mymap.tilewidth
'        y = dy*mymap.tileheight
        myastar.findpath(dx,dy,ex,ey)
        For Local i:=Eachin myastar.path
            path.AddLast(New pathnode(i.x,i.y))
        Next
    End Method
    Method drawpath()
        SetColor 255,0,0
        For Local i:=Eachin path
            DrawOval i.x*mymap.tilewidth,i.y*mymap.tileheight,w/2,h/2
        Next
    End Method
    Method findstartpos()
        Local cnt:Int=400
        Local cnt2:Int=0
        Repeat
            Local nx:Int=Rnd(0,mymap.screenwidth-20)
            Local ny:Int=Rnd(0,mymap.screenheight-20)
            Local found:Bool=True
            ' if the map position a tile
            If mymap.mapcollide(nx,ny,w,h) Then found = False
            ' if the position is to close other enemy
            For Local i:=Eachin myenemy
                If i=Self Then Continue
                If distance(i.x,i.y,nx,ny) < 30 Then found = False ;Exit
            Next
            ' if the position to close to player
            If distance(myplayer.x,myplayer.y,nx,ny) < cnt Then found = False 
            If found = True Then 
                x = nx
                y = ny
                Exit
            Else
                If cnt>32 Then cnt -=1
            End If
        Forever
    End Method
    Method draw()
        SetColor 255,0,255
        DrawOval x,y,w,h
    End Method

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

End Class

Class bullet
    Field x:Float,y:Float
    Field w:Int,h:Int
    Field mx:Int,my:Int
    Field direction:String
    Field deleteme:Bool=False
    Field speed:Int=2
    Field shooter:String
    Method New(x:Int,y:Int,direction:String,shooter:String)
        Self.x = x
        Self.y = y
        Self.w = myplayer.w/3
        Self.h = myplayer.h/3
        Self.shooter = shooter
        Self.direction = direction
        If direction = "left" Then mx = -1
        If direction = "right" Then mx = 1
        If direction = "up" Then my = -1
        If direction = "down" Then my = 1
        If direction = "leftup" Then mx = -1 ; my = -1
        If direction = "rightup" Then mx = 1 ; my = -1
        If direction = "leftdown" Then mx = -1 ; my = 1
        If direction = "rightdown" Then mx = 1 ; my = 1
    End Method
    Method update()
        'move the bullet and see collision with walls
        For Local i:Int=0 Until speed
            x += mx
            y += my
            If x < 0 Or x > mymap.screenwidth Then deleteme = True
            If y < 0 Or y > mymap.screenheight Then deleteme = True
            If mymap.mapcollide(x,y,w,h) Then deleteme = True
        Next
        ' collision with bullet vs enemy
        ' delete bullet and delete enemy
        If shooter = "player"
            For Local i:=Eachin myenemy
                If distance(i.x+(i.w/2),i.y+(i.h/2),x,y)<myplayer.w/1.5 Then 
                    deleteme = True
                    i.deleteme = True
                End If
            Next
        End If

        ' collision with bullet vs player
        ' delete bullet and kill player
        If shooter = "enemy"
            If distance(myplayer.x+(myplayer.w/2),myplayer.y+(myplayer.h/2),x,y)<myplayer.w/1.5 Then 
                deleteme = True
                myplayer.died = True
            End If
        End If

    End Method
    Method draw()
        SetColor 255,255,0
        DrawOval x,y,w,h
    End Method
    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function

End Class

Class player
    Field x:Float,y:Float
    Field w:Int,h:Int
    Field direction:String="up"
    Field died:Bool=False
    Method New()
        w = mymap.tilewidth-4
        h = mymap.tileheight-4
        findstartingpos()
    End Method
    Method update()
        playercontrols()
        makecovermap()
    End Method
    Method playercontrols()
        ' movement    
        If KeyDown(KEY_UP) And Not mymap.mapcollide(x,y-1,w,h)
            y-=1
            direction = "up"
        End If
        If KeyDown(KEY_LEFT) And Not mymap.mapcollide(x-1,y,w,h)
            x-=1
            direction = "left"
        End If
        If KeyDown(KEY_RIGHT) And Not mymap.mapcollide(x+1,y,w,h)
            x+=1
            direction = "right"
        End If
        If KeyDown(KEY_DOWN) And Not mymap.mapcollide(x,y+1,w,h)
            y+=1
            direction = "down"
        End If
        If KeyDown(KEY_LEFT) And KeyDown(KEY_UP) Then direction = "leftup"
        If KeyDown(KEY_RIGHT) And KeyDown(KEY_UP) Then direction = "rightup"
        If KeyDown(KEY_LEFT) And KeyDown(KEY_DOWN) Then direction = "leftdown"
        If KeyDown(KEY_RIGHT) And KeyDown(KEY_DOWN) Then direction = "rightdown"    
        ' shooting
        If KeyHit(KEY_F)
            mybullet.AddLast(New bullet(x,y,direction,"player"))
        End If
    End Method
    Method makecovermap()
        If Rnd(60)>2 Then Return
        For Local y:Int=0 Until mymap.mapheight
        For Local x:Int=0 Until mymap.mapwidth
            mymap.covermap[x][y] = 1
            If mymap.map[x][y] <> 0 Then mymap.covermap[x][y] = 2
        Next
        Next
        ' shoot bullets into random directions around
        ' the player and see if any position is a cover position
        For Local i:Int=0 Until 600
            Local x2:Float=x
            Local y2:Float=y
            Local xa:Float=Rnd(-1,1)
            Local ya:Float=Rnd(-1,1)
            For Local d:Int=0 Until 40
                x2+=xa*Float(mymap.tilewidth/2)
                y2+=ya*Float(mymap.tileheight/2)
                Local mx:Int=x2/mymap.tilewidth
                Local my:Int=y2/mymap.tileheight
                If mx>=0 And my>=0 And mx<mymap.mapwidth And my<mymap.mapheight
                mymap.covermap[mx][my] = 0
                Else
                Exit
                End If
                If mymap.mapcollide(x2,y2,w/3,h/3) Then Exit
                
            Next
        Next
        '
        ' Remove every coverpoint except if they
        ' are near a wall. 
        For Local y2:Int=0 Until mymap.mapheight
        For Local x2:Int=0 Until mymap.mapwidth
            Local remove:Bool=True
            For Local y3:Int=y2-1 To y2+1
            For Local x3:Int=x2-1 To x2+1
                If x3<0 Or y3<0 Or x3>=mymap.mapwidth Or y3>=mymap.mapheight Then Continue
                If mymap.map[x3][y3] <> 0 Then remove = False ; Exit
            Next
            Next
            If remove = True Then
                mymap.covermap[x2][y2] = 0
            End If
        Next
        Next
        'if closer to the player then higher movement cost per tile
        For Local y2:Int=0 Until mymap.mapheight
        For Local x2:Int=0 Until mymap.mapwidth
            If myastar.map[x2][y2] <> 1000 Then myastar.map[x2][y2] = 100-distance(myplayer.x/mymap.tilewidth,myplayer.y/mymap.tileheight,x2,y2)
            If myastar.map[x2][y2] < 85 Then myastar.map[x2][y2] = 0
            If mymap.covermap[x2][y2] = 1 Then myastar.map[x2][y2] = 0
        Next
        Next


    End Method
    Method findstartingpos()
        Repeat
            Local x1:Int = Rnd(0,mymap.mapwidth)
            Local y1:Int = Rnd(0,mymap.mapheight)
            Local istaken:Bool=False
            For Local x2:Int=x1-4 To x1+4
            For Local y2:Int=y1-4 To y1+4
                If x2<0 Or y2<0 Or x2>=mymap.mapwidth Or y2>=mymap.mapheight Then Continue
                If mymap.map[x2][y2] <> 0 Then istaken = True ; Exit                
            Next
            Next
            If istaken=False Then 
                x = x1*mymap.tilewidth
                y = y1*mymap.tileheight
                Exit
            End If            
        Forever
    End Method
    Method draw()
        SetColor 255,255,255
        DrawOval x,y,w,h
    End Method
    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function
End Class

Class astar
    Field mapwidth:Int,mapheight:Int
    Field sx:Int,sy:Int
    Field ex:Int,ey:Int
    Field olmap:Int[][]
    Field clmap:Int[][]
    Field map:Int[][]
    Field ol:List<openlist> = New List<openlist>
    Field cl:List<closedlist> = New List<closedlist>
    Field path:List<pathnode> = New List<pathnode>
    Field xstep:Int[] = [0,-1,1,0]
    Field ystep:Int[] = [-1,0,0,1]
    Method New()
        mapwidth = mymap.mapwidth
        mapheight = mymap.mapheight
        olmap = New Int[mapwidth][]
        clmap = New Int[mapwidth][]
        map = New Int[mapwidth][]
        For Local i:Int=0 Until mapwidth
            olmap[i] = New Int[mapheight]
            clmap[i] = New Int[mapheight]
            map[i] = New Int[mapheight]
        Next
        ' Copy the map into the astar class map
        For Local y:=0 Until mapheight
        For Local x:=0 Until mapwidth
            map[x][y] = mymap.map[x][y]
        Next
        Next
    End Method
    ' This creates the map and copies the 
    ' path in the path list
    Method findpath:Bool(sx:Int,sy:Int,ex:Int,ey:Int)
        If sx = ex And sy = ey Then Return False
        Self.sx = sx
        Self.sy = sy
        Self.ex = ex
        Self.ey = ey
        For Local y=0 Until mapheight
        For Local x=0 Until mapwidth
            olmap[x][y] = 0
            clmap[x][y] = 0
        Next
        Next
        ol.Clear
        cl.Clear
        path.Clear
        ol.AddFirst(New openlist(sx,sy))
        Local tx:Int
        Local ty:Int
        Local tf:Int
        Local tg:Int
        Local th:Int
        Local tpx:Int
        Local tpy:Int
        Local newx:Int
        Local newy:Int
        Local lowestf:Int
        olmap[sx][sy] = 1
        While ol.IsEmpty() = False
            lowestf = 100000
            For Local i:=Eachin ol
                If i.f < lowestf
                    lowestf = i.f
                    tx = i.x
                    ty = i.y
                    tf = i.f
                    tg = i.g
                    th = i.h
                    tpx = i.px
                    tpy = i.py
                End If
            Next
            If tx = ex And ty = ey
                cl.AddLast(New closedlist(tx,ty,tpx,tpy))
                findpathback
                Return True
            Else
                removefromopenlist(tx,ty)
                olmap[tx][ty] = 0
                clmap[tx][ty] = 1
                cl.AddLast(New closedlist(tx,ty,tpx,tpy))
                For Local i:Int=0 Until xstep.Length
                    Local x:Int=xstep[i]
                    Local y:Int=ystep[i]
                    newx = tx+x
                    newy = ty+y
                    If newx>=0 And newy>=0 And newx<mapwidth And newy<mapheight
                    If olmap[newx][newy] = 0
                    If clmap[newx][newy] = 0
                        olmap[newx][newy] = 1
                        Local gg = map[newx][newy]+1
                        Local hh = distance(newx,newy,ex,ey)
                        Local ff = gg+hh
                        ol.AddLast(New openlist(newx,newy,ff,gg,hh,tx,ty))
                    End If
                    End If
                    End If
                Next
            End If
        Wend
        Return False
    End Method

    Method drawpath:Void()
        Local cnt:Int=1
        For Local i:=Eachin path
            SetColor 255,255,0
            DrawOval i.x*mymap.tilewidth,i.y*mymap.tileheight,4,4
            SetColor 255,255,255
            DrawText cnt,i.x*mymap.tilewidth,i.y*mymap.tileheight
            cnt+=1
        Next
    End Method
    ' Here we calculate back from the end back to the
    ' start and create the path list.
    Method findpathback:Bool()
        Local x=ex
        Local y=ey
        path.AddFirst(New pathnode(x,y))
        Repeat
            For Local i:=Eachin cl
                If i.x = x And i.y = y
                    x = i.px
                    y = i.py
                    path.AddFirst(New pathnode(x,y))
                End If
            Next
            If x = sx And y = sy Then Return True
        Forever    
    End Method


    Method removefromopenlist:Void(x1:Int,y1:Int)
        For Local i:=Eachin ol
            If i.x = x1 And i.y = y1
                ol.Remove i
                Exit    
            End If
        Next
    End Method
    
    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function


End Class

Class map
    Field mapwidth:Int
    Field mapheight:Int
    Field screenwidth:Int
    Field screenheight:Int
    Field tilewidth:Float
    Field tileheight:Float
    Field map:Int[][]
    Field covermap:Int[][]
    Method New(screenwidth:Int,screenheight:Int,mapwidth:Int,mapheight:Int)
        Self.screenheight = screenheight
        Self.screenwidth = screenwidth
        Self.mapwidth = mapwidth
        Self.mapheight = mapheight
        tilewidth = Float(screenwidth) / Float(mapwidth)
        tileheight = Float(screenheight) / Float(mapheight)
        map = New Int[mapwidth][]
        covermap = New Int[mapwidth][]
        For Local i:Int=0 Until mapwidth
            map[i] = New Int[mapheight]
            covermap[i] = New Int[mapheight]
        Next
        makemap(10)
    End Method

    Method makemap:Void(numobstacles:Int)
        For Local y=0 Until mapheight
        For Local x=0 Until mapwidth
            map[x][y] = 0
        Next
        Next
        ' Here we create short lines on the map
        ' and sometimes draw some random blocks near them.
        For Local i:Int=0 Until numobstacles
            Local x1:Int=Rnd(4,mapwidth-4)
            Local y1:Int=Rnd(4,mapheight-4)
            Local dist:Int=Rnd(3,5)
            Local angle:Int=Rnd(0,360)
            Local x2:Float=x1
            Local y2:Float=y1
            While dist >= 0
                x2 += Cos(angle) * 1
                y2 += Sin(angle) * 1
                dist -= 1
                If x2<0 Or y2<0 Or x2>=mapwidth Or y2>=mapheight Then continue
                map[x2][y2] = 1000
'                If Rnd(10) < 2 Then
'                    If x2>2 And x2<mymap.mapwidth-2 And y2>2 And y2<mymap.mapheight-2 Then
'                        map[x2+Rnd(-1,1)][y2+Rnd(-1,1)] = 10
'                    end if
'                End If
            Wend            
        Next
    End Method

    Method mapcollide:Bool(x:Int,y:Int,w:Int,h:Int)
        Local lefttopx:Int        =((x)/tilewidth)
        Local lefttopy:Int        =((y)/tileheight)
        Local righttopx:Int        =((x+w)/tilewidth)
        Local righttopy:Int        =((y)/tileheight)
        Local leftbottomx:Int    =((x)/tilewidth)
        Local leftbottomy:Int    =((y+h)/tileheight)
        Local rightbottomx:Int    =((x+w)/tilewidth)                                                
        Local rightbottomy:Int    =((y+h)/tileheight)
        If lefttopx < 0 Or lefttopx >= mapwidth Then Return True
        If lefttopy < 0 Or lefttopy >= mapheight Then Return True
        If righttopx < 0 Or righttopx >= mapwidth Then Return True
        If righttopy < 0 Or righttopy >= mapheight Then Return True
        If leftbottomx < 0 Or leftbottomx >= mapwidth Then Return True
        If leftbottomy < 0 Or leftbottomy >= mapheight Then Return True
        If rightbottomx < 0 Or rightbottomx >= mapwidth Then Return True
        If rightbottomy < 0 Or rightbottomy >= mapheight Then Return True
        
        If map[lefttopx][lefttopy] <> 0 Then Return True
        If map[righttopx][righttopy] <> 0 Then Return True
        If map[leftbottomx][leftbottomy] <> 0 Then Return True
        If map[rightbottomx][rightbottomy] <> 0 Then Return True                        
        Return False
    End Method

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

    Method drawcovermap:Void()
        For Local y=0 Until mapheight
        For Local x=0 Until mapwidth
            If covermap[x][y] = 1
                SetColor 0,15,0
                DrawOval x*mymap.tilewidth,y*mymap.tileheight,tilewidth,tileheight
            End If
        Next
        Next        
    End Method

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

    
End Class

' The open list used by the astar
Class openlist
    Field x:Int
    Field y:Int
    Field f:Int
    Field g:Int
    Field h:Int
    Field px:Int
    Field py:Int
    Method New(    x:Int=0,y:Int=0,f:Int=0,
                g:Int=0,h:Int=0,px:Int=0,py:Int=0)
        Self.x=x
        Self.y=y
        Self.f=f
        Self.g=g
        Self.h=h
        Self.px=px
        Self.py=py
    End Method
End Class

' The closed list used by the astar
Class closedlist
    Field x:Int
    Field y:Int
    Field px:Int
    Field py:Int 
    Method New(x:Int,y:Int,px:Int,py:Int)
        Self.x = x
        Self.y = y
        Self.px = px
        Self.py = py
    End Method
End Class
' the pathnodes (x and y variables)
' used by the astar
Class pathnode
    Field x:Int
    Field y:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
    End Method
End Class

Global mymap:map
Global myastar:astar
Global myplayer:player
Global mybullet:List<bullet> = New List<bullet>
Global myenemy:List<enemy> = New List<enemy>

Class MyGame Extends App
    Field playerwins:Int
    Field enemywins:Int
    Method OnCreate()
        Seed = GetDate[4] * GetDate[5]
        SetUpdateRate(60)
        ' Create a new map
        mymap = New map(DeviceWidth(),DeviceHeight(),30,30)
        myastar = New astar()
        myplayer = New player()
        For Local i:Int=0 Until 10
            myenemy.AddLast(New enemy())
        Next
    End Method
    Method OnUpdate()        
        myplayer.update()
        
        For Local i:=Eachin myenemy
            i.update()
        Next
        For Local i:=Eachin myenemy
            If i.deleteme = True Then myenemy.Remove(i)
        Next

        
        For Local i:=Eachin mybullet
            i.update()
        Next
        For Local i:=Eachin mybullet
            If i.deleteme = True Then mybullet.Remove(i)
        Next


        ' if no more enemies then reset level
        If myenemy.IsEmpty Or myplayer.died Or KeyHit(KEY_TILDE)
            If myplayer.died Then enemywins+=1 
            If myenemy.IsEmpty Then playerwins+=1
            mymap = New map(DeviceWidth(),DeviceHeight(),30,30)
            myastar = New astar()
            myenemy = New List<enemy>
            mybullet = New List<bullet>
            myplayer = New player()
            For Local i:Int=0 Until 10
                myenemy.AddLast(New enemy())
            Next
            
        End If

    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        mymap.drawmap()        
        mymap.drawcovermap()
        For Local i:=Eachin myenemy
            i.draw()
        Next

        For Local i:=Eachin mybullet
            i.draw()
        Next
        myplayer.draw()
        'drawdebug
        SetColor 255,255,255
        DrawText "AI - 'Taking Cover' Locations - Example.`(Tilde = new level)",0,DeviceHeight-15
        DrawText "Controls - cursor u/d/l/r and F - fire",0,15
        DrawText "Matches Player Wins : " + playerwins + " vs Enemy Wins : " + enemywins,DeviceWidth/2,0,.5,0
    End Method
End Class


Function drawdebug()
        SetColor 255,255,255
       For Local i:=Eachin myenemy
            i.drawpath()
        Next
        Return
        Scale(.7,.7)
        For Local y:Int=0 Until mymap.mapwidth
        For Local x:Int=0 Until mymap.mapheight
            DrawText myastar.map[x][y],(x*mymap.tilewidth)*1.4,(y*mymap.tileheight)*1.4
        Next
        Next
End Function

Function Main()
    New MyGame()
End Function

Monkey-X - Astar Pathfinding - Object Oriented - code example


' New Object oriented version of my Astar Code.

Import mojo

Class astar
    Field mapwidth:Int,mapheight:Int
    Field sx:Int,sy:Int
    Field ex:Int,ey:Int
    Field olmap:Int[][]
    Field clmap:Int[][]
    Field map:Int[][]
    Field ol:List<openlist> = New List<openlist>
    Field cl:List<closedlist> = New List<closedlist>
    Field path:List<pathnode> = New List<pathnode>
    Method New()
        mapwidth = mymap.mapwidth
        mapheight = mymap.mapheight
        olmap = New Int[mapwidth][]
        clmap = New Int[mapwidth][]
        map = New Int[mapwidth][]
        For Local i:Int=0 Until mapwidth
            olmap[i] = New Int[mapheight]
            clmap[i] = New Int[mapheight]
            map[i] = New Int[mapheight]
        Next
        ' Copy the map into the astar class map
        For Local y:=0 Until mapheight
        For Local x:=0 Until mapwidth
            map[x][y] = mymap.map[x][y]
        Next
        Next
    End Method
    ' This creates the map and copies the 
    ' path in the path list
    Method findpath:Bool(sx:Int,sy:Int,ex:Int,ey:Int)
        If sx = ex And sy = ey Then Return False
        Self.sx = sx
        Self.sy = sy
        Self.ex = ex
        Self.ey = ey
        For Local y=0 Until mapheight
        For Local x=0 Until mapwidth
            olmap[x][y] = 0
            clmap[x][y] = 0
        Next
        Next
        ol.Clear
        cl.Clear
        path.Clear
        ol.AddFirst(New openlist(sx,sy))
        Local tx:Int
        Local ty:Int
        Local tf:Int
        Local tg:Int
        Local th:Int
        Local tpx:Int
        Local tpy:Int
        Local newx:Int
        Local newy:Int
        Local lowestf:Int
        olmap[sx][sy] = 1
        While ol.IsEmpty() = False
            lowestf = 100000
            For Local i:=Eachin ol
                If i.f < lowestf
                    lowestf = i.f
                    tx = i.x
                    ty = i.y
                    tf = i.f
                    tg = i.g
                    th = i.h
                    tpx = i.px
                    tpy = i.py
                End If
            Next
            If tx = ex And ty = ey
                cl.AddLast(New closedlist(tx,ty,tpx,tpy))
                findpathback
                Return True
            Else
                removefromopenlist(tx,ty)
                olmap[tx][ty] = 0
                clmap[tx][ty] = 1
                cl.AddLast(New closedlist(tx,ty,tpx,tpy))
                For Local y=-1 To 1
                For Local x=-1 To 1
                    newx = tx+x
                    newy = ty+y
                    If newx>=0 And newy>=0 And newx<mapwidth And newy<mapheight
                    If olmap[newx][newy] = 0
                    If clmap[newx][newy] = 0
                        olmap[newx][newy] = 1
                        Local gg = map[newx][newy]+1
                        Local hh = distance(newx,newy,ex,ey)
                        Local ff = gg+hh
                        ol.AddLast(New openlist(newx,newy,ff,gg,hh,tx,ty))
                    End If
                    End If
                    End If
                Next
                Next
            End If
        Wend
        Return False
    End Method

    Method drawpath:Void()
        Local cnt:Int=1
        For Local i:=Eachin path
            SetColor 255,255,0
            DrawOval i.x*mymap.tilewidth,i.y*mymap.tileheight,4,4
            SetColor 255,255,255
            DrawText cnt,i.x*mymap.tilewidth,i.y*mymap.tileheight
            cnt+=1
        Next
    End Method
    ' Here we calculate back from the end back to the
    ' start and create the path list.
    Method findpathback:Bool()
        Local x=ex
        Local y=ey
        path.AddFirst(New pathnode(x,y))
        Repeat
            For Local i:=Eachin cl
                If i.x = x And i.y = y
                    x = i.px
                    y = i.py
                    path.AddFirst(New pathnode(x,y))
                End If
            Next
            If x = sx And y = sy Then Return True
        Forever    
    End Method


    Method removefromopenlist:Void(x1:Int,y1:Int)
        For Local i:=Eachin ol
            If i.x = x1 And i.y = y1
                ol.Remove i
                Exit    
            End If
        Next
    End Method
    
    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function


End Class

Class map
    Field mapwidth:Int
    Field mapheight:Int
    Field screenwidth:Int
    Field screenheight:Int
    Field tilewidth:Float
    Field tileheight:Float
    Field map:Int[][]
    Method New(screenwidth:Int,screenheight:Int,mapwidth:Int,mapheight:Int)
        Self.screenheight = screenheight
        Self.screenwidth = screenwidth
        Self.mapwidth = mapwidth
        Self.mapheight = mapheight
        tilewidth = Float(screenwidth) / Float(mapwidth)
        tileheight = Float(screenheight) / Float(mapheight)
        map = New Int[mapwidth][]
        For Local i:Int=0 Until mapwidth
            map[i] = New Int[mapheight]
        Next
        makemap()
    End Method

    Method makemap:Void()
        For Local y=0 Until mapheight
        For Local x=0 Until mapwidth
            map[x][y] = 0
        Next
        Next
        Local lowest = 0
        While lowest < 13
            Local x1 = Rnd(mapwidth)
            Local y1 = Rnd(mapheight)
            Local radius = Rnd(3,6)
            For Local y2=-radius To radius
            For Local x2=-radius To radius
                If ((x2*x2)+(y2*y2)) <= radius*radius+radius*0.8
                    Local x3 = x1+x2
                    Local y3 = y1+y2
                    If x3>=0 And y3>=0 And x3<mapwidth And y3<mapheight
                        map[x3][y3]=map[x3][y3]+1
                        If map[x3][y3] > lowest Then lowest = map[x3][y3]
                    End If
                End If
            Next
            Next
        Wend
    End Method

    Method drawmap:Void()
        For Local y=0 Until mapheight
        For Local x=0 Until mapwidth
            SetColor 0,map[x][y]*10,0
            DrawRect x*tilewidth,y*tileheight,tilewidth,tileheight
        Next
        Next
    End Method
    
End Class

' The open list used by the astar
Class openlist
    Field x:Int
    Field y:Int
    Field f:Int
    Field g:Int
    Field h:Int
    Field px:Int
    Field py:Int
    Method New(    x:Int=0,y:Int=0,f:Int=0,
                g:Int=0,h:Int=0,px:Int=0,py:Int=0)
        Self.x=x
        Self.y=y
        Self.f=f
        Self.g=g
        Self.h=h
        Self.px=px
        Self.py=py
    End Method
End Class

' The closed list used by the astar
Class closedlist
    Field x:Int
    Field y:Int
    Field px:Int
    Field py:Int 
    Method New(x:Int,y:Int,px:Int,py:Int)
        Self.x = x
        Self.y = y
        Self.px = px
        Self.py = py
    End Method
End Class
' the pathnodes (x and y variables)
' used by the astar
Class pathnode
    Field x:Int
    Field y:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
    End Method
End Class

Global mymap:map
Global myastar:astar

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(1)
        ' Create a new map
        mymap = New map(DeviceWidth(),DeviceHeight(),30,30)
        ' Initiate the astar. Here the map from the mymap
        ' is copied into. Recreate this everytime the map is 
        ' modified..
        ' the map from the mymap should contain the heights/terrain
        ' costs. A tile with a high value is less likely to be chosen.
        myastar = New astar()
    End Method
    Method OnUpdate()        
        ' create 2 unique start and end coordinates
        Local exitloop:Bool=False
        Local sx:Int,sy:Int,ex:Int,ey:Int
        While exitloop = False    
            sx = Rnd(mymap.mapwidth)
            sy = Rnd(mymap.mapheight)
            ex = Rnd(mymap.mapwidth)
            ey = Rnd(mymap.mapheight)
            If sx <> ex And sy <> ey
                exitloop = True
            End If
        Wend
        ' Find/create the path
        myastar.findpath(sx,sy,ex,ey)
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        mymap.drawmap()        
        myastar.drawpath()
        SetColor 255,255,255
        DrawText "a Star Pathfinding example",0,0
    End Method
End Class

Function Main()
    New MyGame()
End Function

Wednesday, October 11, 2017

Monkey-X - Player vs Monsters on Random Map - code example


'Based on the game Legend of Pandora.

Import mojo

Global tilewidth:Int=10
Global tileheight:Int=10

Class map
    Field tilewidth:Float
    Field tileheight:Float
    Field mapwidth:Int
    Field mapheight:Int
    Field screenwidth:Int
    Field screenheight:Int
    Field map:Int[][]
    Method New(    screenwidth:Int,
                screenheight:Int,
                mapwidth:Int,
                mapheight:Int)
        Self.screenwidth = screenwidth
        Self.screenheight = screenheight
        Self.mapwidth = mapwidth
        Self.mapheight = mapheight
        Self.tilewidth = Float(screenwidth)/Float(mapwidth)
        Self.tileheight = Float(screenheight)/Float(mapheight)
        map = New Int[mapwidth][]
        For Local i=0 Until mapwidth
            map[i] = New Int[mapheight]
        Next
        map[mapwidth/2][mapheight/2] = 3 ' 3 is a door
        makemap
    End Method
    Method makemap()
        Local timeout:Int
        While timeout<(mapwidth*mapheight)*20
            timeout+=1
            Local x:Int=Rnd(11,mapwidth-11)
            Local y:Int=Rnd(11,mapheight-11)
            If map[x][y] = 3
                makeroom(x,y)
            End If
        Wend    
        'here we turn doors into walls
        'if they should be walls
        For Local y1=1 Until mapheight-1
        For Local x1=1 Until mapwidth-1
            If map[x1][y1] = 3
            Local cnt:Int=0
            For Local y2=y1-1 To y1+1
            For Local x2=x1-1 To x1+1
                If map[x2][y2] = 2 Then cnt+=1
            Next
            Next
            If cnt>3 Then map[x1][y1] = 2
            End If
        Next
        Next
        'here we turn doors into walls if they
        ' touch tiles that are nothing (0)
        For Local y1=1 Until mapheight-1
        For Local x1=1 Until mapwidth-1
            If map[x1][y1] = 3
            Local cnt:Int=0
            For Local y2=y1-1 To y1+1
            For Local x2=x1-1 To x1+1
                If map[x2][y2] = 0 Then cnt+=1
            Next
            Next
            If cnt>0 Then map[x1][y1] = 2
            End If
        Next
        Next        
        'here we turn the doors into floors
        For Local y1=0 Until mapheight
        For Local x1=0 Until mapwidth
            If map[x1][y1] = 3 Then map[x1][y1] = 1
        Next
        Next
    End Method
    Method makeroom(x:Int,y:Int)
        Local side:String
        If map[x][y-1] = 0
            side="up"
        Elseif map[x+1][y] = 0
            side="right"
        Elseif map[x][y+1] = 0
            side="down"
        Elseif map[x-1][y] = 0
            side="left"
        End If        
        Local w:Int=Rnd(5,10)
        Local h:Int=Rnd(5,10)
        If side="up"
            Local x1:Int=x-w/2
            Local y1:Int=y-h
            If roomfits(x1,y1,w,h)
                insertroom(x1,y1,w,h+1)
                'door up
                map[x1+Rnd(2,w-2)][y1] = 3
                ' door right
                map[x1+w-1][y1+Rnd(2,h-2)] = 3
                'door left
                map[x1][y1+Rnd(2,h-2)] = 3
            End If                        
            
        End If
        If side="right"
            Local x1:Int=x+1
            Local y1:Int=y-h/2
            If roomfits(x1,y1,w,h)
                insertroom(x1-1,y1,w,h)
                'door up
                map[x1+Rnd(2,w-2)][y1] = 3
                'door down
                map[x1+Rnd(2,w-2)][y1+h-1] = 3
                ' door right
                map[x1+w-2][y1+Rnd(2,h-2)] = 3                
            End If
        End If
        If side="left"
            Local x1:Int=x-w
            Local y1:Int=y-h/2
            If roomfits(x1,y1,w,h)
                insertroom(x1,y1,w+1,h)
                'door up
                map[x1+Rnd(2,w-2)][y1] = 3
                'door down
                map[x1+Rnd(2,w-2)][y1+h-1] = 3                
                'door left
                map[x1][y1+Rnd(2,h-2)] = 3

            End If            
        End If
        If side="down"
            Local x1:Int=x-w/2
            Local y1:Int=y+1
            If roomfits(x1,y1,w,h)
                insertroom(x1,y1-1,w,h)
                'door down
                map[x1+Rnd(2,w-2)][y1+h-2] = 3                
                'door left
                map[x1][y1+Rnd(2,h-2)] = 3                
                ' door right
                map[x1+w-1][y1+Rnd(2,h-2)] = 3                

            End If                        
        End If
    End Method
    Method insertroom(x,y,w,h)
        For Local y2=y Until y+h
        For Local x2=x Until x+w
            If map[x2][y2] <> 3 Then map[x2][y2] = 2
        Next
        Next

        For Local y2=y+1 Until y+h-1
        For Local x2=x+1 Until x+w-1
            map[x2][y2] = 1
        Next
        Next
    End Method
    Method roomfits(x:Int,y:Int,w:Int,h:Int)
        For Local y1=y Until y+h
        For Local x1=x Until x+w
            If map[x1][y1] = 1 Then Return False
        Next
        Next
        Return True
    End Method
    Method draw()
        For Local y=0 Until mapheight
        For Local x=0 Until mapwidth
            Select map[x][y]
                Case 0
                Case 1'floor
                SetColor 100,100,100
                DrawRect     x*tilewidth,
                            y*tileheight,
                            tilewidth+1,
                            tileheight+1
                Case 2'wall
                SetColor 200,200,200
                DrawRect     x*tilewidth,
                            y*tileheight,
                            tilewidth+1,
                            tileheight+1
                Case 3'wall
                SetColor 244,244,0
                DrawRect     x*tilewidth,
                            y*tileheight,
                            tilewidth+1,
                            tileheight+1

            End Select
        Next
        Next
    End Method
End Class

Class enemy
    Field x:Float,y:Float
    Field ms:Float 'movement speed
    Field w:Int=mymap.tilewidth-8
    Field h:Int=mymap.tileheight-8
    Field hp:Int
    Field hpceil:Int
    Field direction:String="up" ' left/right/up/down
    Field current:Bool=False 'if being updated
    Field deleteme:Bool=False
    Method New()
        ' find a spot to place the new enemy
        Local exitloop:Bool=False
        Local cnt:Int=0
        While exitloop=False
            exitloop = True
            Local nx = Rnd(50,640-50)
            Local ny = Rnd(50,480-50)    
            Local mx:Int=nx/mymap.tilewidth        
            Local my:Int=ny/mymap.tileheight
            If mymap.map[mx][my] <> 1 Then exitloop = False
            For Local i:=Eachin myenemy
                If distance(nx,ny,i.x,i.y) < 30 Or distance(myplayer.x,myplayer.y,nx,ny) < 250-cnt
                    exitloop = False
                End If
            Next
            If exitloop = True Then
                x = nx
                y = ny
            End If
            cnt+=1
        Wend
        ' Here we set the movement speed
        ms = Rnd(.1,.5)
        ' Here we set the hitpoints
        hp = Rnd(1,50)
        ' the ceiling is what he has or had at start (powerbar)
        hpceil = hp
    End Method
    Method update()
        current=True
        ' store the old location
        Local oldx:Float=x
        Local oldy:Float=y
        ' move the enemy towards the player
        If collide(x+1,y) = False And x < myplayer.x Then 
            x+=ms
            direction = "right"
        End If
        If collide(x-1,y) = False And x > myplayer.x Then 
            x-=ms
            direction = "left"
        End If
        If collide(x,y+1) = False And y < myplayer.y Then 
            y+=ms
            direction = "down"
        End If
        If collide(x,y-1) = False And y > myplayer.y Then 
            y-=ms
            direction = "up"
        End If
        untangle()
        current=False
    End Method
    ' if the enemies are inside of each other
    ' then move them apart
    Method untangle()
        For Local i:=Eachin myenemy
            If i.current=False
                If distance(i.x,i.y,x,y) < w
                    Local a:Int
                    a = getangle(i.x,i.y,x,y)
                    Local nx:Float=x
                    Local ny:Float=y
                    nx += Cos(a)*1
                    ny += Sin(a)*1
                    Local mx:Int=nx/mymap.tilewidth
                    Local my:Int=ny/mymap.tileheight
                    If mymap.map[mx][my] = 1
                        x = nx
                        y = ny
                    End If
                End If
            End If
        Next
    End Method
    Method draw()
        SetColor 255,255,0
        DrawOval x-w/2,y-w/2,w,w
        'powerbar
        Local current:Float=(Float(w)/Float(hpceil))*hp
        
        SetColor 0,0,0
        DrawRect x-w/2,y+w/2,w,5
        SetColor 255,0,0
        DrawRect x-w/2,y+1+w/2,current,3
    End Method
    Method collide:Bool(xx:Int,yy:Int)
        For Local i:=Eachin myenemy
            If i.current = False
                If distance(xx,yy,i.x,i.y) < w Then Return True
            End If
        Next
        Local mx:Int=xx/mymap.tilewidth
        Local my:Int=yy/mymap.tileheight
        If mymap.map[mx][my] <> 1 Then Return true
        Return False
    End Method
    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function    
    Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Local dx = x2 - x1
        Local dy = y2 - y1
        Return ATan2(dy,dx)+360 Mod 360
    End Function        
End Class


Class player
    Field x:Float,y:Float
    Field w:Int=mymap.tilewidth-8
    Field h:Int=mymap.tileheight-8
    Field wx:Int,wy:Int
    Field direction:String="up" ' up/left/down/right
    Field weapondamage:Int=3
    Field swing:Bool=False
    Field swingcountdown:Int=0
    Method New()
        Local exitloop:Bool=False
        While exitloop = False
            x = Rnd(640)
            y = Rnd(480)
            Local mx:Int=x/mymap.tilewidth
            Local my:Int=y/mymap.tileheight
            If mymap.map[mx][my] = 1 Then exitloop = True
        Wend

        direction = "up"
    End Method
    Method update()
        updatecontrols()
        weaponenemies()
    End Method
    Method weaponenemies()
        If swing = False Then Return
        For Local i:=Eachin myenemy
            If distance(i.x,i.y,wx,wy) < w+5
                'make sure the weapon does not hit throught 
                ' walls
                Local mx:Int=wx/mymap.tilewidth
                Local my:Int=wy/mymap.tileheight
                If mymap.map[mx][my] <> 1 Then Exit
                'distance with the enemy
                Local a:Int=getangle(wx,wy ,i.x,i.y)
                For Local ww:Int=0 Until w
                    Local nx:Float=i.x
                    Local ny:Float=i.y                    
                    nx += Cos(a) * 1
                    ny += Sin(a) * 1
                    Local mx:Int=nx/mymap.tilewidth
                    Local my:Int=ny/mymap.tileheight
                    If mymap.map[mx][my] = 1 Then
                        i.x = nx
                        i.y = ny
                    Else
                        Exit
                    End If
                Next
                i.hp -= weapondamage
                If i.hp<1 Then i.deleteme = True
            End If            
        Next
    End Method
    Method updatecontrols()
        ' store the location of the player
        Local oldx:Int=x
        Local oldy:Int=y
        'handle the movement
        If collide(x+1,y)=False And KeyDown(KEY_RIGHT) Then 
            x+=1
            direction = "right"
            swing=False
        End If
        If collide(x-1,y)=False And KeyDown(KEY_LEFT) Then 
            x-=1
            direction = "left"
            swing=False
        End If
        If collide(x,y-1)=False And KeyDown(KEY_UP) Then 
            y-=1
            direction = "up"
            swing=False
        End If
        If collide(x,y+1)=False And KeyDown(KEY_DOWN) Then 
            y+=1
            direction = "down"
            swing=False
        End If
        'Handle the weapon
        If swing = False
            If KeyDown(KEY_SPACE) Then 
                swing=True
                If direction = "left" Then wx=x-w ; wy=y
                If direction = "right" Then wx=x+w ; wy=y
                If direction = "up" Then wx=x ; wy=y-h
                If direction = "down" Then wx=x ; wy=y+h                
                swingcountdown = 20
            End If
        Else
            swingcountdown-=1
            If swingcountdown<0 Then swing=False
        End If
    End Method
    ' collide with map
    Method collide:Bool(xx:Int,yy:Int)
        Local mx:Int=xx/mymap.tilewidth
        Local my:Int=yy/mymap.tileheight
        If mymap.map[mx][my] <> 1 Then Return True
        Return False
    End Method
    Method draw()
        SetColor 255,100,0
        DrawOval x-w/2,y-w/2,w,w
        If swing = True
            'where does the swing graphic get drawn
            DrawOval wx-w/2,wy-w/2,w,w
        End If
    End Method
    Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Local dx = x2 - x1
        Local dy = y2 - y1
        Return ATan2(dy,dx)+360 Mod 360
    End Function        
    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function    

End Class


Global myplayer:player
Global myenemy:List<enemy> = New List<enemy>
Global mymap:map

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(60)
        mymap = New map(640,480,30,30)
        myplayer = New player()        
        'For Local i:=0 Until 10
        '    myenemy.AddLast(New enemy())
        'Next
    End Method
    Method OnUpdate()           
        myplayer.update() 
        ' update the enemies
        For Local i:=Eachin myenemy
            i.update()
        Next
        ' if enemy hitpoint below 1 then remove him from list
        For Local i:=Eachin myenemy
            If i.deleteme = True Then myenemy.Remove(i)
        Next

        If myenemy.IsEmpty
            Local ms:Int=Rnd(30,36)
            mymap = New map(640,480,ms,ms)
            myplayer = New player()         
            Local ecnt:Int=Rnd(2,10)
            For Local i:=0 Until ecnt
                myenemy.AddLast(New enemy())
            Next
        End If

    End Method
    Method OnRender()
        Cls 0,0,0
            
        mymap.draw()    
                
        For Local i:=Eachin myenemy
            i.draw()
        Next
        myplayer.draw()


        SetColor 255,255,255
        DrawText "Player vs Monsters on Random map",0,0
        DrawText "Space = Weapon , Cursor l/r/u/d = movement",0,20        
    End Method
End Class


Function Main()
    New MyGame()
End Function

Monkey-X - Player vs Monsters on Empty map - code example


' I programmed this after playing the game Legend of Pandora.


Import mojo

Class enemy
    Field x:Float,y:Float
    Field ms:Float 'movement speed
    Field w:Int=32
    Field h:Int=32
    Field hp:Int
    Field hpceil:Int
    Field direction:String="up" ' left/right/up/down
    Field current:Bool=False 'if being updated
    Field deleteme:Bool=False
    Method New()
        ' find a spot to place the new enemy
        Local exitloop:Bool=False
        While exitloop=False
            exitloop = True
            Local nx = Rnd(50,640-50)
            Local ny = Rnd(50,480-50)            
            For Local i:=Eachin myenemy
                If distance(nx,ny,i.x,i.y) < 30 Or distance(myplayer.x,myplayer.y,nx,ny) < 250
                    exitloop = False
                End If
            Next
            If exitloop = True Then
                x = nx
                y = ny
            End If
        Wend
        ' Here we set the movement speed
        ms = Rnd(.1,.5)
        ' Here we set the hitpoints
        hp = Rnd(1,50)
        ' the ceiling is what he has or had at start (powerbar)
        hpceil = hp
    End Method
    Method update()
        current=True
        ' store the old location
        Local oldx:Float=x
        Local oldy:Float=y
        ' move the enemy towards the player
        If collide(x+1,y) = False And x < myplayer.x Then 
            x+=ms
            direction = "right"
        End If
        If collide(x-1,y) = False And x > myplayer.x Then 
            x-=ms
            direction = "left"
        End If
        If collide(x,y+1) = False And y < myplayer.y Then 
            y+=ms
            direction = "down"
        End If
        If collide(x,y-1) = False And y > myplayer.y Then 
            y-=ms
            direction = "up"
        End If
        untangle()
        current=False
    End Method
    Method untangle()
        For Local i:=Eachin myenemy
            If i.current=False
                If distance(i.x,i.y,x,y) < w
                    Local a:Int
                    a = getangle(i.x,i.y,x,y)
                    x += Cos(a)*1
                    y += Sin(a)*1
                End If
            End If
        Next
    End Method
    Method draw()
        SetColor 255,255,0
        DrawOval x-w/2,y-w/2,w,w
        'powerbar
        Local current:Float=(Float(w)/Float(hpceil))*hp
        
        SetColor 0,0,0
        DrawRect x-w/2,y+w/2,w,5
        SetColor 255,0,0
        DrawRect x-w/2,y+1+w/2,current,3
    End Method
    Method collide:Bool(xx:Int,yy:Int)
        For Local i:=Eachin myenemy
            If i.current = False
                If distance(xx,yy,i.x,i.y) < w Then Return True
            End If
        Next
        Return False
    End Method
    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function    
    Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Local dx = x2 - x1
        Local dy = y2 - y1
        Return ATan2(dy,dx)+360 Mod 360
    End Function        
End Class


Class player
    Field x:Float,y:Float
    Field w:Int=32
    Field h:Int=32
    Field wx:Int,wy:Int
    Field direction:String="up" ' up/left/down/right
    Field weapondamage:Int=3
    Field swing:Bool=False
    Field swingcountdown:Int=0
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
        direction = "up"
    End Method
    Method update()
        updatecontrols()
        weaponenemies()
    End Method
    Method weaponenemies()
        If swing = False Then Return
        For Local i:=Eachin myenemy
            If distance(i.x,i.y,wx,wy) < 48
                Local a:Int=getangle(wx,wy ,i.x,i.y)
                i.x += Cos(a) * 32
                i.y += Sin(a) * 32
                i.hp -= weapondamage
                If i.hp<1 Then i.deleteme = True
            End If            
        Next
    End Method
    Method updatecontrols()
        ' store the location of the player
        Local oldx:Int=x
        Local oldy:Int=y
        'handle the movement
        If KeyDown(KEY_RIGHT) Then 
            x+=1
            direction = "right"
            swing=False
        End If
        If KeyDown(KEY_LEFT) Then 
            x-=1
            direction = "left"
            swing=False
        End If
        If KeyDown(KEY_UP) Then 
            y-=1
            direction = "up"
            swing=False
        End If
        If KeyDown(KEY_DOWN) Then 
            y+=1
            direction = "down"
            swing=False
        End If
        'Handle the weapon
        If swing = False
            If KeyDown(KEY_SPACE) Then 
                swing=True
                If direction = "left" Then wx=x-w ; wy=y
                If direction = "right" Then wx=x+w ; wy=y
                If direction = "up" Then wx=x ; wy=y-h
                If direction = "down" Then wx=x ; wy=y+h                
                swingcountdown = 20
            End If
        Else
            swingcountdown-=1
            If swingcountdown<0 Then swing=False
        End If
    End Method
    Method draw()
        SetColor 255,100,0
        DrawOval x-w/2,y-w/2,w,w
        If swing = True
            'where does the swing graphic get drawn
            DrawOval wx-w/2,wy-w/2,w,w
        End If
    End Method
    Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Local dx = x2 - x1
        Local dy = y2 - y1
        Return ATan2(dy,dx)+360 Mod 360
    End Function        
    Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
        Return Abs(x2-x1)+Abs(y2-y1)
    End Function    

End Class


Global myplayer:player
Global myenemy:List<enemy> = New List<enemy>

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(60)
        myplayer = New player(DeviceWidth()/2,DeviceHeight()/2)
        'For Local i:=0 Until 10
        '    myenemy.AddLast(New enemy())
        'Next
    End Method
    Method OnUpdate()           
        myplayer.update() 
        ' update the enemies
        For Local i:=Eachin myenemy
            i.update()
        Next
        ' if enemy hitpoint below 1 then remove him from list
        For Local i:=Eachin myenemy
            If i.deleteme = True Then myenemy.Remove(i)
        Next

        If myenemy.IsEmpty
            Local ecnt:Int=Rnd(2,10)
            For Local i:=0 Until ecnt
                myenemy.AddLast(New enemy())
            Next
        End If

    End Method
    Method OnRender()
        Cls 0,0,0
                
        For Local i:=Eachin myenemy
            i.draw()
        Next
        myplayer.draw()


        SetColor 255,255,255
        DrawText "Player vs Monsters on empty map",0,0
        DrawText "Space = Weapon , Cursor l/r/u/d = movement",0,20        
    End Method
End Class


Function Main()
    New MyGame()
End Function