Artificial intelligence/templates/examples/rts/rpg/strategy ect. in MonkeyX/CerberusX language. You can download the free version of MonkeyX from itch.io or Cerberus-x.com The Flash applets will stop working in around 2020.
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
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
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
' 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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