Import mojo
'
' This is the tile class.
' Here a stone tile is created
' using the generate method
Class tile
Field width:Int,height:Int
Field map:Int[][]
Method New(w:Int,h:Int)
Self.width = w
Self.height = h
map = New Int[width][]
For Local i:Int=0 Until width
map[i] = New Int[height]
Next
End Method
Method generate(spacing:Int)
' Put a number of stone points on the map
' try to keep a distance between them
Local numpoints:Int=Rnd(width/5,width/2)
For Local i:Int=0 Until numpoints
Local x:Int=Rnd(width)
Local y:Int=Rnd(height)
Local exitloop:Bool=False
While exitloop=False
exitloop = True
If disttootherstone(x,y,i) < spacing
x=Rnd(width)
y=Rnd(height)
exitloop=False
End If
Wend
map[x][y] = i
Next
'
' Grow the stone points
For Local i:Int=0 Until (width*height)*10
Local x:Int=Rnd(width)
Local y:Int=Rnd(height)
If map[x][y] > 0
If disttootherstone(x,y,map[x][y]) < spacing Then Continue
For Local y2:Int=y-1 To y+1
For Local x2:Int=x-1 To x+1
If x2<0 Or y2<0 Or x2>=width Or y2>=height Then Continue
If Rnd(5)<2 Then
If map[x2][y2] = 0
If x2 = 0 Then map[width-1][y2] = map[x][y]
If x2 = width-1 Then map[0][y2] = map[x][y]
If y2 = 0 Then map[x2][height-1] = map[x][y]
If y2 = height-1 Then map[x2][0] = map[x][y]
map[x2][y2] = map[x][y]
End If
End If
Next
Next
End If
Next
shadeedges()
End Method
' Add ligther and darker pixels ontop of the stones
' value 1 to <100 is each seperate stone
' value 200 is light color 100 is dark color
Method shadeedges()
For Local y:Int=0 Until height
For Local x:Int=0 Until width
If map[x][y] > 0 And map[x][y] <> 200
If x-1 >=0 And map[x-1][y] = 0
For Local x2:Int=x+2 To x+4
If Rnd(2)<1
If x2>=0 And x2<width And map[x2][y] >0 Then map[x2][y] = 100
End If
Next
End If
If x-1 >=0 And y-1>=0 And map[x-1][y-1] = 0
map[x][y] = 100
End If
If x+1 < width And map[x+1][y] = 0
For Local x2:Int=x-4 To x+2
If Rnd(2)<1
If x2>=0 And x2<width And map[x2][y] >0 Then map[x2][y] = 200
End If
Next
End If
End If
Next
Next
End Method
' Returns the shortest distance to any other stone part then
' the currentstore
Method disttootherstone:Int(sx:Int,sy:Int,currentstone:Int)
Local shortest:Int=9999
For Local y:Int=0 Until height
For Local x:Int=0 Until width
If map[x][y] <> 0 And map[x][y] <> currentstone
Local d:Int=distance(sx,sy,x,y)
If d<shortest Then shortest = d
End If
Next
Next
Return shortest
End Method
' Draw the tile at x and y position and tw=size
Method draw(sx:Int,sy:Int,tw:Int,th:Int)
Local x:Int
Local y:Int
For y=0 Until height
For x=0 Until width
Local t:Int=map[x][y]
Local x2:Int=x*tw
Local y2:Int=y*th
x2+=sx
y2+=sy
If t >= 1 Then 'grey base color
SetColor 100,100,100
End If
If t=100 Then SetColor 40,40,40 'dark shade color
If t=200 Then SetColor 140,140,140 'light shade color
If t>0 ' draw a rect (part of the stone)
DrawRect x2,y2,tw,th
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
Class MyGame Extends App
Field mytile:tile
Field cnt:Int=0
Method OnCreate()
Seed = GetDate[4]*GetDate[5]
SetUpdateRate(1)
mytile = New tile(32,32)
mytile.generate(6)
End Method
Method OnUpdate()
cnt+=1
If KeyHit(KEY_SPACE) Or cnt>3
cnt = 0
mytile = New tile(32,32) 'reset/create new tile
Local spacing:Int=Rnd(4,10) ' set random spacing
If Rnd(3)<1 Then spacing=4
mytile.generate(spacing) ' generate the tile
End If
End Method
Method OnRender()
Cls 0,0,0
'draw the tiles in 4x the size
For Local y:Int=0 Until DeviceHeight Step 32*4
For Local x:Int=0 Until DeviceWidth Step 32*4
mytile.draw(x,y,4,4)
Next
Next
' draw the tiles in 1x size
SetColor 0,0,0
DrawRect 320,240,320,240
For Local y:Int=240 Until DeviceHeight Step 32
For Local x:Int=320 Until DeviceWidth Step 32
mytile.draw(x,y,1,1)
Next
Next
End Method
End Class
Function Main()
New MyGame()
End Function
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.
Monday, October 30, 2017
Monkey-X - Generator - Tileable Textured Stones - code example
Monday, October 23, 2017
Monkey-x - Generator - 2d flasks and bottles - code example
Import mojo
Class tile
Field width:Int,height:Int
Field map:Int[][]
Method New(w:Int,h:Int)
Self.width = w
Self.height = h
map = New Int[width][]
For Local i:Int=0 Until width
map[i] = New Int[height]
Next
End Method
' Here we create the flasks or bottles
' or what else.
Method generate()
'make right side
' from the center top to center bottom
Local x:Float=width/2
Local y:Float=0
Local angle:Int=0
While y<=height
For Local i:Int=0 Until 20
x+=Cos(angle)*.5
y+=Sin(angle)*.5
If x>=width Then x-=1
If x<0 Or y<0 Or x>=width Or y>=height Then Exit
map[x][y] = 1 ' create border point
fillleftside(x-1,y) ' fill left side
Next
angle=Rnd(0,120)
Wend
If y>height Then y=height-1
For Local x1:Int=x Until width/2-1 Step -1
map[x1][y] = 1
Next
'make left side (mirror right side)
For y = 0 Until height
For x = width/2 Until width
map[width-x][y] = map[x][y]
Next
Next
Return
End Method
' here we put the value of
' 2 inside the map from inputted
' coords to most left position
Method fillleftside(fx:Int,fy:Int)
For Local x:Int=fx Until 0 Step -1
map[x][fy] = 2
Next
End Method
Method draw(sx:Int,sy:Int,ar:Int,ag:Int,ab:Int)
Local c:Int
Local g:Int
Local b:Int
Local lightpointx:Int=Rnd(5,width-5)
For Local y:Int=0 Until height
For Local x:Int=0 Until width
If map[x][y] = 0 Then
c=0+((ag/height)*y)
g=0+((ab/height)*y)
b=0+((ar/height)*y)
If c>255 Then c=255
If g>255 Then g=255
If b>255 Then b=255
If c<0 Then c=0
If g<0 Then g=0
If b<0 Then b=0
SetColor c,g,b
DrawRect sx+x,sy+y,1,1
Continue
End If
' here we draw the border
' and the red (rainbowish color)
Select map[x][y]
Case 1'border
c = 255-((255/height)*y)
If x>width/2 Then c/=2
SetColor c,c,c
Case 2
c = ar-((ar/height)*y)
g = ag-((ag/height)*y)
b = ab-((ab/height)*y)
c=-distance(lightpointx,0,x,0)+c
g=-distance(lightpointx,0,x,0)+g
b=-distance(lightpointx,0,x,0)+b
If c>255 Then c=255
If g>255 Then g=255
If b>255 Then b=255
If c<0 Then c=0
If g<0 Then g=0
If b<0 Then b=0
SetColor c,g,b
End Select
DrawRect sx+x,sy+y,1,1
Next
Next
End Method
Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
Return Abs(x2-x1)+Abs(y2-y1)
End Function
End Class
Class MyGame Extends App
Field mytile:tile
Method OnCreate()
Seed = GetDate[4]*GetDate[5]
SetUpdateRate(1)
End Method
Method OnUpdate()
End Method
Method OnRender()
Cls 0,0,0
SetColor 255,255,255
For Local y:Int=0 Until DeviceHeight Step 55
For Local x:Int=0 Until DeviceWidth Step 55
mytile = New tile(48,48)
mytile.generate()
mytile.draw(x,y,Rnd(24,255),Rnd(24,255),Rnd(24,255))
Next
Next
End Method
End Class
Function Main()
New MyGame()
End Function
Monkey-X - Generator - 2d Maps using Lines - code example
' Create a map with lines.
' It works by randomly selecting a point on the map
' and the drawing into a random direction. We stop
' drawing if we are close to a previously drawn line.
'
Import mojo
Class map
Field screenwidth:Int
Field screenheight:Int
Field mapwidth:Int
Field mapheight:Int
Field tilewidth:Float
Field tileheight:Float
Field map:Int[][]
Method New(sw:Int,sh:Int,mw:Int,mh:Int)
Self.screenwidth = sw
Self.screenheight = sh
Self.mapwidth = mw
Self.mapheight = mh
Self.tilewidth = Float(sw) / Float(mw)
Self.tileheight = Float(sh) / Float(mh)
map = New int[mapwidth][]
For Local i:Int=0 Until mapwidth
map[i] = New Int[mapheight]
Next
createmap()
End Method
Method createmap()
' Loop a number of times
For Local i:Int=0 Until (mapwidth+mapheight)
' Get a random x and y spot on the map
Local x:Float=Rnd(mapwidth)
Local y:Float=Rnd(mapheight)
' Chose an angle
Local angle:Int=Rnd(360)
' We will draw d into angle it's direction
Local d:Int=Rnd(3,35)
Local xitloop:Bool=False
' We change the angle and distance 3 times
For Local iii:Int=0 Until 3
' Loop the distance
For Local ii:Int=0 Until d
' If spot taken with 1 or out of screen
' then exit the loop
If maptaken(x-4,y-4,8,8) Then xitloop=True ; Exit
' Put value 2 into the map
map[x][y] = 2
' Next x and y position
x+=Cos(angle)*1
y+=Sin(angle)*1
Next
' Exit the loop(spot taken)
If xitloop=True Then Exit
' Change angle and distance
angle+=Rnd(-90,90)
d=Rnd(3,35)
Next
' Turn all new drawn 2 value's into
' value of 1
For Local y:Int=0 Until mapheight
For Local x:Int=0 Until mapwidth
If map[x][y] = 2 Then map[x][y] = 1
Next
Next
Next
End Method
' See if the area selected is outside the
' screen or if the map value is 1
Method maptaken:Bool(x:Int,y:Int,w:Int,h:Int)
For Local y2:Int=y Until y+h
For Local x2:Int=x Until x+w
If x2<0 Or x2>=mapwidth Or y2<0 Or y2>=mapheight Then Return True
If map[x2][y2] = 1 Then Return True
Next
Next
Return False
End Method
' Draw the map
Method draw()
For Local y:Int=0 Until mapheight
For Local x:Int=0 Until mapwidth
If map[x][y] = 0 Then Continue
SetColor 255,255,255
Local x2:Int=x*tilewidth
Local y2:Int=y*tileheight
DrawRect x2,y2,tilewidth+1,tileheight+1
Next
Next
End Method
End Class
Class MyGame Extends App
Field mymap:map
Field cnt:Int=0
Method OnCreate()
Seed = GetDate[4] * GetDate[5]
SetUpdateRate(1)
createrandommap()
End Method
Method OnUpdate()
cnt+=1
If KeyHit(KEY_SPACE) Or cnt > 1
cnt=0
createrandommap()
End If
End Method
Method OnRender()
Cls 0,0,0
' Draw the map
mymap.draw()
SetColor 255,255,255
Local mw:Int=mymap.mapwidth
Local mh:Int=mymap.mapheight
DrawText "Width : "+mw+" Height : "+mh,0,0
End Method
Method createrandommap()
Local size:Int=Rnd(20,200)
mymap = New map(DeviceWidth,DeviceHeight,size,size)
End Method
End Class
Function Main()
New MyGame()
End Function
Monkey-X - Breath First Search(bfs) - code example
'Is this the breath first search? Not to familiar with it.
Import mojo
Class search
Field screenwidth:Int,screenheight:Int
Field mapwidth:Int,mapheight:Int
Field tilewidth:Float,tileheight:Float
Field sx:Int,sy:Int
Field ex:Int,ey:Int
Field map:Int[][]
Field myopenlist:List<node>
Field myclosedlist:List<node>
Field mypath:List<path>
Field mx:Int[]=[0,-1,1,0]
Field my:Int[]=[-1,0,0,1]
Method New(screenwidth:Int,screenheight:Int,mapwidth:Int,mapheight:Int)
Self.screenwidth = screenwidth
Self.screenheight = screenheight
Self.mapwidth = mapwidth
Self.mapheight = mapheight
Self.tilewidth = Float(screenwidth) / Float(mapwidth)
Self.tileheight = Float(screenheight) / Float(mapheight)
map = New Int[mapwidth][]
For Local i:Int=0 Until mapwidth
map[i] = New Int[mapheight]
Next
makemap()
End Method
Method makemap:Void()
For Local i:Int=0 Until mapwidth/3
Local x1:Float=Rnd(0,mapwidth)
Local y1:Float=Rnd(0,mapheight)
Local angle:Int=Rnd(360)
Local dist:Int=Rnd(3,7)
For Local ii:Int=0 Until dist
x1+=Cos(angle)*1
y1+=Sin(angle)*1
If x1<0 Or y1<0 Or x1>=mapwidth Or y1>=mapheight Then Exit
map[x1][y1] = 1
Next
Next
End Method
Method search:Bool(sx:Int,sy:Int,ex:Int,ey:Int)
If sx=ex And sy=ey Then Return False
If map[sx][sy] <> 0 Or map[ex][ey] <> 0 Then Return False
Self.sx = sx
Self.sy = sy
Self.ex = ex
Self.ey = ey
myopenlist = New List<node>
myclosedlist = New List<node>
mypath = New List<path>
myopenlist.AddFirst(New node(sx,sy,sx,sy))
' the search
While Not myopenlist.IsEmpty
Local cx:Int=myopenlist.First.x
Local cy:Int=myopenlist.First.y
Local px:Int=myopenlist.First.parentx
Local py:Int=myopenlist.First.parenty
myclosedlist.AddFirst(New node(cx,cy,px,py))
If cx = ex And cy = ey Then
findpathback()
Return True
End If
myopenlist.RemoveFirst()
For Local i:Int=0 Until mx.Length
Local nx:Int=cx+mx[i]
Local ny:Int=cy+my[i]
If nx<0 Or ny<0 Or nx>=mapwidth Or ny>=mapheight Then Continue
If map[nx][ny] = 0 'if the map is not obstructed
If isonclosedlist(nx,ny) = False And isonopenlist(nx,ny) = False
myopenlist.AddLast(New node(nx,ny,cx,cy))
End If
End If
Next
Wend
Return False
End Method
' Here we calculate back from the end back to the
' start and create the path list.
Method findpathback:Bool()
Local x:Int=ex
Local y:Int=ey
mypath.AddFirst(New path(x,y))
Repeat
For Local i:=Eachin myclosedlist
If i.x = x And i.y = y
x = i.parentx
y = i.parenty
mypath.AddFirst(New path(x,y))
End If
Next
If x = sx And y = sy Then Return True
Forever
End Method
Method drawpath()
If Not mypath Then Return
For Local i:=Eachin mypath
SetColor 255,0,0
DrawOval i.x*tilewidth+(tilewidth/4),i.y*tileheight,tilewidth/4,tileheight/2
Next
End Method
Method drawclosedlist()
If Not myclosedlist Then Return
For Local i:=Eachin myclosedlist
DrawText "loc:"+i.x+","+i.y, i.x*tilewidth,i.y*tileheight+15
DrawText "par:"+i.parentx+","+i.parenty, i.x*tilewidth,i.y*tileheight+30
Next
End Method
Method isonopenlist:Bool(x:Int,y:Int)
For Local i:=Eachin myopenlist
If x = i.x And y = i.y Then
Return True
End If
Next
Return False
End Method
Method isonclosedlist:Bool(x:Int,y:Int)
For Local i:=Eachin myclosedlist
If x = i.x And y = i.y Then
Return True
End If
Next
Return False
End Method
Method draw()
SetColor 255,255,255
For Local y:Int = 0 Until mapheight
For Local x:Int = 0 Until mapheight
If map[x][y] = 1
SetColor 155,155,155
DrawRect x*tilewidth,y*tileheight,tilewidth,tileheight
End If
If sx = x And sy = y
SetColor 255,0,0
DrawOval x*tilewidth+10,y*tileheight,10,10
End If
If ex = x And ey = y
SetColor 255,255,0
DrawOval x*tilewidth+10,y*tileheight,10,10
End If
Next
Next
End Method
End Class
Class node
Field x:Int
Field y:Int
Field parentx:Int
Field parenty:Int
Method New(x:Int,y:Int,parentx:Int,parenty:Int)
Self.x = x
Self.y = y
Self.parentx = parentx
Self.parenty = parenty
End Method
End Class
Class path
Field x:Int
Field y:Int
Method New(x:Int,y:Int)
Self.x = x
Self.y = y
End Method
End Class
Class MyGame Extends App
Field pathfound:Bool=False
Field mysearch:search
Field cnt:Int=0
Method OnCreate()
Seed = GetDate[5] * GetDate[4]
SetUpdateRate(10)
mysearch = New search(DeviceWidth,DeviceHeight,10,10)
pathfound = mysearch.search(2,2,6,6)
End Method
Method OnUpdate()
cnt+=1
If KeyHit(KEY_SPACE) Or cnt>15
pathfound=False
cnt=0
Local w:Int=Rnd(10,50)
mysearch = New search(DeviceWidth,DeviceHeight,w,w)
pathfound = mysearch.search(Rnd(w),Rnd(w),Rnd(w),Rnd(w))
End If
End Method
Method OnRender()
Cls 0,0,0
mysearch.drawclosedlist
mysearch.draw
mysearch.drawpath
SetColor 255,255,255
If pathfound
DrawText "Path Found",0,0
End If
End Method
End Class
Function Main()
New MyGame()
End Function
Thursday, October 19, 2017
Monkey-X - Ai Taking Cover - Shooter - code example
Import mojo Class enemy Field x:Int,y:Int Field w:Int,h:Int Field state:String Field deleteme:Bool Field cooldown:Int Field waittime:Int Field path:List<pathnode> = New List<pathnode> Method New() w = mymap.tilewidth-4 h = mymap.tileheight-4 findstartpos() End Method Method update() ' enemy shoot diagnal If Rnd(100)<2 Then Local px:Int=myplayer.x Local py:Int=myplayer.y If distance(px,py,x,y) < 200 If px<x And py<y And mymap.mapcollide(x-5,y-5,w/3,h/3) = False mybullet.AddLast(New bullet(x,y,"leftup","enemy")) End If If px>x And py<y And mymap.mapcollide(x+5,y-5,w/3,h/3) = False mybullet.AddLast(New bullet(x,y,"rightup","enemy")) End If If px<x And py>y And mymap.mapcollide(x-5,y+5,w/3,h/3) = False mybullet.AddLast(New bullet(x,y,"leftdown","enemy")) End If If px>x And py>y And mymap.mapcollide(x+5,y+5,w/3,h/3) = False mybullet.AddLast(New bullet(x,y,"rightdown","enemy")) End If End If End If 'enemy shoot horizontal vertical If Rnd(100)<2 Then Local px:Int=myplayer.x Local py:Int=myplayer.y If distance(px,py,x,y) < 200 If px<x And mymap.mapcollide(x-5,y,w/3,h/3) = False mybullet.AddLast(New bullet(x,y,"left","enemy")) End If If px>x And mymap.mapcollide(x+5,y-5,w/3,h/3) = False mybullet.AddLast(New bullet(x,y,"right","enemy")) End If If py>y And mymap.mapcollide(x,y+5,w/3,h/3) = False mybullet.AddLast(New bullet(x,y,"down","enemy")) End If If py<y And mymap.mapcollide(x,y-5,w/3,h/3) = False mybullet.AddLast(New bullet(x,y,"up","enemy")) End If End If End If ' move around the enemy If path.IsEmpty = False ' add 2 to the destination coords or gets stuck Local dx:Int=path.First.x*mymap.tilewidth+2 Local dy:Int=path.First.y*mymap.tileheight+2 If x<dx And mymap.mapcollide(x+1,y,w,h) = False Then x+=1 If x>dx And mymap.mapcollide(x-1,y,w,h) = False Then x-=1 If y<dy And mymap.mapcollide(x,y+1,w,h) = False Then y+=1 If y>dy And mymap.mapcollide(x,y-1,w,h) = False Then y-=1 'if near destination If distance(x,y,dx,dy) < 2 Then path.RemoveFirst x = dx y = dy End If End If 'if no more moves left find new cover spot If path.IsEmpty If waittime>0 Then waittime-=1 If waittime<=0 For Local i:Int=0 Until 100 Local dx:Int=Rnd(2,mymap.mapwidth-2) Local dy:Int=Rnd(2,mymap.mapheight-2) If mymap.covermap[dx][dy] = 1 Then createpath(dx,dy) waittime=200 Exit End If Next End If End If 'if player is nearby then move to closest cover spot If distance(myplayer.x,myplayer.y,x,y) < 160 If cooldown>0 Then cooldown-=1 If cooldown=0 cooldown=100 Local d:Int=10000 Local destx:Int,desty:Int Local fnd:Bool=False ' random spots until coverspot, log closest For Local i:Int=0 Until 250 Local dx:Int=Rnd(2,mymap.mapwidth-2) Local dy:Int=Rnd(2,mymap.mapheight-2) If mymap.covermap[dx][dy] = 1 Then Local d2:Int = distance(dx,dy,x/mymap.tilewidth,y/mymap.tileheight) If d2 < d Then d = d2 destx = dx desty = dy fnd=True End If End If Next ' if we have a new dest then plan it If fnd=True Then createpath(destx,desty) End If End If End Method Method createpath(ex:Int,ey:Int) path = New List<pathnode> Local dx:Int=x/mymap.tilewidth Local dy:Int=y/mymap.tileheight ' x = dx*mymap.tilewidth ' y = dy*mymap.tileheight myastar.findpath(dx,dy,ex,ey) For Local i:=Eachin myastar.path path.AddLast(New pathnode(i.x,i.y)) Next End Method Method drawpath() SetColor 255,0,0 For Local i:=Eachin path DrawOval i.x*mymap.tilewidth,i.y*mymap.tileheight,w/2,h/2 Next End Method Method findstartpos() Local cnt:Int=400 Local cnt2:Int=0 Repeat Local nx:Int=Rnd(0,mymap.screenwidth-20) Local ny:Int=Rnd(0,mymap.screenheight-20) Local found:Bool=True ' if the map position a tile If mymap.mapcollide(nx,ny,w,h) Then found = False ' if the position is to close other enemy For Local i:=Eachin myenemy If i=Self Then Continue If distance(i.x,i.y,nx,ny) < 30 Then found = False ;Exit Next ' if the position to close to player If distance(myplayer.x,myplayer.y,nx,ny) < cnt Then found = False If found = True Then x = nx y = ny Exit Else If cnt>32 Then cnt -=1 End If Forever End Method Method draw() SetColor 255,0,255 DrawOval x,y,w,h End Method Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function End Class Class bullet Field x:Float,y:Float Field w:Int,h:Int Field mx:Int,my:Int Field direction:String Field deleteme:Bool=False Field speed:Int=2 Field shooter:String Method New(x:Int,y:Int,direction:String,shooter:String) Self.x = x Self.y = y Self.w = myplayer.w/3 Self.h = myplayer.h/3 Self.shooter = shooter Self.direction = direction If direction = "left" Then mx = -1 If direction = "right" Then mx = 1 If direction = "up" Then my = -1 If direction = "down" Then my = 1 If direction = "leftup" Then mx = -1 ; my = -1 If direction = "rightup" Then mx = 1 ; my = -1 If direction = "leftdown" Then mx = -1 ; my = 1 If direction = "rightdown" Then mx = 1 ; my = 1 End Method Method update() 'move the bullet and see collision with walls For Local i:Int=0 Until speed x += mx y += my If x < 0 Or x > mymap.screenwidth Then deleteme = True If y < 0 Or y > mymap.screenheight Then deleteme = True If mymap.mapcollide(x,y,w,h) Then deleteme = True Next ' collision with bullet vs enemy ' delete bullet and delete enemy If shooter = "player" For Local i:=Eachin myenemy If distance(i.x+(i.w/2),i.y+(i.h/2),x,y)<myplayer.w/1.5 Then deleteme = True i.deleteme = True End If Next End If ' collision with bullet vs player ' delete bullet and kill player If shooter = "enemy" If distance(myplayer.x+(myplayer.w/2),myplayer.y+(myplayer.h/2),x,y)<myplayer.w/1.5 Then deleteme = True myplayer.died = True End If End If End Method Method draw() SetColor 255,255,0 DrawOval x,y,w,h End Method Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function End Class Class player Field x:Float,y:Float Field w:Int,h:Int Field direction:String="up" Field died:Bool=False Method New() w = mymap.tilewidth-4 h = mymap.tileheight-4 findstartingpos() End Method Method update() playercontrols() makecovermap() End Method Method playercontrols() ' movement If KeyDown(KEY_UP) And Not mymap.mapcollide(x,y-1,w,h) y-=1 direction = "up" End If If KeyDown(KEY_LEFT) And Not mymap.mapcollide(x-1,y,w,h) x-=1 direction = "left" End If If KeyDown(KEY_RIGHT) And Not mymap.mapcollide(x+1,y,w,h) x+=1 direction = "right" End If If KeyDown(KEY_DOWN) And Not mymap.mapcollide(x,y+1,w,h) y+=1 direction = "down" End If If KeyDown(KEY_LEFT) And KeyDown(KEY_UP) Then direction = "leftup" If KeyDown(KEY_RIGHT) And KeyDown(KEY_UP) Then direction = "rightup" If KeyDown(KEY_LEFT) And KeyDown(KEY_DOWN) Then direction = "leftdown" If KeyDown(KEY_RIGHT) And KeyDown(KEY_DOWN) Then direction = "rightdown" ' shooting If KeyHit(KEY_F) mybullet.AddLast(New bullet(x,y,direction,"player")) End If End Method Method makecovermap() If Rnd(60)>2 Then Return For Local y:Int=0 Until mymap.mapheight For Local x:Int=0 Until mymap.mapwidth mymap.covermap[x][y] = 1 If mymap.map[x][y] <> 0 Then mymap.covermap[x][y] = 2 Next Next ' shoot bullets into random directions around ' the player and see if any position is a cover position For Local i:Int=0 Until 600 Local x2:Float=x Local y2:Float=y Local xa:Float=Rnd(-1,1) Local ya:Float=Rnd(-1,1) For Local d:Int=0 Until 40 x2+=xa*Float(mymap.tilewidth/2) y2+=ya*Float(mymap.tileheight/2) Local mx:Int=x2/mymap.tilewidth Local my:Int=y2/mymap.tileheight If mx>=0 And my>=0 And mx<mymap.mapwidth And my<mymap.mapheight mymap.covermap[mx][my] = 0 Else Exit End If If mymap.mapcollide(x2,y2,w/3,h/3) Then Exit Next Next ' ' Remove every coverpoint except if they ' are near a wall. For Local y2:Int=0 Until mymap.mapheight For Local x2:Int=0 Until mymap.mapwidth Local remove:Bool=True For Local y3:Int=y2-1 To y2+1 For Local x3:Int=x2-1 To x2+1 If x3<0 Or y3<0 Or x3>=mymap.mapwidth Or y3>=mymap.mapheight Then Continue If mymap.map[x3][y3] <> 0 Then remove = False ; Exit Next Next If remove = True Then mymap.covermap[x2][y2] = 0 End If Next Next 'if closer to the player then higher movement cost per tile For Local y2:Int=0 Until mymap.mapheight For Local x2:Int=0 Until mymap.mapwidth If myastar.map[x2][y2] <> 1000 Then myastar.map[x2][y2] = 100-distance(myplayer.x/mymap.tilewidth,myplayer.y/mymap.tileheight,x2,y2) If myastar.map[x2][y2] < 85 Then myastar.map[x2][y2] = 0 If mymap.covermap[x2][y2] = 1 Then myastar.map[x2][y2] = 0 Next Next End Method Method findstartingpos() Repeat Local x1:Int = Rnd(0,mymap.mapwidth) Local y1:Int = Rnd(0,mymap.mapheight) Local istaken:Bool=False For Local x2:Int=x1-4 To x1+4 For Local y2:Int=y1-4 To y1+4 If x2<0 Or y2<0 Or x2>=mymap.mapwidth Or y2>=mymap.mapheight Then Continue If mymap.map[x2][y2] <> 0 Then istaken = True ; Exit Next Next If istaken=False Then x = x1*mymap.tilewidth y = y1*mymap.tileheight Exit End If Forever End Method Method draw() SetColor 255,255,255 DrawOval x,y,w,h End Method Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function End Class Class astar Field mapwidth:Int,mapheight:Int Field sx:Int,sy:Int Field ex:Int,ey:Int Field olmap:Int[][] Field clmap:Int[][] Field map:Int[][] Field ol:List<openlist> = New List<openlist> Field cl:List<closedlist> = New List<closedlist> Field path:List<pathnode> = New List<pathnode> Field xstep:Int[] = [0,-1,1,0] Field ystep:Int[] = [-1,0,0,1] Method New() mapwidth = mymap.mapwidth mapheight = mymap.mapheight olmap = New Int[mapwidth][] clmap = New Int[mapwidth][] map = New Int[mapwidth][] For Local i:Int=0 Until mapwidth olmap[i] = New Int[mapheight] clmap[i] = New Int[mapheight] map[i] = New Int[mapheight] Next ' Copy the map into the astar class map For Local y:=0 Until mapheight For Local x:=0 Until mapwidth map[x][y] = mymap.map[x][y] Next Next End Method ' This creates the map and copies the ' path in the path list Method findpath:Bool(sx:Int,sy:Int,ex:Int,ey:Int) If sx = ex And sy = ey Then Return False Self.sx = sx Self.sy = sy Self.ex = ex Self.ey = ey For Local y=0 Until mapheight For Local x=0 Until mapwidth olmap[x][y] = 0 clmap[x][y] = 0 Next Next ol.Clear cl.Clear path.Clear ol.AddFirst(New openlist(sx,sy)) Local tx:Int Local ty:Int Local tf:Int Local tg:Int Local th:Int Local tpx:Int Local tpy:Int Local newx:Int Local newy:Int Local lowestf:Int olmap[sx][sy] = 1 While ol.IsEmpty() = False lowestf = 100000 For Local i:=Eachin ol If i.f < lowestf lowestf = i.f tx = i.x ty = i.y tf = i.f tg = i.g th = i.h tpx = i.px tpy = i.py End If Next If tx = ex And ty = ey cl.AddLast(New closedlist(tx,ty,tpx,tpy)) findpathback Return True Else removefromopenlist(tx,ty) olmap[tx][ty] = 0 clmap[tx][ty] = 1 cl.AddLast(New closedlist(tx,ty,tpx,tpy)) For Local i:Int=0 Until xstep.Length Local x:Int=xstep[i] Local y:Int=ystep[i] newx = tx+x newy = ty+y If newx>=0 And newy>=0 And newx<mapwidth And newy<mapheight If olmap[newx][newy] = 0 If clmap[newx][newy] = 0 olmap[newx][newy] = 1 Local gg = map[newx][newy]+1 Local hh = distance(newx,newy,ex,ey) Local ff = gg+hh ol.AddLast(New openlist(newx,newy,ff,gg,hh,tx,ty)) End If End If End If Next End If Wend Return False End Method Method drawpath:Void() Local cnt:Int=1 For Local i:=Eachin path SetColor 255,255,0 DrawOval i.x*mymap.tilewidth,i.y*mymap.tileheight,4,4 SetColor 255,255,255 DrawText cnt,i.x*mymap.tilewidth,i.y*mymap.tileheight cnt+=1 Next End Method ' Here we calculate back from the end back to the ' start and create the path list. Method findpathback:Bool() Local x=ex Local y=ey path.AddFirst(New pathnode(x,y)) Repeat For Local i:=Eachin cl If i.x = x And i.y = y x = i.px y = i.py path.AddFirst(New pathnode(x,y)) End If Next If x = sx And y = sy Then Return True Forever End Method Method removefromopenlist:Void(x1:Int,y1:Int) For Local i:=Eachin ol If i.x = x1 And i.y = y1 ol.Remove i Exit End If Next End Method Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function End Class Class map Field mapwidth:Int Field mapheight:Int Field screenwidth:Int Field screenheight:Int Field tilewidth:Float Field tileheight:Float Field map:Int[][] Field covermap:Int[][] Method New(screenwidth:Int,screenheight:Int,mapwidth:Int,mapheight:Int) Self.screenheight = screenheight Self.screenwidth = screenwidth Self.mapwidth = mapwidth Self.mapheight = mapheight tilewidth = Float(screenwidth) / Float(mapwidth) tileheight = Float(screenheight) / Float(mapheight) map = New Int[mapwidth][] covermap = New Int[mapwidth][] For Local i:Int=0 Until mapwidth map[i] = New Int[mapheight] covermap[i] = New Int[mapheight] Next makemap(10) End Method Method makemap:Void(numobstacles:Int) For Local y=0 Until mapheight For Local x=0 Until mapwidth map[x][y] = 0 Next Next ' Here we create short lines on the map ' and sometimes draw some random blocks near them. For Local i:Int=0 Until numobstacles Local x1:Int=Rnd(4,mapwidth-4) Local y1:Int=Rnd(4,mapheight-4) Local dist:Int=Rnd(3,5) Local angle:Int=Rnd(0,360) Local x2:Float=x1 Local y2:Float=y1 While dist >= 0 x2 += Cos(angle) * 1 y2 += Sin(angle) * 1 dist -= 1 If x2<0 Or y2<0 Or x2>=mapwidth Or y2>=mapheight Then continue map[x2][y2] = 1000 ' If Rnd(10) < 2 Then ' If x2>2 And x2<mymap.mapwidth-2 And y2>2 And y2<mymap.mapheight-2 Then ' map[x2+Rnd(-1,1)][y2+Rnd(-1,1)] = 10 ' end if ' End If Wend Next End Method Method mapcollide:Bool(x:Int,y:Int,w:Int,h:Int) Local lefttopx:Int =((x)/tilewidth) Local lefttopy:Int =((y)/tileheight) Local righttopx:Int =((x+w)/tilewidth) Local righttopy:Int =((y)/tileheight) Local leftbottomx:Int =((x)/tilewidth) Local leftbottomy:Int =((y+h)/tileheight) Local rightbottomx:Int =((x+w)/tilewidth) Local rightbottomy:Int =((y+h)/tileheight) If lefttopx < 0 Or lefttopx >= mapwidth Then Return True If lefttopy < 0 Or lefttopy >= mapheight Then Return True If righttopx < 0 Or righttopx >= mapwidth Then Return True If righttopy < 0 Or righttopy >= mapheight Then Return True If leftbottomx < 0 Or leftbottomx >= mapwidth Then Return True If leftbottomy < 0 Or leftbottomy >= mapheight Then Return True If rightbottomx < 0 Or rightbottomx >= mapwidth Then Return True If rightbottomy < 0 Or rightbottomy >= mapheight Then Return True If map[lefttopx][lefttopy] <> 0 Then Return True If map[righttopx][righttopy] <> 0 Then Return True If map[leftbottomx][leftbottomy] <> 0 Then Return True If map[rightbottomx][rightbottomy] <> 0 Then Return True Return False End Method Method drawmap:Void() For Local y=0 Until mapheight For Local x=0 Until mapwidth If map[x][y] = 1000 SetColor 255,255,255 DrawRect x*tilewidth,y*tileheight,tilewidth,tileheight End If Next Next End Method Method drawcovermap:Void() For Local y=0 Until mapheight For Local x=0 Until mapwidth If covermap[x][y] = 1 SetColor 0,15,0 DrawOval x*mymap.tilewidth,y*mymap.tileheight,tilewidth,tileheight End If Next Next End Method Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function End Class ' The open list used by the astar Class openlist Field x:Int Field y:Int Field f:Int Field g:Int Field h:Int Field px:Int Field py:Int Method New( x:Int=0,y:Int=0,f:Int=0, g:Int=0,h:Int=0,px:Int=0,py:Int=0) Self.x=x Self.y=y Self.f=f Self.g=g Self.h=h Self.px=px Self.py=py End Method End Class ' The closed list used by the astar Class closedlist Field x:Int Field y:Int Field px:Int Field py:Int Method New(x:Int,y:Int,px:Int,py:Int) Self.x = x Self.y = y Self.px = px Self.py = py End Method End Class ' the pathnodes (x and y variables) ' used by the astar Class pathnode Field x:Int Field y:Int Method New(x:Int,y:Int) Self.x = x Self.y = y End Method End Class Global mymap:map Global myastar:astar Global myplayer:player Global mybullet:List<bullet> = New List<bullet> Global myenemy:List<enemy> = New List<enemy> Class MyGame Extends App Field playerwins:Int Field enemywins:Int Method OnCreate() Seed = GetDate[4] * GetDate[5] SetUpdateRate(60) ' Create a new map mymap = New map(DeviceWidth(),DeviceHeight(),30,30) myastar = New astar() myplayer = New player() For Local i:Int=0 Until 10 myenemy.AddLast(New enemy()) Next End Method Method OnUpdate() myplayer.update() For Local i:=Eachin myenemy i.update() Next For Local i:=Eachin myenemy If i.deleteme = True Then myenemy.Remove(i) Next For Local i:=Eachin mybullet i.update() Next For Local i:=Eachin mybullet If i.deleteme = True Then mybullet.Remove(i) Next ' if no more enemies then reset level If myenemy.IsEmpty Or myplayer.died Or KeyHit(KEY_TILDE) If myplayer.died Then enemywins+=1 If myenemy.IsEmpty Then playerwins+=1 mymap = New map(DeviceWidth(),DeviceHeight(),30,30) myastar = New astar() myenemy = New List<enemy> mybullet = New List<bullet> myplayer = New player() For Local i:Int=0 Until 10 myenemy.AddLast(New enemy()) Next End If End Method Method OnRender() Cls 0,0,0 SetColor 255,255,255 mymap.drawmap() mymap.drawcovermap() For Local i:=Eachin myenemy i.draw() Next For Local i:=Eachin mybullet i.draw() Next myplayer.draw() 'drawdebug SetColor 255,255,255 DrawText "AI - 'Taking Cover' Locations - Example.`(Tilde = new level)",0,DeviceHeight-15 DrawText "Controls - cursor u/d/l/r and F - fire",0,15 DrawText "Matches Player Wins : " + playerwins + " vs Enemy Wins : " + enemywins,DeviceWidth/2,0,.5,0 End Method End Class Function drawdebug() SetColor 255,255,255 For Local i:=Eachin myenemy i.drawpath() Next Return Scale(.7,.7) For Local y:Int=0 Until mymap.mapwidth For Local x:Int=0 Until mymap.mapheight DrawText myastar.map[x][y],(x*mymap.tilewidth)*1.4,(y*mymap.tileheight)*1.4 Next Next End Function Function Main() New MyGame() End Function
Monkey-X - Astar Pathfinding - Object Oriented - code example
' New Object oriented version of my Astar Code. Import mojo Class astar Field mapwidth:Int,mapheight:Int Field sx:Int,sy:Int Field ex:Int,ey:Int Field olmap:Int[][] Field clmap:Int[][] Field map:Int[][] Field ol:List<openlist> = New List<openlist> Field cl:List<closedlist> = New List<closedlist> Field path:List<pathnode> = New List<pathnode> Method New() mapwidth = mymap.mapwidth mapheight = mymap.mapheight olmap = New Int[mapwidth][] clmap = New Int[mapwidth][] map = New Int[mapwidth][] For Local i:Int=0 Until mapwidth olmap[i] = New Int[mapheight] clmap[i] = New Int[mapheight] map[i] = New Int[mapheight] Next ' Copy the map into the astar class map For Local y:=0 Until mapheight For Local x:=0 Until mapwidth map[x][y] = mymap.map[x][y] Next Next End Method ' This creates the map and copies the ' path in the path list Method findpath:Bool(sx:Int,sy:Int,ex:Int,ey:Int) If sx = ex And sy = ey Then Return False Self.sx = sx Self.sy = sy Self.ex = ex Self.ey = ey For Local y=0 Until mapheight For Local x=0 Until mapwidth olmap[x][y] = 0 clmap[x][y] = 0 Next Next ol.Clear cl.Clear path.Clear ol.AddFirst(New openlist(sx,sy)) Local tx:Int Local ty:Int Local tf:Int Local tg:Int Local th:Int Local tpx:Int Local tpy:Int Local newx:Int Local newy:Int Local lowestf:Int olmap[sx][sy] = 1 While ol.IsEmpty() = False lowestf = 100000 For Local i:=Eachin ol If i.f < lowestf lowestf = i.f tx = i.x ty = i.y tf = i.f tg = i.g th = i.h tpx = i.px tpy = i.py End If Next If tx = ex And ty = ey cl.AddLast(New closedlist(tx,ty,tpx,tpy)) findpathback Return True Else removefromopenlist(tx,ty) olmap[tx][ty] = 0 clmap[tx][ty] = 1 cl.AddLast(New closedlist(tx,ty,tpx,tpy)) For Local y=-1 To 1 For Local x=-1 To 1 newx = tx+x newy = ty+y If newx>=0 And newy>=0 And newx<mapwidth And newy<mapheight If olmap[newx][newy] = 0 If clmap[newx][newy] = 0 olmap[newx][newy] = 1 Local gg = map[newx][newy]+1 Local hh = distance(newx,newy,ex,ey) Local ff = gg+hh ol.AddLast(New openlist(newx,newy,ff,gg,hh,tx,ty)) End If End If End If Next Next End If Wend Return False End Method Method drawpath:Void() Local cnt:Int=1 For Local i:=Eachin path SetColor 255,255,0 DrawOval i.x*mymap.tilewidth,i.y*mymap.tileheight,4,4 SetColor 255,255,255 DrawText cnt,i.x*mymap.tilewidth,i.y*mymap.tileheight cnt+=1 Next End Method ' Here we calculate back from the end back to the ' start and create the path list. Method findpathback:Bool() Local x=ex Local y=ey path.AddFirst(New pathnode(x,y)) Repeat For Local i:=Eachin cl If i.x = x And i.y = y x = i.px y = i.py path.AddFirst(New pathnode(x,y)) End If Next If x = sx And y = sy Then Return True Forever End Method Method removefromopenlist:Void(x1:Int,y1:Int) For Local i:=Eachin ol If i.x = x1 And i.y = y1 ol.Remove i Exit End If Next End Method Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function End Class Class map Field mapwidth:Int Field mapheight:Int Field screenwidth:Int Field screenheight:Int Field tilewidth:Float Field tileheight:Float Field map:Int[][] Method New(screenwidth:Int,screenheight:Int,mapwidth:Int,mapheight:Int) Self.screenheight = screenheight Self.screenwidth = screenwidth Self.mapwidth = mapwidth Self.mapheight = mapheight tilewidth = Float(screenwidth) / Float(mapwidth) tileheight = Float(screenheight) / Float(mapheight) map = New Int[mapwidth][] For Local i:Int=0 Until mapwidth map[i] = New Int[mapheight] Next makemap() End Method Method makemap:Void() For Local y=0 Until mapheight For Local x=0 Until mapwidth map[x][y] = 0 Next Next Local lowest = 0 While lowest < 13 Local x1 = Rnd(mapwidth) Local y1 = Rnd(mapheight) Local radius = Rnd(3,6) For Local y2=-radius To radius For Local x2=-radius To radius If ((x2*x2)+(y2*y2)) <= radius*radius+radius*0.8 Local x3 = x1+x2 Local y3 = y1+y2 If x3>=0 And y3>=0 And x3<mapwidth And y3<mapheight map[x3][y3]=map[x3][y3]+1 If map[x3][y3] > lowest Then lowest = map[x3][y3] End If End If Next Next Wend End Method Method drawmap:Void() For Local y=0 Until mapheight For Local x=0 Until mapwidth SetColor 0,map[x][y]*10,0 DrawRect x*tilewidth,y*tileheight,tilewidth,tileheight Next Next End Method End Class ' The open list used by the astar Class openlist Field x:Int Field y:Int Field f:Int Field g:Int Field h:Int Field px:Int Field py:Int Method New( x:Int=0,y:Int=0,f:Int=0, g:Int=0,h:Int=0,px:Int=0,py:Int=0) Self.x=x Self.y=y Self.f=f Self.g=g Self.h=h Self.px=px Self.py=py End Method End Class ' The closed list used by the astar Class closedlist Field x:Int Field y:Int Field px:Int Field py:Int Method New(x:Int,y:Int,px:Int,py:Int) Self.x = x Self.y = y Self.px = px Self.py = py End Method End Class ' the pathnodes (x and y variables) ' used by the astar Class pathnode Field x:Int Field y:Int Method New(x:Int,y:Int) Self.x = x Self.y = y End Method End Class Global mymap:map Global myastar:astar Class MyGame Extends App Method OnCreate() SetUpdateRate(1) ' Create a new map mymap = New map(DeviceWidth(),DeviceHeight(),30,30) ' Initiate the astar. Here the map from the mymap ' is copied into. Recreate this everytime the map is ' modified.. ' the map from the mymap should contain the heights/terrain ' costs. A tile with a high value is less likely to be chosen. myastar = New astar() End Method Method OnUpdate() ' create 2 unique start and end coordinates Local exitloop:Bool=False Local sx:Int,sy:Int,ex:Int,ey:Int While exitloop = False sx = Rnd(mymap.mapwidth) sy = Rnd(mymap.mapheight) ex = Rnd(mymap.mapwidth) ey = Rnd(mymap.mapheight) If sx <> ex And sy <> ey exitloop = True End If Wend ' Find/create the path myastar.findpath(sx,sy,ex,ey) End Method Method OnRender() Cls 0,0,0 SetColor 255,255,255 mymap.drawmap() myastar.drawpath() SetColor 255,255,255 DrawText "a Star Pathfinding example",0,0 End Method End Class Function Main() New MyGame() End Function
Wednesday, October 11, 2017
Monkey-X - Player vs Monsters on Random Map - code example
'Based on the game Legend of Pandora.
Import mojo Global tilewidth:Int=10 Global tileheight:Int=10 Class map Field tilewidth:Float Field tileheight:Float Field mapwidth:Int Field mapheight:Int Field screenwidth:Int Field screenheight:Int Field map:Int[][] Method New( screenwidth:Int, screenheight:Int, mapwidth:Int, mapheight:Int) Self.screenwidth = screenwidth Self.screenheight = screenheight Self.mapwidth = mapwidth Self.mapheight = mapheight Self.tilewidth = Float(screenwidth)/Float(mapwidth) Self.tileheight = Float(screenheight)/Float(mapheight) map = New Int[mapwidth][] For Local i=0 Until mapwidth map[i] = New Int[mapheight] Next map[mapwidth/2][mapheight/2] = 3 ' 3 is a door makemap End Method Method makemap() Local timeout:Int While timeout<(mapwidth*mapheight)*20 timeout+=1 Local x:Int=Rnd(11,mapwidth-11) Local y:Int=Rnd(11,mapheight-11) If map[x][y] = 3 makeroom(x,y) End If Wend 'here we turn doors into walls 'if they should be walls For Local y1=1 Until mapheight-1 For Local x1=1 Until mapwidth-1 If map[x1][y1] = 3 Local cnt:Int=0 For Local y2=y1-1 To y1+1 For Local x2=x1-1 To x1+1 If map[x2][y2] = 2 Then cnt+=1 Next Next If cnt>3 Then map[x1][y1] = 2 End If Next Next 'here we turn doors into walls if they ' touch tiles that are nothing (0) For Local y1=1 Until mapheight-1 For Local x1=1 Until mapwidth-1 If map[x1][y1] = 3 Local cnt:Int=0 For Local y2=y1-1 To y1+1 For Local x2=x1-1 To x1+1 If map[x2][y2] = 0 Then cnt+=1 Next Next If cnt>0 Then map[x1][y1] = 2 End If Next Next 'here we turn the doors into floors For Local y1=0 Until mapheight For Local x1=0 Until mapwidth If map[x1][y1] = 3 Then map[x1][y1] = 1 Next Next End Method Method makeroom(x:Int,y:Int) Local side:String If map[x][y-1] = 0 side="up" Elseif map[x+1][y] = 0 side="right" Elseif map[x][y+1] = 0 side="down" Elseif map[x-1][y] = 0 side="left" End If Local w:Int=Rnd(5,10) Local h:Int=Rnd(5,10) If side="up" Local x1:Int=x-w/2 Local y1:Int=y-h If roomfits(x1,y1,w,h) insertroom(x1,y1,w,h+1) 'door up map[x1+Rnd(2,w-2)][y1] = 3 ' door right map[x1+w-1][y1+Rnd(2,h-2)] = 3 'door left map[x1][y1+Rnd(2,h-2)] = 3 End If End If If side="right" Local x1:Int=x+1 Local y1:Int=y-h/2 If roomfits(x1,y1,w,h) insertroom(x1-1,y1,w,h) 'door up map[x1+Rnd(2,w-2)][y1] = 3 'door down map[x1+Rnd(2,w-2)][y1+h-1] = 3 ' door right map[x1+w-2][y1+Rnd(2,h-2)] = 3 End If End If If side="left" Local x1:Int=x-w Local y1:Int=y-h/2 If roomfits(x1,y1,w,h) insertroom(x1,y1,w+1,h) 'door up map[x1+Rnd(2,w-2)][y1] = 3 'door down map[x1+Rnd(2,w-2)][y1+h-1] = 3 'door left map[x1][y1+Rnd(2,h-2)] = 3 End If End If If side="down" Local x1:Int=x-w/2 Local y1:Int=y+1 If roomfits(x1,y1,w,h) insertroom(x1,y1-1,w,h) 'door down map[x1+Rnd(2,w-2)][y1+h-2] = 3 'door left map[x1][y1+Rnd(2,h-2)] = 3 ' door right map[x1+w-1][y1+Rnd(2,h-2)] = 3 End If End If End Method Method insertroom(x,y,w,h) For Local y2=y Until y+h For Local x2=x Until x+w If map[x2][y2] <> 3 Then map[x2][y2] = 2 Next Next For Local y2=y+1 Until y+h-1 For Local x2=x+1 Until x+w-1 map[x2][y2] = 1 Next Next End Method Method roomfits(x:Int,y:Int,w:Int,h:Int) For Local y1=y Until y+h For Local x1=x Until x+w If map[x1][y1] = 1 Then Return False Next Next Return True End Method Method draw() For Local y=0 Until mapheight For Local x=0 Until mapwidth Select map[x][y] Case 0 Case 1'floor SetColor 100,100,100 DrawRect x*tilewidth, y*tileheight, tilewidth+1, tileheight+1 Case 2'wall SetColor 200,200,200 DrawRect x*tilewidth, y*tileheight, tilewidth+1, tileheight+1 Case 3'wall SetColor 244,244,0 DrawRect x*tilewidth, y*tileheight, tilewidth+1, tileheight+1 End Select Next Next End Method End Class Class enemy Field x:Float,y:Float Field ms:Float 'movement speed Field w:Int=mymap.tilewidth-8 Field h:Int=mymap.tileheight-8 Field hp:Int Field hpceil:Int Field direction:String="up" ' left/right/up/down Field current:Bool=False 'if being updated Field deleteme:Bool=False Method New() ' find a spot to place the new enemy Local exitloop:Bool=False Local cnt:Int=0 While exitloop=False exitloop = True Local nx = Rnd(50,640-50) Local ny = Rnd(50,480-50) Local mx:Int=nx/mymap.tilewidth Local my:Int=ny/mymap.tileheight If mymap.map[mx][my] <> 1 Then exitloop = False For Local i:=Eachin myenemy If distance(nx,ny,i.x,i.y) < 30 Or distance(myplayer.x,myplayer.y,nx,ny) < 250-cnt exitloop = False End If Next If exitloop = True Then x = nx y = ny End If cnt+=1 Wend ' Here we set the movement speed ms = Rnd(.1,.5) ' Here we set the hitpoints hp = Rnd(1,50) ' the ceiling is what he has or had at start (powerbar) hpceil = hp End Method Method update() current=True ' store the old location Local oldx:Float=x Local oldy:Float=y ' move the enemy towards the player If collide(x+1,y) = False And x < myplayer.x Then x+=ms direction = "right" End If If collide(x-1,y) = False And x > myplayer.x Then x-=ms direction = "left" End If If collide(x,y+1) = False And y < myplayer.y Then y+=ms direction = "down" End If If collide(x,y-1) = False And y > myplayer.y Then y-=ms direction = "up" End If untangle() current=False End Method ' if the enemies are inside of each other ' then move them apart Method untangle() For Local i:=Eachin myenemy If i.current=False If distance(i.x,i.y,x,y) < w Local a:Int a = getangle(i.x,i.y,x,y) Local nx:Float=x Local ny:Float=y nx += Cos(a)*1 ny += Sin(a)*1 Local mx:Int=nx/mymap.tilewidth Local my:Int=ny/mymap.tileheight If mymap.map[mx][my] = 1 x = nx y = ny End If End If End If Next End Method Method draw() SetColor 255,255,0 DrawOval x-w/2,y-w/2,w,w 'powerbar Local current:Float=(Float(w)/Float(hpceil))*hp SetColor 0,0,0 DrawRect x-w/2,y+w/2,w,5 SetColor 255,0,0 DrawRect x-w/2,y+1+w/2,current,3 End Method Method collide:Bool(xx:Int,yy:Int) For Local i:=Eachin myenemy If i.current = False If distance(xx,yy,i.x,i.y) < w Then Return True End If Next Local mx:Int=xx/mymap.tilewidth Local my:Int=yy/mymap.tileheight If mymap.map[mx][my] <> 1 Then Return true Return False End Method Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int) Local dx = x2 - x1 Local dy = y2 - y1 Return ATan2(dy,dx)+360 Mod 360 End Function End Class Class player Field x:Float,y:Float Field w:Int=mymap.tilewidth-8 Field h:Int=mymap.tileheight-8 Field wx:Int,wy:Int Field direction:String="up" ' up/left/down/right Field weapondamage:Int=3 Field swing:Bool=False Field swingcountdown:Int=0 Method New() Local exitloop:Bool=False While exitloop = False x = Rnd(640) y = Rnd(480) Local mx:Int=x/mymap.tilewidth Local my:Int=y/mymap.tileheight If mymap.map[mx][my] = 1 Then exitloop = True Wend direction = "up" End Method Method update() updatecontrols() weaponenemies() End Method Method weaponenemies() If swing = False Then Return For Local i:=Eachin myenemy If distance(i.x,i.y,wx,wy) < w+5 'make sure the weapon does not hit throught ' walls Local mx:Int=wx/mymap.tilewidth Local my:Int=wy/mymap.tileheight If mymap.map[mx][my] <> 1 Then Exit 'distance with the enemy Local a:Int=getangle(wx,wy ,i.x,i.y) For Local ww:Int=0 Until w Local nx:Float=i.x Local ny:Float=i.y nx += Cos(a) * 1 ny += Sin(a) * 1 Local mx:Int=nx/mymap.tilewidth Local my:Int=ny/mymap.tileheight If mymap.map[mx][my] = 1 Then i.x = nx i.y = ny Else Exit End If Next i.hp -= weapondamage If i.hp<1 Then i.deleteme = True End If Next End Method Method updatecontrols() ' store the location of the player Local oldx:Int=x Local oldy:Int=y 'handle the movement If collide(x+1,y)=False And KeyDown(KEY_RIGHT) Then x+=1 direction = "right" swing=False End If If collide(x-1,y)=False And KeyDown(KEY_LEFT) Then x-=1 direction = "left" swing=False End If If collide(x,y-1)=False And KeyDown(KEY_UP) Then y-=1 direction = "up" swing=False End If If collide(x,y+1)=False And KeyDown(KEY_DOWN) Then y+=1 direction = "down" swing=False End If 'Handle the weapon If swing = False If KeyDown(KEY_SPACE) Then swing=True If direction = "left" Then wx=x-w ; wy=y If direction = "right" Then wx=x+w ; wy=y If direction = "up" Then wx=x ; wy=y-h If direction = "down" Then wx=x ; wy=y+h swingcountdown = 20 End If Else swingcountdown-=1 If swingcountdown<0 Then swing=False End If End Method ' collide with map Method collide:Bool(xx:Int,yy:Int) Local mx:Int=xx/mymap.tilewidth Local my:Int=yy/mymap.tileheight If mymap.map[mx][my] <> 1 Then Return True Return False End Method Method draw() SetColor 255,100,0 DrawOval x-w/2,y-w/2,w,w If swing = True 'where does the swing graphic get drawn DrawOval wx-w/2,wy-w/2,w,w End If End Method Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int) Local dx = x2 - x1 Local dy = y2 - y1 Return ATan2(dy,dx)+360 Mod 360 End Function Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function End Class Global myplayer:player Global myenemy:List<enemy> = New List<enemy> Global mymap:map Class MyGame Extends App Method OnCreate() SetUpdateRate(60) mymap = New map(640,480,30,30) myplayer = New player() 'For Local i:=0 Until 10 ' myenemy.AddLast(New enemy()) 'Next End Method Method OnUpdate() myplayer.update() ' update the enemies For Local i:=Eachin myenemy i.update() Next ' if enemy hitpoint below 1 then remove him from list For Local i:=Eachin myenemy If i.deleteme = True Then myenemy.Remove(i) Next If myenemy.IsEmpty Local ms:Int=Rnd(30,36) mymap = New map(640,480,ms,ms) myplayer = New player() Local ecnt:Int=Rnd(2,10) For Local i:=0 Until ecnt myenemy.AddLast(New enemy()) Next End If End Method Method OnRender() Cls 0,0,0 mymap.draw() For Local i:=Eachin myenemy i.draw() Next myplayer.draw() SetColor 255,255,255 DrawText "Player vs Monsters on Random map",0,0 DrawText "Space = Weapon , Cursor l/r/u/d = movement",0,20 End Method End Class Function Main() New MyGame() End Function
Monkey-X - Player vs Monsters on Empty map - code example
' I programmed this after playing the game Legend of Pandora.
Import mojo Class enemy Field x:Float,y:Float Field ms:Float 'movement speed Field w:Int=32 Field h:Int=32 Field hp:Int Field hpceil:Int Field direction:String="up" ' left/right/up/down Field current:Bool=False 'if being updated Field deleteme:Bool=False Method New() ' find a spot to place the new enemy Local exitloop:Bool=False While exitloop=False exitloop = True Local nx = Rnd(50,640-50) Local ny = Rnd(50,480-50) For Local i:=Eachin myenemy If distance(nx,ny,i.x,i.y) < 30 Or distance(myplayer.x,myplayer.y,nx,ny) < 250 exitloop = False End If Next If exitloop = True Then x = nx y = ny End If Wend ' Here we set the movement speed ms = Rnd(.1,.5) ' Here we set the hitpoints hp = Rnd(1,50) ' the ceiling is what he has or had at start (powerbar) hpceil = hp End Method Method update() current=True ' store the old location Local oldx:Float=x Local oldy:Float=y ' move the enemy towards the player If collide(x+1,y) = False And x < myplayer.x Then x+=ms direction = "right" End If If collide(x-1,y) = False And x > myplayer.x Then x-=ms direction = "left" End If If collide(x,y+1) = False And y < myplayer.y Then y+=ms direction = "down" End If If collide(x,y-1) = False And y > myplayer.y Then y-=ms direction = "up" End If untangle() current=False End Method Method untangle() For Local i:=Eachin myenemy If i.current=False If distance(i.x,i.y,x,y) < w Local a:Int a = getangle(i.x,i.y,x,y) x += Cos(a)*1 y += Sin(a)*1 End If End If Next End Method Method draw() SetColor 255,255,0 DrawOval x-w/2,y-w/2,w,w 'powerbar Local current:Float=(Float(w)/Float(hpceil))*hp SetColor 0,0,0 DrawRect x-w/2,y+w/2,w,5 SetColor 255,0,0 DrawRect x-w/2,y+1+w/2,current,3 End Method Method collide:Bool(xx:Int,yy:Int) For Local i:=Eachin myenemy If i.current = False If distance(xx,yy,i.x,i.y) < w Then Return True End If Next Return False End Method Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int) Local dx = x2 - x1 Local dy = y2 - y1 Return ATan2(dy,dx)+360 Mod 360 End Function End Class Class player Field x:Float,y:Float Field w:Int=32 Field h:Int=32 Field wx:Int,wy:Int Field direction:String="up" ' up/left/down/right Field weapondamage:Int=3 Field swing:Bool=False Field swingcountdown:Int=0 Method New(x:Int,y:Int) Self.x = x Self.y = y direction = "up" End Method Method update() updatecontrols() weaponenemies() End Method Method weaponenemies() If swing = False Then Return For Local i:=Eachin myenemy If distance(i.x,i.y,wx,wy) < 48 Local a:Int=getangle(wx,wy ,i.x,i.y) i.x += Cos(a) * 32 i.y += Sin(a) * 32 i.hp -= weapondamage If i.hp<1 Then i.deleteme = True End If Next End Method Method updatecontrols() ' store the location of the player Local oldx:Int=x Local oldy:Int=y 'handle the movement If KeyDown(KEY_RIGHT) Then x+=1 direction = "right" swing=False End If If KeyDown(KEY_LEFT) Then x-=1 direction = "left" swing=False End If If KeyDown(KEY_UP) Then y-=1 direction = "up" swing=False End If If KeyDown(KEY_DOWN) Then y+=1 direction = "down" swing=False End If 'Handle the weapon If swing = False If KeyDown(KEY_SPACE) Then swing=True If direction = "left" Then wx=x-w ; wy=y If direction = "right" Then wx=x+w ; wy=y If direction = "up" Then wx=x ; wy=y-h If direction = "down" Then wx=x ; wy=y+h swingcountdown = 20 End If Else swingcountdown-=1 If swingcountdown<0 Then swing=False End If End Method Method draw() SetColor 255,100,0 DrawOval x-w/2,y-w/2,w,w If swing = True 'where does the swing graphic get drawn DrawOval wx-w/2,wy-w/2,w,w End If End Method Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int) Local dx = x2 - x1 Local dy = y2 - y1 Return ATan2(dy,dx)+360 Mod 360 End Function Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int) Return Abs(x2-x1)+Abs(y2-y1) End Function End Class Global myplayer:player Global myenemy:List<enemy> = New List<enemy> Class MyGame Extends App Method OnCreate() SetUpdateRate(60) myplayer = New player(DeviceWidth()/2,DeviceHeight()/2) 'For Local i:=0 Until 10 ' myenemy.AddLast(New enemy()) 'Next End Method Method OnUpdate() myplayer.update() ' update the enemies For Local i:=Eachin myenemy i.update() Next ' if enemy hitpoint below 1 then remove him from list For Local i:=Eachin myenemy If i.deleteme = True Then myenemy.Remove(i) Next If myenemy.IsEmpty Local ecnt:Int=Rnd(2,10) For Local i:=0 Until ecnt myenemy.AddLast(New enemy()) Next End If End Method Method OnRender() Cls 0,0,0 For Local i:=Eachin myenemy i.draw() Next myplayer.draw() SetColor 255,255,255 DrawText "Player vs Monsters on empty map",0,0 DrawText "Space = Weapon , Cursor l/r/u/d = movement",0,20 End Method End Class Function Main() New MyGame() End Function
Subscribe to:
Posts (Atom)