Monday, December 14, 2015

Monkey-X - Maze Generator - code example


I think I fixed the previous mistakes in the maze generator.

Import mojo

Global maxwidth:Int=60
Global maxheight:Int=40

Class maze
    Field map:Bool[][]
    Field w:Int,h:Int
    Field dirx:Int[] = [0,1,0,-1]
    Field diry:Int[] = [-1,0,1,0]
    Field rd:Int
    Method New(w:Int,h:Int,rd:Int)
        Self.w = w
        Self.h = h
        map = New Bool[w][]
        For Local i = 0 Until w
            map[i] = New Bool[h]
        Next
        Self.rd=rd
        makemaze
    End Method
    Method makemaze()
        Local count:Int=0
        For Local i=0 Until w*h
            Local x = 2 + (Int(((w - 2) * Rnd) / 2) * 2)
            Local y = 2 + (Int(((h - 2) * Rnd) / 2) * 2)            
            If count=0 Then map[x][y] = True
            Local dir:Int=Rnd(0,4)            
               If map[x][y] = True
                While spacetaken(x+(dirx[dir]*2),y+(diry[dir]*2)) = False
                   map[x][y] = True
                   map[x+dirx[dir]][y+diry[dir]] = True
                   x+=dirx[dir]
                   y+=diry[dir]
                   If Rnd(0,rd) < rd/10 Then
                       dir=Rnd(0,4)
                   End If
                   Wend
            End If
        Next
    End Method
    Method spacetaken:Bool(x:Int,y:Int)
        If x>-1 And y>-1 And x<w And y<h
            Return map[x][y]
        End If
        Return True
    End Method
    Method draw()        
        Local tw:Float=DeviceWidth()/Float(w)
        Local th:Float=DeviceHeight()/Float(h)
        For Local y=0 Until h
        For Local x=0 Until w
            If map[x][y] = False
                Local d:Int                
                Local dx:Int=x*tw
                Local dy:Int=y*th                
                d = distance(dx,dy,320,200)
                d=d/2.5
                SetColor 255-d,(255-d)/2,(255-d)/2
                DrawRect dx,dy,tw+1,th+1
            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

Global mymaze:maze = New maze(    maxwidth,
                                maxheight,
                                Rnd(0,40))
                                
Class MyGame Extends App
    Field w:Int,h:Int
    Field rd:Int
    field cnt:Int
    Method OnCreate()
        SetUpdateRate(10)
        Local date := GetDate()
        ' set the random seed to
        ' current second
        Seed = date[5]        
    End Method
    Method OnUpdate()   
        cnt+=1
           If KeyHit(KEY_RIGHT) Or cnt>30
               cnt=0
            w = Rnd(20,maxwidth)
            h = Rnd(15,maxheight)
            rd = Rnd(0,40)
            If Rnd(0,10) < 3
                w=Rnd(50,200)
                h=Rnd(50,150)
            End If
            mymaze = New maze(w,h,rd)
        End If
    End Method
    Method OnRender()
        Cls 0,0,0 
        mymaze.draw
        SetColor 0,0,0
        DrawRect 0,0,DeviceWidth()/2,15
        SetColor 255,255,255
        DrawText     "Maze width :"+w+
                    " height "+h+
                    " and rdness "+
                    rd,10,0
    End Method
End Class


Function Main()
    New MyGame()
End Function

Monkey-X - Another Map generator (failed maze generator) - code example


Import mojo


Class maze
    Field map:Bool[][]
    Field w:Int,h:Int
    Field dirx:Int[] = [0,1,0,-1]
    Field diry:Int[] = [-1,0,1,0]
    Field rd:Int
    Field ds:int
    Method New(w:Int,h:Int,rd:Int,ds:Int)
        Self.w = w
        Self.h = h
        map = New Bool[w][]
        For Local i = 0 Until w
            map[i] = New Bool[h]
        Next
        Self.rd=rd
        Self.ds=ds
        makemaze
    End Method
    Method makemaze()
        Local count:Int=0
        For Local i=0 Until (w*h)/ds
            Local x = 2 + (Int(((w - 2) * Rnd) / 2) * 2)
            Local y = 2 + (Int(((h - 2) * Rnd) / 2) * 2)            
            If count=0 Then map[x][y] = True
            Local dir:Int=Rnd(0,4)            
               While spacetaken(x+(dirx[dir]*2),y+(diry[dir]*2)) = False
                   If Rnd(rd)<10 Then dir=Rnd(0,4)
                While spacetaken(x+(dirx[dir]*2),y+(diry[dir]*2)) = True
                       dir=Rnd(0,4)
                   Wend
                   map[x][y] = True
                   map[x+dirx[dir]][y+diry[dir]] = True
                   x+=dirx[dir]
                   y+=diry[dir]
            Wend
        Next
    End Method
    Method spacetaken:Bool(x:Int,y:Int)
        If x>-1 And y>-1 And x<w And y<h
            Return map[x][y]
        End If
        Return True
    End Method
    Method draw()
        Local tw:Float=DeviceWidth()/Float(w)
        Local th:Float=DeviceHeight()/Float(h)
        For Local y=0 Until h
        For Local x=0 Until w
            If map[x][y] = True
                SetColor 255,255,255
                DrawRect x*tw,y*th,tw+1,th+1
            End If
        Next
        Next
    End Method
End Class

Global mymaze:maze = New maze(    Rnd(15,60),
                                Rnd(15,60),
                                Rnd(0,100),
                                Rnd(1,20))

Class MyGame Extends App
    Field time:Int=0
    Field w:Int,h:Int
    Field rd:Int
    Field ds:Int
    Method OnCreate()
        SetUpdateRate(10)
        Local date := GetDate()
        ' set the random seed to
        ' current second
        Seed = date[5]        
    End Method
    Method OnUpdate()        
        time+=1
        If time>10
            w = Rnd(15,60)
            h = Rnd(15,60)
            rd = Rnd(0,100)
            ds = Rnd(1,20)
            mymaze = New maze(w,h,rd,ds)
            time=0
        End If
    End Method
    Method OnRender()
        Cls 0,0,0 
        mymaze.draw
        SetColor 0,0,0
        DrawRect 0,0,DeviceWidth(),15
        SetColor 255,255,255
        DrawText     "Maze width :"+w+
                    " height "+h+
                    " and rdness "+
                    rd+" and ds "+ds,10,0
    End Method
End Class


Function Main()
    New MyGame()
End Function

Sunday, December 13, 2015

Monkey-X - Sidefilling Heightmap method - Code Example


This code creates a drawing by drawing lines into the screen and increasing the image by one value on one side of the line. I saw this on a tutorial site once. I can't really remember if I did all the steps.

Import mojo

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


Class heightmap
    Field ol:List<openlist> = New List<openlist>
    Field h:Int,w:Int
    ' hold the heightmap
    Field hmap:Int[][]
    'hold the fillmap
    Field fmap:Int[][]
    Field x3:Int,y3:Int
    Field x4:Int,y4:Int
    Method New(w:Int,h:Int)
        Self.w = w
        Self.h = h
        hmap = New Int[w][]
        fmap = New Int[w][]
        For Local i = 0 Until w
            hmap[i] = New Int[h]
            fmap[i] = New Int[h]            
        Next
        makeheightmap        
    End Method
    Method makeheightmap()
        For Local i=0 Until 255
        Local startside:Int
        Local endside:Int
         Local exitloop:Bool=False
         While exitloop = False
             endside = Rnd(1,5)
             startside = Rnd(1,5)
             If endside<>startside Then
                 exitloop = True
             End If
         Wend         
         x3=Rnd(w)
         y3=Rnd(h)
         x4=Rnd(w)
         y4=Rnd(h)
         Select startside
             Case 1
             y3=0
             Case 2
             x3=w-1
             Case 3
             y3=h-1
             Case 4
             x3=0
         End Select
         Select endside
             Case 1
             y4=0
             Case 2
             x4=w-1
             Case 3
             y4=h-1
             Case 4
             x4=0
         End Select
         clearfmap()
         line(x3,y3,x4,y4)
         fillfmap()
         addhmap()
        Next
    End Method
    Method addhmap()
        For Local y=0 Until h
        For Local x=0 Until w
            hmap[x][y]+=fmap[x][y]
        Next
        Next
    End Method
    Method fillfmap()
        Local exitloop:Bool=False
        Local x1:Int,y1:Int
        While exitloop = False
            x1=Rnd(w)
            y1=Rnd(h)
            If fmap[x1][y1] = 0
                exitloop = True
            End If
        Wend
        ol.Clear
        ol.AddLast(New openlist(x1,y1))
        fmap[x1][y1]=1
        While ol.IsEmpty() = False
            For Local i:=Eachin ol

                Local tx:Int=i.x
                Local ty:Int=i.y
                
                If tx-1>-1
                If fmap[tx-1][ty] = 0
                    ol.AddLast(New openlist(tx-1,ty))
                    fmap[tx-1][ty] = 1
                End If
                End If

                If tx+1<w
                If fmap[tx+1][ty] = 0
                    ol.AddLast(New openlist(tx+1,ty))
                    fmap[tx+1][ty] = 1
                End If
                End If

                If ty-1>-1
                If fmap[tx][ty-1] = 0
                    ol.AddLast(New openlist(tx,ty-1))
                    fmap[tx][ty-1] = 1
                End If
                End If
                
                If ty+1<h
                If fmap[tx][ty+1] = 0
                    ol.AddLast(New openlist(tx,ty+1))
                    fmap[tx][ty+1] = 1
                End If
                End If
                ol.Remove i 
            Next
        Wend
    End Method
    Method line:Void(x1:Int,y1:Int,x2:Int,y2:Int)
        Local dx:Int, dy:Int, sx:Int, sy:Int, e:Int
         dx = Abs(x2 - x1)
          sx = -1
          If x1 < x2 Then sx = 1      
          dy = Abs(y2 - y1)
          sy = -1
          If y1 < y2 Then sy = 1
          If dx < dy Then 
              e = dx / 2 
          Else 
              e = dy / 2          
          End If
          Local exitloop:Bool=False
          While exitloop = False
            fmap[x1][y1] = 1
            If x1 = x2 
                If y1 = y2
                    exitloop = True
                End If
            End If
            If dx > dy Then
                x1 += sx ; e -= dy 
                  If e < 0 Then e += dx ; y1 += sy
            Else
                y1 += sy ; e -= dx 
                If e < 0 Then e += dy ; x1 += sx
            Endif
          Wend
    End Method
    Method clearfmap()
        For Local y=0 Until h
        For Local x=0 Until w
            fmap[x][y] = 0
        Next
        Next
    End Method
    Method draw()
        Local sx:Float=DeviceWidth()/Float(w)
        Local sy:Float=DeviceHeight()/Float(h)
        For Local y=0 Until h
        For Local x=0 Until w
            Local g:Int=hmap[x][y]
            SetColor g/1.5,g/1.5,g
            DrawRect x*sx,y*sy,sx+1,sy+1
        Next
        Next
    End Method
End Class

Global myhmap:heightmap = New heightmap(100,100)

Class MyGame Extends App
    Field refreshtime:Int=0
    Method OnCreate()
        SetUpdateRate(10)
    End Method
    Method OnUpdate()
        refreshtime+=1
        If refreshtime>10
            myhmap = New heightmap(100,100)
            refreshtime=0
        End If
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        myhmap.draw
    End Method
End Class


Function Main()
    New MyGame()
End Function

Monday, December 7, 2015

Monkey-X - RPG - Scrolling platformer - Mining.- Game Template


' version 7-12-2015.
' Template.
' Scrolling platformer with RPG features.
' Based on the scrolling platformer with vines
' template on my Monkey-X blog.
'
' The mapwidth variables can be set to large(200+) or 
' small(100*100) maps. There will be multiple mines
' placed and populated if there is enough space for them
' on the map. (This version runs fast enough on low
' end laptops with maps up to 320*240 - there currently
' is no LOD implemented.)
'
' Game :
' Travel down/explore the mine.
' Has mining eggs feature. Hunting for meat.
' Monsters lay eggs. Only one monster hatches from a egg
' if there are no other monsters nearby.
' Monsters/breeders do not attack.
' You can pick up the eggs. Kill the monsters for meat.
' You can place an egg on the ground and a monster could be
' hatched.
' Eggs can also spawn Deathwings and they attack/hurt you.
' You have health and if zero restarts the game.
' p - Place egg on the ground.
' t - Pick up egg from the ground.
' Space - Attack with spear.
' curs left/right/up - move and jump.
' 
' Thinking of adding automated machine gun nests that you 
' can place/move around and they kill the flying monsters.
'
' Mood of the game at the moment is : 
' Monsters live in an old abandoned mining area. You can 
' mine meat/eggs to make a profit. Monsters
' have been seen flying nearby mines attacking people.
'
'
Import mojo

Const mapwidth:Int=100
Const mapheight:Int=100
Const tilewidth:Int=32
Const tileheight:Int=32
Global mapx:Int=0
Global mapy:Int=0
Global mapsx:Int=0
Global mapsy:Int=0
Global maxdeathwings:Int=10

Class maptest
    Field tw:Int,th:Int
    Field w:Int,h:Int
    Field map:Int[][]
    Method New(w:Int,h:Int)
        Self.w = w
        Self.h = h
        tw = DeviceWidth()/w
        th = DeviceHeight()/h
        map = New Int[w][]
        For Local i=0 Until w
            map[i] = New Int[h]
        Next
        drawmaprect(0,0,w-1,15)
        For Local i=0 Until h
            map[1][i] = 0
            map[w-2][i] = 0
        Next
        Local x:Int=32
        While x<w-48
            makemine(x,15,Rnd(4,h/15))
            x+=Rnd(48,64)
        Wend
    End Method
    Method makemine(x:Int,y:Int,depth:Int)
        For Local mydepth=0 Until depth
        Local d1:Int=Rnd(8,16)'depth
        tunneldown(x,y,d1)
        y+=d1
        Local d2:Int=Rnd(1,4)'direction
        If d2=1 Then sidetunnel(x,y,"left")
           If d2=2 Then sidetunnel(x,y,"right")
           If d2=3 Then 
            sidetunnel(x,y,"left")
               sidetunnel(x,y,"right")
           End If
           Next
           For Local y1=0 Until y
               map[x][y1] = 2
           Next
    End Method
    Method sidetunnel(x:Int,y:Int,d:String)
        If d="left"
            Local width:Int=Rnd(5,10)
            drawmaprect(x-width+2,y,width,3)
            Local roomw:Int=Rnd(5,15)
            drawmaprect(x-width+2-roomw,y-1,roomw,5)
            For Local x1=0 Until roomw/3
                map[(x-width+2-roomw)+x1][y+4] = 3
                eggs.AddLast( New egg((x-width+2-roomw)+x1,y+4) )
            Next
'            a.AddLast(    New agent(    ((x-width+2-roomw))*tilewidth,
'                                    (y+4)*tileheight) )
        End If
        If d="right"
            Local width:Int=Rnd(5,10)
            drawmaprect(x-1,y,width,3)
            Local roomw:Int=Rnd(5,15)
            drawmaprect(x+width,y-1,roomw,5)        
            For Local x1=roomw Until roomw/1.5 Step -1
                map[(x+width)+x1][y+4] = 3
                eggs.AddLast( New egg((x+width)+x1,y+4) )
            Next            
'            a.AddLast( New agent(     (x+width+2)*tilewidth,
'                                     (y+4)*tileheight ))
        End If
    End Method
    Method tunneldown(x:Int,y:Int,d:Int)
        drawmaprect(x-2,y,4,d)
    End Method
    Method drawmaprect(x:Int,y:Int,w:Int,h:Int)
        For Local y1=y To y+h
        For Local x1=x To x+w
            map[x1][y1] = 1
        Next
        Next        
    End Method
    Method draw()
        For Local y=0 Until h
        For Local x=0 Until w
            If map[x][y] = 1
                SetColor 255,255,255
                DrawRect x*tw,y*th,tw,th
            End If
            If map[x][y] = 3
                SetColor 200,200,10
                DrawOval x*tw,y*th,tw,th
            End If            
        Next
        Next
    End Method
End Class

Class spear
    Field x:Float,y:Float
    Field w:Int=20
    Field h:Int=4
    Field d:String
    Field incx:Float
    Field active:Bool    
    Method New(x:Int,y:Int,d:String)
        Self.x = x
        Self.y = y
        Self.d = d
        incx = 3
        active = True
    End Method
    Method update()
        If active = False Then Return
        w+=incx
        incx-=0.5
        If     incx > 0
            killcreature
        End If
        If incx < -3 Then active = False
    End Method
    Method killcreature()
        For Local i:=Eachin dw
            If d="left" 
                If rectsoverlap(    i.x,i.y,32,32,
                                    x-32,y,32,32)
                    i.remove = True
                    myinven.meat+=1
                End If
            Else
                If rectsoverlap(    i.x,i.y,32,32,
                                    x+32,y,32,32)
                    i.remove = True
                    myinven.meat+=1
                End If
            End If
        Next

        For Local i:=Eachin a            
            If d="left" 
                If rectsoverlap(    i.x,i.y,32,32,
                                    x-32,y,32,32)
                    i.remove = True
                    myinven.meat+=1
                End If
            Else
                If rectsoverlap(    i.x,i.y,32,32,
                                    x+32,y,32,32)
                    i.remove = True
                    myinven.meat+=1
                End If
            End If
        Next
        For Local i:=Eachin a
            If i.remove=True
                a.Remove i
            End If
        Next
    End Method
    Method draw()
        If active = True
            SetColor 200,100,0
            If d = "right"
                DrawRect x+32,y+8,w,h
            Else
                DrawRect x-w,y+8,w,h    
            End If
        End If
    End Method
End Class

Class player    
    Field x:Float=0
    Field y:Float=0
    Field w:Int=32
    Field h:Int=32
    Field incy:Float=0
    Field isjumping:Bool = False
    Field facing:Int '0 = left , 1 = right
    Field jumpofvine:Bool=False
    Field jumpofvinetimeout:Int
    Field health:Int=10
    Method update()
        Local ox:Int=x
        Local oy:Int=y
        If pvc(0,0) = False Or jumpofvine = True Then regularmode
        If pvc(0,0) = True 
            If jumpofvine = False
                vinemode
            End If
        End If
        If KeyHit(KEY_SPACE)
            Local md:String
            If facing = 0 Then 
                md="left" 
            Else
                md="right"
            End If
            myspear = New spear(p.x,p.y,md)
        End If
        If KeyHit(KEY_T)
            Local offx:Int
            If p.facing=0 Then 
                offx=0
            Else
                offx=32
            End If
               Local cx = (p.x+offx)/tilewidth+mapx
            Local cy = (p.y)/tileheight+mapy
            If mymaptest.map[cx][cy] = 3
                mymaptest.map[cx][cy] = 1
                myinven.eggs+=1
                For Local i:=Eachin eggs
                    If i.x = cx And
                        i.y = cy
                        i.remove = True
                    End If
                Next
                For Local i:=Eachin eggs
                    If i.remove=True
                        eggs.Remove i
                    End If
                Next
            End If
        End If
        If KeyHit(KEY_P)
            If myinven.eggs > 0
               Local cx = (p.x)/tilewidth+mapx
            Local cy = (p.y)/tileheight+mapy
            If mymaptest.map[cx][cy] = 1
                mymaptest.map[cx][cy] = 3
                eggs.AddLast(New egg(cx,cy))
            End If            
            End If
            myinven.eggs-=1
        End If
    End Method
    Method movea(x1:Int,y1:Int)
        For Local i:=Eachin a
            i.x+=x1
            i.y+=y1
        Next
        For Local i:=Eachin dw
            i.x+=x1
            i.y+=y1
        Next        
    End Method
    Method vinemode()
        isjumping = False
        incy=0
        If KeyDown(KEY_J)
            jumpofvine = True
            jumpofvinetimeout = Millisecs() + 1000
            isjumping = True
            incy=-4
        End If
        If KeyDown(KEY_UP)
            For Local i=0 Until 4
                If pvc(0,0) = True And ptc(0,-1) = False
                    y-=1
                End If
            Next
        End If
        If KeyDown(KEY_DOWN)
            For Local i=0 Until 4
                If pvc(0,0) = True And ptc(0,1) = False
                    y+=1
                End If
            Next
        End If
        If KeyDown(KEY_LEFT)
            For Local i=0 Until 4
                If pvc(0,0) = True And ptc(-1,0) = False
                    x-=1
                    facing=0
                End If
            Next
        End If
        If KeyDown(KEY_RIGHT)
            For Local i=0 Until 4
                If pvc(0,0) = True And ptc(1,0) = False
                    x+=1
                    facing = 1
                End If
            Next
        End If
    End Method
    Method regularmode()        
        If jumpofvine = True
            If Millisecs() > jumpofvinetimeout Then jumpofvine=False
        End If
        'Left and Right movement
        If KeyDown(KEY_RIGHT)
            For Local i=0 Until 4 ' move with 4 pixels at a time
                If ptc(1,0) = False
                    x+=1
                    facing = 1
                End If
            Next
        End If
        If KeyDown(KEY_LEFT)
            For Local i=0 Until 4
                If ptc(-1,0) = False
                    x-=1
                    facing = 0
                End If
            Next
        End If
        'player gravity part
        'if in the air and not in jump
        If isjumping = False
            If ptc(0,1) = False
                isjumping=True
                incy=0
            End If
        End If
        ' jump
        If KeyDown(KEY_UP)
            If isjumping = False
                isjumping = True
                incy=-4
            End If
        End If
        ' if we are in a jump/falling down
        If isjumping=True
            If incy>=0 'if we are going down
                If incy<4 Then incy+=.1
                For Local i=0 Until(incy)
                    If ptc(0,1) = False
                        y+=1
                    Else
                        isjumping = False
                    End If
                Next
            End If
            If incy<0 'if we are going up
                incy+=.1
                For Local i=0 Until Abs(incy)
                    If ptc(0,-1) = False
                        y-=1
                    Else
                        incy=0
                    End If
                Next
            End If
        End If    
    End Method
    Method draw()
        SetColor 255,255,0
        DrawRect x,y,w,h
    End Method
End Class

Class deathwing
    Field x:Int,y:Int
    Field w:Int,h:Int
    Field state:String
    Field remove:Bool=False
    Field lasthurt:Int=Millisecs()
    
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
        w = 32
        h = 32
        state = "flyup"
    End Method
    Method update()    
        hurtplayer    
        Local x1:Int = ((Self.x-mapsx+16)/tilewidth)+mapx
        Local y1:Int = ((Self.y)/tileheight)+mapy
        canattack
        Select state
            Case "attack"
                If p.x < x Then x-=1
                If p.y < y Then y-=1
                If p.x > x Then x+=1
                If p.y > y Then y+=1
            Case "flyup"                
                ' if high enough
                If y1<12 Then 
                    If Rnd(10)<5                    
                        state="flyleft"                        
                        Else
                        state="flyright"
                    End If                
                End If
                'if can fly up
                If mymaptest.map[x1][y1-2] = 1
                    y-=1
                Else
                    If Rnd(10)<5
                        state="flyleft"
                        Else
                        state="flyright"
                    End If                
                End If                
            Case "flyleft"
                If mymaptest.map[x1][y1] = 1
                    x-=1
                Else
                    state="flyright"
                End If
                If Rnd(150)<5
                    If canflyup(x1+2,y1) = True
                        state="flyup"
                    End If
                Elseif Rnd(150)>140
                    If canflydown(x1+2,y1) = True
                        state="flydown"
                    End If
                End If
            Case "flyright"
                If mymaptest.map[x1+2][y1] = 1
                    x+=1
                Else                
                    state="flyleft"
                End If
                If Rnd(150)<5 Then
                    If canflyup(x1,y1) = True
                        state="flyup"
                    End If
                Elseif Rnd(150)>140
                    If canflydown(x1,y1) = True
                        state="flydown"
                    End If
                End If
            Case "flydown"
                If mymaptest.map[x1][y1+1] = 1
                    y+=1
                    Else
                    state="flyup"
                End If
        End Select
    End Method
    Method hurtplayer()
        If lasthurt<Millisecs()
            lasthurt = Millisecs()+600
            If rectsoverlap(p.x,p.y,32,32,x,y,32,32)
                p.health-=1
            End If
        End If
    End Method
    Method canattack()
        If state="attack"
        If distance(p.x,p.y,x,y) > 32
            If Rnd(10)<5 Then
                state="flyright"
            Else
                state="flyleft"
            End    If            
        End If
        End If
        If rectsoverlap(p.x-16,p.y-16,96,96,x-16,y-16,96,96)
            state="attack"
        End If
    End Method
    Method canflydown:Bool(x1:Int,y1:Int)
        For Local y2=y1 To y1+5
            If mymaptest.map[x1][y2] <> 1 Then
                Return False
            End If
        Next
        Return True        
    End Method
    Method canflyup:Bool(x1:Int,y1:Int)
        If y1<14 Then Return False
        For Local y2=y1 To y1-5 Step -1
            If mymaptest.map[x1][y2] <> 1 Then
                Return False
            End If
        Next
        Return True        
    End Method
    Method draw()
        SetColor 0,250,20
        DrawOval x,y,w,h
        SetColor 255,255,255
    End Method
End Class

Class agent
    Field x:Int,y:Int
    Field w:Int,h:Int
    Field state:String
    Field remove:Bool=False
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
        w = 32
        h = 32
        state="right"
    End Method
    Method update()
        Local x1:Int = ((Self.x-mapsx+16)/tilewidth)+mapx
        Local y1:Int = ((Self.y)/tileheight)+mapy
        Select state
            Case "right"
            If mymaptest.map[x1+2][y1] = 0 Or
                mymaptest.map[x1+2][y1+1] = 1 Then
                state="left"
                Else
                x+=1
            End If
            Case "left"
            If mymaptest.map[x1][y1] = 0 Or
                mymaptest.map[x1][y1+1] = 1 Then
                state="right"
                Else 
                x-=1
            End If
        End Select
        If Rnd(1500)<2
            Local placeegg:Bool=True
            For Local i:=Eachin eggs
                If i.x = x1 And i.y = y1
                    placeegg=False
                End If
            Next
            If placeegg = True
                If mymaptest.map[x1][y1] = 1
                mymaptest.map[x1][y1] = 3
                eggs.AddLast(New egg(x1,y1) )
                End If
            End If
        End If
    End Method
    Method draw()
        SetColor 255,0,0
        DrawRect x,y,w,h
        SetColor 255,255,255
    End Method
End Class

Class egg
    Field x:Int,y:Int
    Field hatch:Bool=False
    Field remove:Bool=False
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
    End Method
End Class

Class inventory
    Field eggs:Int=0
    Field meat:Int=0
    Method New()
    End Method
    Method draw()
        SetColor 0,0,0
        DrawRect     0,DeviceHeight()-64,
                    DeviceWidth(),64
        SetColor 255,255,255
        DrawText "Eggs :"+eggs,10,DeviceHeight()-40
        DrawText "Meat :"+meat,10,DeviceHeight()-20
        DrawText "Health :"+p.health,100,DeviceHeight()-40
        DrawText "This game template might be updated if I get inspired",DeviceWidth()/3,DeviceHeight()-60
        DrawText "or if there are lots of hits on it. So check this",DeviceWidth()/3,DeviceHeight()-40
        DrawText "link in the future.",DeviceWidth()/3,DeviceHeight()-20
    End Method
End Class

' -----------------------------------------------------------------------------------------------

Global myinven:inventory = New inventory
Global mymaptest:maptest
Global p:player
Global a:List<agent> = New List<agent>
Global dw:List<deathwing> = New List<deathwing>
Global eggs:List<egg> = New List<egg>
Global myspear:spear = New spear

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(60)
        restartgame
    End Method
    Method OnUpdate()    
        If p.health < 0 Or
            KeyHit(KEY_F1)
            restartgame
        End If
        p.update    
        alignmap
        For Local i:=Eachin a
            i.update
        Next
        For Local i:=Eachin dw
            i.update
            If i.remove = True 
                dw.Remove i
            End If
        Next        
        egghatch()
        myspear.update
    End Method
    Method OnRender()
        Cls 0,0,0 
        drawmap
        For Local i:=Eachin a
            i.draw
        Next
        For Local i:=Eachin dw
            i.draw
        Next
        myspear.draw
        p.draw        
        SetColor 0,0,0
        DrawRect 0,0,DeviceWidth(),50
        SetColor 255,255,255
        myinven.draw
        DrawText "Use Cursor left/right to move, cursor up to jump. Travel down the mine and mine eggs/meat.",0,0
        DrawText "Space to attack. t to take egg. p to place egg. Monsters spawn from eggs.",0,16
        DrawText "Monsters lay eggs. M - Show map.",0,32
        If KeyDown(KEY_M) Then
            Cls 0,0,0
            mymaptest.draw
        End If
    End Method
End Class



Function Main()
    New MyGame()
End Function

Function egghatch()
    'hatch deathwing
    For Local z=0 Until 2                    
        Local ax:Int=Rnd(mapwidth)
        Local ay:Int=Rnd(mapheight)
        If mymaptest.map[ax][ay] = 3
        If countdeathwings()<maxdeathwings    
            dw.AddLast( New deathwing(    (ax*tilewidth)-
                                        (mapx*tilewidth),
                                        (ay*tileheight)-
                                        (mapy*tileheight)+
                                        (mapsy) ) )        
            For Local i:=Eachin eggs
                If i.x = ax
                If i.y = ay
                    i.remove = True
                End If
                End If
            Next
            mymaptest.map[ax][ay]  = 1
            For Local i:=Eachin eggs
                If i.remove = True
                    eggs.Remove i
                End If
            Next                
            Exit
        End If
        End If
    Next
    'hatch breeder
    For Local z=0 Until mapwidth/2
        Local ax:Int=Rnd(mapwidth)
        Local ay:Int=Rnd(mapheight)
        If mymaptest.map[ax][ay] = 3
            For Local i:=Eachin eggs
            If i.x = ax And i.y = ay
                i.hatch = True
                For Local ii:=Eachin a
                    Local x1:Int = ((ii.x-mapsx+16)/tilewidth)+mapx
                    Local y1:Int = ((ii.y)/tileheight)+mapy

                    If distance(i.x,i.y,x1,y1) < 15 
                        i.hatch = False            
                    End If
                Next
            End If
            Next            
        End If        
    Next
    For Local i:=Eachin eggs
        If i.hatch = True
            mymaptest.map[i.x][i.y] = 1
            If Rnd(10) > 3  'hatch monster
                a.AddLast( New     agent(     (i.x*tilewidth)-
                                        (mapx*tilewidth),
                                        (i.y*tileheight)-
                                        (mapy*tileheight)+
                                        (mapsy) ) )
            End If
            i.remove = True
            For Local ii:=Eachin eggs
            If i<>ii
                If distance(i.x,i.y,ii.x,ii.y) < 10
                    ii.hatch=False
                End If
            End If
            Next
        End If
    Next
    For Local i:=Eachin eggs
        If i.remove = True Then
            eggs.Remove i
        End If
    Next
End Function

Function countdeathwings:Int()
    Local cnt:Int=0
    For Local i:=Eachin dw
        cnt+=1
    Next
    Return cnt
End Function

Function alignmap:Bool()
        For Local i=0 Until 4
        If p.x > DeviceWidth / 2
            If mapx+20 < mapwidth-1
                mapsx-=1
                If mapsx < 0 Then 
                    mapsx = 31
                    mapx += 1
                Endif
                p.x-=1
                p.movea(-1,0)
            End If
        End If
        Next

        For Local i=0 Until 4
        If p.x < DeviceWidth / 2
            If mapx > 0
                mapsx+=1
                If mapsx > 31 Then 
                    mapsx = 0
                    mapx -= 1
                Endif
                p.x+=1
                p.movea(1,0)
            End If
        End If
        Next
        ' scrolling down
        For Local i=0 Until 16
        If p.y > DeviceHeight / 2
            If mapy+14 < mapheight-1
                mapsy-=1
                If mapsy < 0 Then 
                    mapsy = 31
                    mapy += 1
                Endif
                p.y-=1
                p.movea(0,-1)
            End If
        End If
        Next
        ' scrolling up
        For Local i=0 Until 16
        If p.y < DeviceHeight / 2
            If mapy > 0
                mapsy+=1
                If mapsy > 31 Then 
                    mapsy = 0
                    mapy -= 1
                Endif
                p.y+=1
                p.movea(0,1)
            End If
        End If
        Next
End Function

'player collide with solid blocks true/false
Function ptc:Bool(offsetx:Int=0,offsety:Int=0)
    Local cx = (p.x+offsetx)/tilewidth+mapx
    Local cy = (p.y+offsety)/tileheight+mapy
    For Local y2=cy-1 Until cy+4
    For Local x2=cx-1 Until cx+4
        If x2>=0 And x2<mapwidth And y2>=0 And y2<mapheight
            If mymaptest.map[x2][y2] = 0
                Local x3 = (x2-mapx)*tilewidth-32+mapsx
                Local y3 = (y2-mapy)*tileheight+mapsy
                If rectsoverlap(p.x+offsetx,p.y+offsety,p.w,p.h,x3,y3,tilewidth,tileheight) = True
                    Return True
                End If
            End If
        End If
    Next
    Next
    Return False
End Function

'player collide with vines blocks true/false
Function pvc:Bool(offsetx:Int=0,offsety:Int=0)
    Local cx = (p.x+offsetx)/tilewidth+mapx
    Local cy = (p.y+offsety)/tileheight+mapy
    For Local y2=cy-1 Until cy+4
    For Local x2=cx-1 Until cx+4
        If x2>=0 And x2<mapwidth And y2>=0 And y2<mapheight
            If mymaptest.map[x2][y2] = 2
                Local x3 = (x2-mapx)*tilewidth-32+mapsx
                Local y3 = (y2-mapy)*tileheight+mapsy
                If rectsoverlap(p.x+offsetx,p.y+offsety,p.w,p.h,x3,y3,tilewidth,tileheight) = True
                    Return True
                End If
            End If
        End If
    Next
    Next
    Return False
End Function

Function drawmap:Void()
    For Local y=0 To 14
    For Local x=0 To 20
        Local x1 = ((x*tilewidth)+mapsx)-tilewidth
        Local y1 = ((y*tileheight)+mapsy)
        Select mymaptest.map[x+mapx][y+mapy]
            Case 0'Wall
            SetColor 100,100,100
            DrawRect x1,y1,tilewidth,tileheight
            Case 2'vine
            SetColor 10,100,10
            DrawRect x1,y1,tilewidth,tileheight
            Case 3'coin
            SetColor 200,200,10
            DrawOval x1+4,y1+4,tilewidth-8,tileheight-4
          End Select
     Next
     Next
     
End Function

Function restartgame()
    a.Clear()
    dw.Clear()
    eggs.Clear()
    mapx=0
    mapy=0
    mapsx=0
    mapsy=0
    mymaptest = New maptest(mapwidth,mapheight)
    p = New player
    p.x+=64
    p.movea(64,0)

End Function

Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
    Return Abs(x2-x1)+Abs(y2-y1)
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

Friday, December 4, 2015

Monkey-X - 2d Map Generator (Mazelike) - code example


This mazelike generator works like this. It finds a free position on the map and then build a wall there if there is space there. A wall can change directions while it is being created.

Import mojo

' This class holds the map.
' mapmaker selects a random pos in the map
' and then builds a wall there if there is space.
Class maptest
    Field tw:Int,th:Int
    Field w:Int,h:Int
    Field map:Int[][]
    Method New(w:Int,h:Int)
        Self.w = w
        Self.h = h
        tw = DeviceWidth()/w
        th = DeviceHeight()/h
        map = New Int[w][]
        For Local i=0 Until w
            map[i] = New Int[h]
        Next
        makemap        
    End Method
    'make the map
    Method makemap()
        Local exitloop:Bool=False
        Local exitcount:Int=0
        While exitloop = False
            Local x:Int=Rnd(0,w)
            Local y:Int=Rnd(0,h)
            If mappartisfree(x,y) = True
                exitcount=0
                ' dir = direction 1 to 4
                ' dis = distance of wall
                Local dir:Int=Rnd(1,5)
                Local dis:Int=Rnd(4,10)
                makewall(x,y,dir,dis)
            Else
                exitcount+=1
            End If
            If exitcount>200 Then exitloop=True
        Wend
    End Method
    ' this method makes the walls
    Method makewall(x:Int,y:Int,dir:Int,dis:Int)
        ' px and py hold the wall and is drawn
        ' onto the map when the complete wall
        ' fits on the map.
        Local px:Int[dis]
        Local py:Int[dis]
        For Local i=0 Until dis
            px[i] = x
            py[i] = y
            Select dir
                Case 1;y-=1
                Case 2;x+=1
                Case 3;y+=1
                Case 4;x-=1
            End Select
            If Rnd(0,3) < 1 Then dir=Rnd(1,5)
            ' stay inside bounds or exit
            If x<0 Or x>=w Or y<0 Or y>=h Then Return
            ' if map position taken then exit
            If mappartisfree(x,y) = False Then Return
        Next
        ' here the wall is added to the map
        For Local i=0 Until dis
            map[px[i]][py[i]] = 1
        Next
    End Method
    ' check if the area around x,y is no wall
    Method mappartisfree:Bool(x,y)
        For Local y1=-1 To 1
        For Local x1=-1 To 1
            If x+x1>-1 And x+x1<w
            If y+y1>-1 And y+y1<h
                If map[x+x1][y+y1] = 1
                    Return False
                End If
            End If
            End If
        Next
        Next
        Return True
    End Method
    Method draw()
        SetColor 255,255,255
        For Local y=0 Until h
        For Local x=0 Until w
            If map[x][y] = 1
                DrawRect x*tw,y*th,tw,th
            End If
        Next
        Next
    End Method
End Class

Global mymaptest:maptest

Class MyGame Extends App
    Field mytime:Int
    Method OnCreate()
        SetUpdateRate(60)
        mymaptest = New maptest(Rnd(20,50),Rnd(15,30))
    End Method
    Method OnUpdate()  
        mytime+=1
        If KeyHit(KEY_SPACE) Or mytime>180
            mytime=0
            mymaptest = New maptest(Rnd(20,50),Rnd(15,30))
        End If      
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        mymaptest.draw
        SetColor 255,255,255
        DrawText "Monkey-X - Map generator - mazelike (if space then place)",10,10
    End Method
End Class


Function Main()
    New MyGame()
End Function

Monkey-X - Filled Balls, WritePixels/CreateImage/Class - code example


I saw a certain kind of icon on my ipad and had the idea to make this kind of image in Monkey- In the code images are created that look like some kind of rainbow balls. They are drawn to the screen.

Import mojo

Class filledballs
    Field myc:Int=0 'oval color
    Field x:Int,y:Int
    Field w:Int,h:Int
    Field im:Image
    Field pixels:Int[]
    Method New(x:Int,y:Int,w:Int,h:Int,c:Int)
        Self.x = x
        Self.y = y
        Self.w = w
        Self.h = h
        myc=c
        pixels = New Int[w*h]
        im = CreateImage(w,h,1,Image.MidHandle)
        For Local i=0 Until im.Width()*im.Height()
            pixels[i] = $00000000
        Next
        Local i2:Int=0
        For Local i=(w/2)-1 To 1 Step -1
            Local col:Int=0
            Select myc
                Case 0;col=argb(i2,i2,i2,255)
                Case 1;col=argb(i2,0,i2,255)
                Case 2;col=argb(i2,i2,0,255)
                Case 3;col=argb(i2,0,0,255)
                Case 4;col=argb(0,i2,i2,255)
                Case 5;col=argb(0,0,i2,255)
                Case 6;col=argb(0,i2,0,255)
            End Select
            drawo(w/2,w/2,i,col)
            i2+=255/(w/2)
        Next
        im.WritePixels(pixels, 0, 0, w, h, 0)
    End Method
    Method drawo(x1,y1,radius,col)
        For Local y2=-radius To radius
        For Local x2=-radius To radius
            If (y2*y2+x2*x2) <= radius*radius+radius*0.8
                Local x3 = x2+x1
                Local y3 = y2+y1
                Local pc = y3*im.Width()+x3
                If pc>=0 And pc < im.Width()*im.Height()
                    pixels[pc] = col
                End If
            End If
        Next
        Next      
    End Method
    Function argb:Int(r:Int, g:Int, b:Int ,alpha:Int=255)
        Return (alpha Shl 24) | (r Shl 16) | (g Shl 8) | b          
    End Function     
    Method draw()
        DrawImage im,x,y
    End Method
End Class

Global myfball:List<filledballs> = New List<filledballs>

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(60)
        For Local y=0 To DeviceHeight() Step 64
        For Local x=0 To DeviceWidth() Step 64
            myfball.AddLast(New filledballs(x,y,64,64,Rnd(0,7)))
        Next
        Next
        For Local x=0 To DeviceWidth()+96 Step 96
            myfball.AddLast(New filledballs(x,100,96,96,Rnd(07)))
        Next
    End Method
    Method OnUpdate()        
    End Method
    Method OnRender()
        Cls 0,0,0 
        For Local i:=Eachin myfball
            i.draw
        Next
        SetColor 0,0,0
        DrawRect 0,100,DeviceWidth(),20
        SetColor 255,255,255
        DrawText "MonkeyX - Filled balls, WritePixels/CreateImage",10,105
    End Method
End Class


Function Main()
    New MyGame()
End function

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

Sunday, September 27, 2015

Monkey-X - Rotating Astroids Image Array Class - code example


Here a example where I create a image in a class and draw lines in it to form the shape of a asteroid. It then rotates the midhandled image. Uses bresenham's linealgorithm to draw in a array.

Import mojo

Global numasteroids:Int=10
Global awidth:Int=64
Global aheight:Int=64

Class asteroid
    Field im:Image
    Field pixels:Int[awidth*aheight]
    Field x:Int,y:Int
    Field angle:Float=0
    Field rotspeed:Float=Rnd(-3.3,3.3)
    Method New(x:Int,y:Int)
        im = CreateImage(awidth,aheight,1,Image.MidHandle)
        Self.x = x
        Self.y = y
        Local myan:Int=0
        Local x1:Int,y1:Int
        Local x2:Int,y2:Int        
        Local sx:Int,sy:Int
        x1 = awidth/2+((Cos(myan)*Rnd(16,32)))
        y1 = aheight/2+((Sin(myan)*Rnd(16,32)))        
        sx=x1
        sy=y1
        For Local i=0 Until 10
            myan+=350/10
            x2 = awidth/2+((Cos(myan)*Rnd(16,32)))
            y2 = aheight/2+((Sin(myan)*Rnd(16,32)))
            bline(x1,y1,x2,y2)
            x1 = x2
            y1 = y2
        Next
        bline x1,y1,sx,sy
        im.WritePixels(pixels, 0, 0, awidth, aheight, 0)
    End Method
    Method update()
        angle+=rotspeed
        If angle > 359 Then angle = 0
        If angle < 0 Then angle = 359
    End Method
    Method draw()
        DrawImage im,x,y,angle,1.0,1.0,0
    End Method
    Method bline:Void(x1:Int,y1:Int,x2:Int,y2:Int)
        Local dx:Int, dy:Int, sx:Int, sy:Int, e:Int
        dx = Abs(x2 - x1)
          sx = -1
          If x1 < x2 Then sx = 1      
          dy = Abs(y2 - y1)
          sy = -1
          If y1 < y2 Then sy = 1
          If dx < dy Then 
              e = dx / 2 
          Else 
              e = dy / 2          
          End If
          Local exitloop:Bool=False
          While exitloop = False
            Local pc:Int = y1*awidth+x1
            If pc>=0 And pc <awidth*aheight
                pixels[pc] = argb(255,255,255,255)
            End If
            If x1 = x2 
                If y1 = y2
                    exitloop = True
                End If
            End If
            If dx > dy Then
                x1 += sx ; e -= dy 
                  If e < 0 Then e += dx ; y1 += sy
            Else
                y1 += sy ; e -= dx 
                If e < 0 Then e += dy ; x1 += sx
            Endif
          Wend
    End Method
    Function argb:Int(r:Int, g:Int, b:Int ,alpha:Int=255)
        Return (alpha Shl 24) | (r Shl 16) | (g Shl 8) | b          
    End Function        
End Class

Global myasteroids:List<asteroid> = New List<asteroid>

Class MyApp Extends App
    
    Method OnCreate()
        SetUpdateRate(60)
        Local date := GetDate()
        Seed = date[5]        
        For Local y=64 Until DeviceHeight Step 128
        For Local x=64 Until DeviceWidth Step 128
        myasteroids.AddLast(New asteroid(x,y))
        Next
        Next
    End Method
    Method OnUpdate()
        For Local i:=Eachin myasteroids
            i.update
        Next
    End Method    
    Method OnRender()
        Cls 0,0,0
        For Local i:=Eachin myasteroids
            i.draw
        Next
        SetColor 255,255,255
        DrawText "Monkey-X Class Image Asteroids example.",10,10
    End Method
    
End Class


Function Main()
    New MyApp
End Function

Monkey-X - Bresenham's Line Algorithm - (function) - code example


Useful thing this bresenham line function.

Import mojo

Class MyApp Extends App
    
    Method OnCreate()
        SetUpdateRate(60)
        Local date := GetDate()
        Seed = date[5]        
    End Method
    Method OnUpdate()
    End Method    
    Method OnRender()
        Cls 0,0,0
        SetColor 255,255,255
        DrawText "Monkey-X Bresenham's line algorithm - function.",10,10
        For Local i=0 Until 32
            bline Rnd(0,640),Rnd(0,480),Rnd(0,640),Rnd(0,480)
        Next
    End Method
    
End Class

Function bline:Void(x1:Int,y1:Int,x2:Int,y2:Int)
      Local dx:Int, dy:Int, sx:Int, sy:Int, e:Int
      dx = Abs(x2 - x1)
      sx = -1
      If x1 < x2 Then sx = 1      
      dy = Abs(y2 - y1)
      sy = -1
      If y1 < y2 Then sy = 1
      If dx < dy Then 
          e = dx / 2 
      Else 
          e = dy / 2          
      End If
      Local exitloop:Bool=False
      While exitloop = False
        SetColor 255,255,255
        DrawPoint x1,y1
        If x1 = x2 
            If y1 = y2
                exitloop = True
            End If
        End If
        If dx > dy Then
            x1 += sx ; e -= dy 
              If e < 0 Then e += dx ; y1 += sy
        Else
            y1 += sy ; e -= dx 
            If e < 0 Then e += dy ; x1 += sx
        Endif
      Wend
End Function

Function Main()
    New MyApp
End Function

Saturday, September 26, 2015

Monkey-X - TextWidth/DrawText/DeviceWidth - code example


Sometimes you need the width of the text that you have on the screen. See below how this can be done.

Import mojo

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(60)
    End Method
    Method OnUpdate()
    End Method
    Method OnRender()
        Cls 0,0,0           
        
        Local s:String="This is a string."
        Local tw:Int=TextWidth(s)
        
        SetColor 255,255,255
        DrawText s,DeviceWidth()/2,100,0.5,0.5
        DrawText "Width of text is :"+tw,DeviceWidth()/2,125,0.5,0.5
        
        SetColor 255,255,255
        DrawText "Monkey-X - TextWidth Example.",10,10
    End Method
End Class


Function Main()
    New MyGame()
End Function

Monkey-X - Simple Pattern Movement - code example


Here something I read in a ai book. There are movement instructions in a array that the unit uses to move around. Patrol in a square like pattern here. You can also put coordinates in a array and move them like that.

Import mojo

' x : -1 = left , 1 = right
' y : -1 = up , 1 = down
Global path1x:Int[] = [1,1,0,0,-1,-1,0,0]
Global path1y:Int[] = [0,0,1,1,0,0,-1,-1]
Global tilewidth:Int=32
Global tileheight:Int=32

Class ai
    Field x:Int,y:Int
    Field cpathpos:Int=0
    Field delay
    Field delay2:Int
    Method New(x:Int,y:Int,delay:Int)
        Self.x = x
        Self.y = y
        Self.delay2 = delay
        Self.delay = 0
    End Method
    Method update()
        delay-=1
        If delay>0 Then Return
        delay = delay2
        Select path1x[cpathpos]
            Case 1;x+=1
            Case -1;x-=1
        End Select
        Select path1y[cpathpos]
            Case 1;y+=1
            Case -1;y-=1
        End Select
        cpathpos+=1
        If cpathpos >= path1x.Length Then
            cpathpos=0
        End If
    End Method
    Method draw()
        SetColor 255,0,0
        DrawOval     x*tilewidth,y*tileheight,
                    tilewidth,tileheight
    End Method
End Class

Global myai:List<ai> = New List<ai>

Class MyApp Extends App
    
    Method OnCreate()
        SetUpdateRate(60)
        Local cnt:Int=10
        For Local y=0 Until 5
        For Local x=0 Until 5
            cnt+=1
            myai.AddLast(New ai(x*5,y*5,cnt))
        Next
        Next
    End Method

    Method OnUpdate()
        For Local i:= Eachin myai
            i.update
        Next
    End Method
    
    Method OnRender()
        Cls 0,0,0        
        For Local i:=Eachin myai
            i.draw
        Next
        SetColor 255,255,255
        DrawText "Monkey-X Pattern Movement example.",10,10
    End Method
    
End Class


Function Main()
    New MyApp
End Function

Monkey-X - GetDate Seconds to Rnd Seed - code example


To not get the same random behaviour each time you start the game you can set the seed to use the GetDate current second.

Import mojo

Global color:Int[] = New Int[3]

Class MyApp Extends App
    
    Method OnCreate()
        SetUpdateRate(60)
        ' here 
        Local date := GetDate()
        ' set the random seed to
        ' current second
        Seed = date[5]
        color[0] = Rnd(255)
        color[1] = Rnd(255)
        color[2] = Rnd(255)                
    End Method

    Method OnUpdate()
    End Method
    
    Method OnRender()
        Cls 0,0,0
        SetColor 255,255,255
        DrawText "Monkey-X different random seed each time.",10,10
        For Local i=0 Until 3
            SetColor color[i],0,0
            DrawRect i*DeviceWidth()/3,0,DeviceWidth()/3,DeviceHeight()
        Next
    End Method
    
End Class


Function Main()
    New MyApp
End Function

Monkey-X - Simple Group Movement - code example


Here a example of how to move units that are grouped.

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
    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()
        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
                End If
                End If
                End If
            Next
            If nxt = False
                x += Cos(angle)*ms
                y += Sin(angle)*ms
            End If
        End If
    End Method
    Method draw()
        SetColor 255,0,0
        DrawOval x,y,16,16
    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 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

Monday, September 21, 2015

Monkey-X - BreadCrumb artificial Intelligence - code example


This I learned about a long time ago. Basically you leave a trail and if the ai finds the trail then he starts to follow that trail.

Import mojo

Global tilewidth:Int=16
Global tileheight:Int=16
Global aiwidth:Int=16
Global aiheight:Int=16

Class ai
    Field x:Int,y:Int
    Field readcountdown:Int
    Field state:String
    Field bcx:Int,bcy:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
        readcountdown=Rnd(0,60)
        state="search"
    End Method
    Method update()
        If state="search" And 
            distance(x,y,myplayer.x,myplayer.y) > 16
            '
            readcountdown-=1
            If readcountdown<0
                readcountdown=60
                For Local i:=Eachin myplayercrumb
                    If distance(i.x,i.y,x,y) < 32
                        DebugLog "Found crumbs"
                        state="following"
                        bcx = i.x
                        bcy = i.y
                        Exit
                    End If                    
                Next
            End If
        End If
        If state="following"
            If x < bcx Then x+=1
            If x > bcx Then x-=1
            If y < bcy Then y+=1
            If y > bcy Then y-=1
            If x = bcx And y = bcy
                setnextbread()
                If distance(x,y,bcx,bcy) > 32
                    DebugLog "Out of range.."
                    state="search"                     
                End If
                If distance(x,y,myplayer.x,myplayer.y) < 16
                    DebugLog "engaging player.."
                    state="search"                                         
                End If
            End If
        End If
    End Method
    Method setnextbread()
        Local prx:Int
        Local pry:Int
        For Local i:=Eachin myplayercrumb
            If i.x = x And i.y = y
                bcx = prx
                bcy = pry
                Return
            End If
            prx = i.x
            pry = i.y
        Next
    End Method
    Method draw()
        SetColor 255,0,0
        DrawOval x,y,aiwidth,aiheight
    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:Int,y:Int
    Field playerwidth:Int=16
    Field playerheight:Int=16
    Field playerspeed:Int=4
    Field otx:Int,oty:Int
    Method New(x:Int,y:Int)
        otx = x
        oty = y
        Self.x = x*tilewidth
        Self.y = y*tileheight        
    End Method
    Method update()
        For Local i=0 Until playerspeed
            Local newx:Int=x
            Local newy:Int=y
            If KeyDown(KEY_RIGHT)
                newx+=1
            End If
            If KeyDown(KEY_LEFT)
                newx-=1
            End If
            If KeyDown(KEY_UP)
                newy-=1
            End If
            If KeyDown(KEY_DOWN)
                newy+=1
            End If
            If newx>0 And 
                newx<DeviceWidth()-playerwidth
            If newy>0 And 
                newy<DeviceHeight()-playerheight
                x = newx
                y = newy
            End If
            End If
            If x = otx And y=oty
            Else
                myplayercrumb.AddFirst(New crumb(x,y))
                If myplayercrumb.Count() > 196 Then
                    myplayercrumb.RemoveLast()
                End If
                otx = x
                oty = y
            End If
            
        Next
    End Method
    Method draw()
        SetColor 0,0,255
        DrawOval x,y,playerwidth,playerheight
    End Method
End Class

Class crumb
    Field x:Int,y:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
    End Method
End Class

Global myplayercrumb:List<crumb> = New List<crumb>
Global myplayer:player = New player(10,10)
Global myai:List<ai> = New List<ai>

Class MyApp Extends App
    
    Method OnCreate()
        SetUpdateRate(60)
        myai.AddLast(New ai(100,100))
    End Method

    Method OnUpdate()
        myplayer.update
        For Local i:=Eachin myai
            i.update
        Next
    End Method
    
    Method OnRender()
        Cls 0,0,0
        drawplayerbreadcrumbs()
        For Local i:=Eachin myai
            i.draw
        Next
        myplayer.draw
        SetColor 255,255,255
        DrawText "Monkey-X Bread crumb ai.",10,10
        DrawText "Use cursors to move (blue) and leave trail..",10,25
    End Method
    
End Class

Function drawplayerbreadcrumbs:Void()
    SetColor 100,100,100
    For Local i:=Eachin myplayercrumb
        DrawPoint     i.x+tilewidth/2,i.y+tileheight/2
    Next
End Function

Function Main()
    New MyApp
End Function