'diffusion limited aggregation (dla) ' This basically works like this. ' You create random walkers(dots) They move into a random direction. ' On the map there is a solid part and if the walker touches it he turns ' into a solid part. This is it. Import mojo ' The random walker class. We only use it to store ' the x and y coordinates Class walker Field x:Int,y:Int Field deleteme:Bool Method New(x:Int,y:Int) Self.x = x Self.y = y End Method End Class Class dla ' map width/height screen width/height ' tile width/height ' map containing the solids parts. ' The walker list containing the walkers Field mw:Int,mh:Int,sw:Int,sh:Int Field tw:Float,th:Float Field map:Int[][] Field mywalker:List<walker> Field walkerradius:Int=1 Field finished:Bool=False Method New(sw:Int,sh:Int,mw:Int,mh:Int) Self.sw = sw Self.sh = sh Self.mw = mw Self.mh = mh Self.tw = Float(sw) / Float(mw) Self.th = Float(sh) / Float(mh) ' create our map array map = New Int[mw][] For Local i:=0 Until mw map[i] = New Int[mh] Next ' create the solid part mapcircle(mw/2,mh/2) ' create the walker list mywalker = New List<walker> 'add some walkers to the list For Local i:=0 Until mw*mh/20 addwalker(Rnd(4)) Next End Method ' Here we update the walkers. We keep adding them to ' the screen until they have created a solid part ' on the most part of the screen. Method update() ' speed it up For Local speed:Int=0 Until 20 ' loop through each walker on the list For Local i:=Eachin mywalker ' step in one of 8 directions Local x:Int=Rnd(-2,2) Local y:Int=Rnd(-2,2) ' if we are not moving outside of the map ' then update position If i.x+x >= 0 And i.x+x < mw Then i.x += x If i.y+y >= 0 And i.y+y < mh Then i.y += y ' if we touch a solid then If map[i.x][i.y] = 1 Then ' flag for deletion i.deleteme = True ' if the last position was not near the edge of the screen If i.x > 10 And i.x < mw-10 And i.y > 10 And i.y < mh-10 ' add new walker to the border of screen addwalker(Rnd(4)) End If ' Draw the new solid mapcircle(i.x,i.y) End If Next ' Go through the walker list and see if ' we can delete any walkers from the list For Local i:=Eachin mywalker If i.deleteme = True Then mywalker.Remove(i) Next Next If mywalker.IsEmpty Then finished = True End Method ' Add a walker to the list at a random edge location Method addwalker(loc:Int) Select loc Case 0'top mywalker.AddLast(New walker(Rnd(mw),0)) Case 1'bottom mywalker.AddLast(New walker(Rnd(mw),mh-1)) Case 2'left mywalker.AddLast(New walker(0,Rnd(mh))) Case 3'"right" mywalker.AddLast(New walker(mw-1,Rnd(mh))) End Select End Method Method mapcircle(x:Int,y:Int) For Local y2:=-walkerradius To walkerradius For Local x2:=-walkerradius To walkerradius Local x3:Int=x+x2 Local y3:Int=y+y2 If x3<0 Or y3<0 Or x3>=mw Or y3>=mh Then Continue map[x3][y3] = 1 Next Next End Method ' Draw the solid and walkers Method draw() For Local y:=0 Until mh For Local x:=0 Until mw If map[x][y] = 1 Then SetColor 255,255,255 DrawRect x*tw,y*th,tw+1,th+1 End If Next Next For Local i:=Eachin mywalker DrawCircle i.x*tw,i.y*th,walkerradius*th Next End Method End Class Class MyGame Extends App Field mydla:dla Field count:Int=200 Method OnCreate() SetUpdateRate(60) Seed = GetDate[4] + GetDate[5] mydla = New dla(DeviceWidth(),DeviceHeight(),100,100) End Method Method OnUpdate() mydla.update() If MouseHit(MOUSE_LEFT) Then mydla.finished = True ; count=0 If mydla.finished = True Then count-=1 If count<0 Local s:Int=Rnd(50,256) mydla = New dla(DeviceWidth(),DeviceHeight(),s,s) count=200 End If End If End Method Method OnRender() Cls 0,0,0 mydla.draw() SetColor 255,255,255 DrawText "Diffusion Limited Aggregation map generator - click = new",0,0 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, July 31, 2017
Monkey-X - Diffusion Limited Aggregation - Map Generator - code example
Sunday, July 23, 2017
Monkey-X - Circle Line Segment Collision - code example
' ' Circle Line Segment Collision ' Import mojo Class MyGame Extends App Method OnCreate() SetUpdateRate(30) End Method Method OnUpdate() End Method Method OnRender() Cls 0,0,0 SetColor 255,255,255 ' the mouse location for circle to line collision Local cx:Float=MouseX(),cy:Float=MouseY() Local cr:Int=20 'circle radius 'draw the circle DrawCircle cx,cy,cr ' line coordinates Local l1:Int[]=[100,100,200,200] ' line x1,y1,x2,y2 Local l2:Int[]=[250,100,290,300] ' draw the lines SetColor 100,100,100 DrawLine l1[0],l1[1],l1[2],l1[3] 'x1,y1,x2,y2 DrawLine l2[0],l2[1],l2[2],l2[3] ',, SetColor 255,255,255 ' check the collisions If circlelinecollide(l1[0],l1[1],l1[2],l1[3],cx,cy,cr) DrawText "Collide line 1",0,20 Else DrawText "No Collide line 1",0,20 End If If circlelinecollide(l2[0],l2[1],l2[2],l2[3],cx,cy,cr) DrawText "Collide line 2",0,40 Else DrawText "No Collide line 2",0,40 End If DrawText "Move Mouse around to check collisions with lines.",0,0 End Method End Class ' ' Line(segment) to Circle Collision ' Function circlelinecollide:Bool(sx1:Int, sy1:Int, sx2:Int, sy2:Int, cx:Int, cy:Int,cr:Float) Local xDelta:Float = sx2 - sx1 Local yDelta:Float = sy2 - sy1 Local px:Int,py:Int Local u:Float If ((xDelta = 0) And (yDelta = 0)) Error("Segment start equals segment end") End If u = ((cx - sx1) * xDelta + (cy - sy1) * yDelta) / (xDelta * xDelta + yDelta * yDelta) If (u < 0) px = sx1 py = sy1 Else If (u > 1) px = sx2 py = sy2 Else px = Int(Floor(sx1 + u * xDelta)) py = Int(Floor(sy1 + u * yDelta)) End If ' If the distance of the circle to the closest point in the line ' is less then the radius then there is a collision Local d:Int= Sqrt( Pow(px - cx,2) + Pow(py - cy,2)) If d<=(cr) Then Return True Return False End Function Function Main() New MyGame() End Function
Friday, July 21, 2017
Monkey-X - 4 Way Flood Fill Pathfinding - code example
Import mojo ' This is a class that holds x and y variables. Class pathnode Field x:Int,y:Int Method New(x:Int,y:Int) Self.x = x Self.y = y End Method End Class Class MyGame Extends App 'Our map. it holds the walls(-1) and the distance 'from the start to end position. Field cmap:Int[][] ' map width and height Field mw:Int=20,mh:Int=20 ' tile width and height Field tw:Float=22,th:Float=18 ' our start and end position Field sx:Int,sy:Int,ex:Int,ey:Int ' this holds our path Field path:List<pathnode> Method OnCreate() SetUpdateRate(1) ' create a new map array cmap = New Int[mw][] For Local i:=0 Until mw cmap[i] = New Int[mh] Next ' set the tile width and height. tw = DeviceWidth() / Float(mw) th = DeviceHeight() / Float(mh) ' get a random seed so every time we run ' this program we get a different result. Seed = GetDate[4] + GetDate[5] End Method Method OnUpdate() 'erase the map For Local y:=0 Until mh For Local x:=0 Until mw cmap[x][y] = 0 Next Next 'draw some contents on the map For Local x:=0 Until mw Step 5 For Local y:=2 Until mh-2 cmap[x][y] = -1 Next Next For Local i:=0 Until 5 Local x1:Int=Rnd(0,mw-4) Local y1:Int=Rnd(0,mh-4) For Local x2:=0 Until 4 For Local y2:=0 Until 4 cmap[x1+x2][y1+y2] = -1 Next Next Next For Local y:=0 Until mh Step 5 For Local x:=0 Until mw cmap[x][y] = 0 Next Next 'find start and end position Repeat sx = Rnd(0,mw) sy = Rnd(0,mh) ex = Rnd(0,mw) ey = Rnd(0,mh) If cmap[sx][sy] = 0 And cmap[ex][ey] = 0 If sx<>ex And sy<>ey Exit End If End If Forever 'flood the map with distance from 'sx and sy ' Create a list with a class inside it (the class has ' the x and y variables) Local ol:List<pathnode> = New List<pathnode> ' Add the start position on the list ol.AddLast(New pathnode(sx,sy)) ' set the cloes map at the start position to distance 1 cmap[sx][sy] = 1 ' some helper arrays. We can determine the top,right,and bottom ' and left position cells with these numbers. Local dx:Int[] = [0,1,0,-1] Local dy:Int[] = [-1,0,1,0] ' While there is contents in the list While ol.Count <> 0 ' Get the current location Local x1:Int=ol.First.x Local y1:Int=ol.First.y ' Remove the current location from the list ol.RemoveFirst ' Get 4 new positions around the current positions For Local i:=0 Until 4 ' Set new x and y Local nx:Int=x1+dx[i] Local ny:Int=y1+dy[i] ' If the coordinates are inside the map If nx>=0 And ny>=0 And nx<mw And ny<mh ' If the closedmap is not written to yet If cmap[nx][ny] = 0 ' Set the new distance based on the current distance cmap[nx][ny] = cmap[x1][y1] + 1 ' Add new position to the list ol.AddLast(New pathnode(nx,ny)) End If End If Next Wend ' Make the path. Here we start at the end position ' and find the lowest value around our current position ' and so on until we are at the start position. ' Get the current position Local x1:Int=ex,y1:Int=ey ' Reset our path list path = New List<pathnode> ' Set the first path contents(end x and y) path.AddLast(New pathnode(x1,y1)) ' Little counter for if we enter an infinite loop Local cnt:Int=0 ' While we are not near the map distance of 1 While cmap[x1][y1] > 1 ' Get tge current poditions distance Local lowest:Int=cmap[x1][y1] ' Create 2 new variables that hold the new location Local nx:Int,ny:Int ' If the position left of our current position is on the map ' and is not a wall and has a distance smaller that of our ' current position. If x1-1>=0 And cmap[x1-1][y1]>-1 And cmap[x1-1][y1] < lowest Then ' set new position nx=x1-1 ny=y1 ' set new lowest variable lowest = cmap[nx][ny] End If ' If the position right of our current position is on the map ' and is not a wall and has a distance smaller that of our ' current position. If x1+1<mw And cmap[x1+1][y1]>-1 And cmap[x1+1][y1] < lowest nx=x1+1 ny=y1 lowest = cmap[nx][ny] End If ' If the position top of our current position is on the map ' and is not a wall and has a distance smaller that of our ' current position. If y1-1>=0 And cmap[x1][y1-1]>-1 And cmap[x1][y1-1] < lowest nx=x1 ny=y1-1 lowest = cmap[nx][ny] End If ' If the position at the bottom of our current position is on the map ' and is not a wall and has a distance smaller that of our ' current position. If y1+1 < mh And cmap[x1][y1+1]>-1 And cmap[x1][y1+1] < lowest nx=x1 ny=y1+1 lowest = cmap[nx][ny] End If ' Here we should have a new position so we put it into ' our current position x1 = nx y1 = ny ' Add the next position to the bottom of our path list path.AddLast(New pathnode(x1,y1)) ' If we can not go anywhere then exit this loop if we have done ' a thousand loops. cnt+=1 If cnt>1000 Then Exit Wend End Method Method OnRender() Cls 0,0,0 SetColor 255,255,255 'draw the map For Local y:=0 Until mh For Local x:=0 Until mw If cmap[x][y] = -1 Then DrawRect x*tw,y*th,tw,th End If Next Next 'draw the path If path For Local i:=Eachin path SetColor 255,255,0 DrawRect i.x*tw,i.y*th,tw,th SetColor 255,255,255 DrawText cmap[i.x][i.y],i.x*tw,i.y*th Next End If 'Draw the end and start position SetColor 255,0,0 DrawRect sx*tw,sy*th,tw,th DrawRect ex*tw,ey*th,tw,th SetColor 255,255,255 DrawText "FloodFill pathfinding",0,0 End Method End Class Function Main() New MyGame() End Function
Thursday, July 13, 2017
Monkey-X - Flow Fields Multiple Agents - rts - code example
Around each agent flow fields are placed direction agents who want to travel
in their path around them. On the map itself random flowfields are placed.
The code does not work 100% correctly yet since sometimes agents go through
each other.
Import mojo Class flowfield Field mapwidth:Int,mapheight:Int Field tilewidth:Float,tileheight:Float Field screenwidth:Int,screenheight:Int Field map:Int[][] Field tempmap:Int[][] Field flowlinestartx:Int Field flowlinestarty:Int Method New(screenwidth:Int,screenheight:Int,mapwidth:Int,mapheight:Int) Self.screenwidth = screenwidth Self.screenheight = screenheight Self.tilewidth = Float(screenwidth)/Float(mapwidth) Self.tileheight = Float(screenheight)/Float(mapheight) Self.mapwidth = mapwidth Self.mapheight = mapheight ' make a array map = New Int[mapwidth][] tempmap = New Int[mapwidth][] For Local i = 0 Until mapwidth map[i] = New Int[mapheight] tempmap[i] = New Int[mapheight] Next ' -1 if no direction For Local y:=0 Until mapheight For Local x:=0 Until mapheight map[x][y] = -1 Next Next ' ' Here we create a number of points ' with which we draw the lines in between. ' Seed = GetDate[5] Local lastx:Int=Rnd(2,mapwidth-2) Local lasty:Int=Rnd(2,mapheight-2) flowlinestartx = lastx flowlinestarty = lasty For Local i:=0 Until mapwidth*mapheight/10 Local newx:Int=Rnd(2,mapwidth-2) Local newy:Int=Rnd(2,mapheight-2) flowline(lastx,lasty,newx,newy) lastx=newx lasty=newy Next End Method 'copy temp into map Method refreshmap() For Local y:=0 Until mapheight For Local x:=0 Until mapwidth map[x][y] = tempmap[x][y] Next Next End Method ' Make a flowfield(line) between two points Method flowline(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 For Local y:=-6 To 6 For Local x:=-6 To 6 If x1+x<0 Or x1+x>=mapwidth Or y1+y<0 Or y1+y>=mapheight Then continue map[x1+x][y1+y] = pointto(x1+x,y1+y,x1,y1) Next Next map[x1][y1] = pointto(x1,y1,x2,y2) 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 ' put contents in tempmap For Local y:=0 Until mapheight For Local x:=0 Until mapwidth tempmap[x][y] = map[x][y] Next Next End Method ' point the flow field direction to the x2,y2 from x1,y1 Function pointto:Int(x1:Int,y1:Int,x2:Int,y2:Int) Local nd:Int=-1 If x1<x2 Then nd=0 If x1>x2 Then nd=4 If y1<y2 Then nd=2 If y1>y2 Then nd=6 If x1<x2 And y1<y2 Then nd=1 If x1>x2 And y1<y2 Then nd=3 If x1<x2 And y1>y2 Then nd=7 If x1>x2 And y1>y2 Then nd=5 Return nd End Function Method draw() SetColor 255,255,255 For Local y:=0 Until mapheight For Local x:=0 Until mapwidth Local direction:Int = map[x][y] If direction=-1 Then Continue Local x1:Float=Float(x)*tilewidth+tilewidth/2 Local y1:Float=Float(y)*tileheight+tileheight/2 Local ang:Int= (360/8*direction) Local x2:Float=x1+(Cos(ang)*tilewidth/2) Local y2:Float=y1+(Sin(ang)*tileheight/2) Local x3:Float=x1+(Cos(ang+150)*tilewidth/4) Local y3:Float=y1+(Sin(ang+150)*tileheight/4) Local x4:Float=x1+(Cos(ang-150)*tilewidth/4) Local y4:Float=y1+(Sin(ang-150)*tileheight/4) DrawPoly([x2,y2,x3,y3,x4,y4]) Next Next End Method End Class Class alien Field alienx:Float,alieny:Float Field speed:Float Method New(x:Int,y:Int) Self.alienx = x Self.alieny = y Self.speed = Rnd(0.1,1) End Method ' ' here we modify the flowfield so that other units can move around the ' unit. We do this by placing arrows around the unit based on his direction. Method modifyflowmap() Local x:Int=alienx / myflowfield.tilewidth Local y:Int=alieny / myflowfield.tileheight If x-1<0 Or x+1>=myflowfield.mapwidth Or y-1<0 Or y+1>=myflowfield.mapheight Then Return Local d:Int=myflowfield.map[x][y] Local a:Int[8] Select d Case 2 'moving down a[0]=2;a[1]=1;a[2]=2;a[3]=7 a[4]=0;a[5]=5;a[6]=2;a[7]=3 Case 3 'moving left down a[0]=4;a[1]=3;a[2]=2;a[3]=3 a[4]=4;a[5]=1;a[6]=2;a[7]=3 Case 4 'moving left a[0]=4;a[1]=5;a[2]=4;a[3]=3 a[4]=4;a[5]=5;a[6]=6;a[7]=3 Case 5 'moving left up a[0]=4;a[1]=5;a[2]=6;a[3]=5 a[4]=4;a[5]=5;a[6]=6;a[7]=3 Case 6 ' moving up a[0]=4;a[1]=5;a[2]=6;a[3]=7 a[4]=6;a[5]=5;a[6]=6;a[7]=7 Case 7 ' moving right up a[0]=0;a[1]=5;a[2]=6;a[3]=7 a[4]=0;a[5]=7;a[6]=6;a[7]=7 Case 0 ' moving right a[0]=0;a[1]=1;a[2]=6;a[3]=7 a[4]=0;a[5]=1;a[6]=0;a[7]=7 Case 1 ' moving right down a[0]=0;a[1]=1;a[2]=2;a[3]=3 a[4]=0;a[5]=1;a[6]=2;a[7]=7 End Select myflowfield.map[x][y+1] = a[0] myflowfield.map[x-1][y+1] = a[1] myflowfield.map[x-1][y] = a[2] myflowfield.map[x-1][y-1] = a[3] myflowfield.map[x][y-1] = a[4] myflowfield.map[x+1][y-1] = a[5] myflowfield.map[x+1][y] = a[6] myflowfield.map[x+1][y+1] = a[7] End Method Method move() Local x2:Int=alienx/myflowfield.tilewidth Local y2:Int=alieny/myflowfield.tileheight Local d:Int=myflowfield.map[x2][y2] ' Move the alien based on the flowfield array's direction 0=right 1=rightdown 7=rightup Select d Case 0 alienx+=speed Case 1 alienx+=speed;alieny+=speed Case 2 alieny+=speed Case 3 alienx-=speed alieny+=speed Case 4 alienx-=speed Case 5 alienx-=speed alieny-=speed Case 6 alieny-=speed Case 7 alieny-=speed alienx+=speed End Select ' stay inside array(screen) If alienx+10>myflowfield.screenwidth Then alienx = myflowfield.screenwidth-10 If alienx-10<0 Then alienx = 10 If alieny+10>myflowfield.screenheight Then alieny = myflowfield.screenheight-10 If alieny-10<0 Then alieny = 10 End Method Method draw() SetColor 255,0,0 DrawCircle(alienx,alieny,myflowfield.tilewidth/2) End Method End Class Global myflowfield:flowfield Global myalien:List<alien> = New List<alien> Class MyGame Extends App Field mapwidth:Int,mapheight:Int Method OnCreate() Seed = GetDate[5] + GetDate[4] SetUpdateRate(60) myflowfield = New flowfield(DeviceWidth(),DeviceHeight(),20,20) For Local i:=0 Until 10 myalien.AddLast(New alien(Rnd(DeviceWidth),Rnd(DeviceHeight))) Next End Method Method OnUpdate() myflowfield.refreshmap() For Local i:=Eachin myalien i.modifyflowmap i.move() Next ' if pressed space or no move by alien then new flowfield If KeyHit(KEY_SPACE) Or MouseHit(MOUSE_LEFT) Seed = Millisecs() mapwidth = Rnd(20,80) mapheight = mapwidth myflowfield = New flowfield(DeviceWidth(),DeviceHeight(),mapwidth,mapheight) myalien.Clear() For Local i:=0 Until mapwidth*mapheight/20 Local x:Int=Rnd(DeviceWidth) Local y:Int=Rnd(DeviceHeight) myalien.AddLast(New alien(x,y)) Next End If End Method Method OnRender() Cls 0,0,0 SetColor 255,255,255 myflowfield.draw() For Local i:=Eachin myalien i.draw Next SetColor 255,255,255 DrawText("Flow Fields multiple agents - space(touch/lmb) new map.",0,0) End Method End Class 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 Function
Wednesday, July 12, 2017
Monkey-X - Flow Fields - Lines - code example
Import mojo Class flowfield Field mapwidth:Int,mapheight:Int Field tilewidth:Float,tileheight:Float Field screenwidth:Int,screenheight:Int Field map:Int[][] Field flowlinestartx:Int Field flowlinestarty:Int Method New(screenwidth:Int,screenheight:Int,mapwidth:Int,mapheight:Int) Self.screenwidth = screenwidth Self.screenheight = screenheight Self.tilewidth = Float(screenwidth)/Float(mapwidth) Self.tileheight = Float(screenheight)/Float(mapheight) Self.mapwidth = mapwidth Self.mapheight = mapheight ' make a array map = New Int[mapwidth][] For Local i = 0 Until mapwidth map[i] = New Int[mapheight] Next ' -1 if no direction For Local y:=0 Until mapheight For Local x:=0 Until mapheight map[x][y] = -1 Next Next ' ' Here we create a number of points ' with which we draw the lines in between. ' Seed = GetDate[5] Local lastx:Int=Rnd(2,mapwidth-2) Local lasty:Int=Rnd(2,mapheight-2) flowlinestartx = lastx flowlinestarty = lasty For Local i:=0 Until 5 Local newx:Int=Rnd(2,mapwidth-2) Local newy:Int=Rnd(2,mapheight-2) flowline(lastx,lasty,newx,newy) lastx=newx lasty=newy Next End Method ' Make a flowfield(line) between two points Method flowline(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 For Local y:=-1 To 1 For Local x:=-1 To 1 map[x1+x][y1+y] = pointto(x1+x,y1+y,x1,y1) Next Next map[x1][y1] = pointto(x1,y1,x2,y2) 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 ' point the flow field direction to the x2,y2 from x1,y1 Function pointto:Int(x1:Int,y1:Int,x2:Int,y2:Int) Local nd:Int=-1 If x1<x2 Then nd=0 If x1>x2 Then nd=4 If y1<y2 Then nd=2 If y1>y2 Then nd=6 If x1<x2 And y1<y2 Then nd=1 If x1>x2 And y1<y2 Then nd=3 If x1<x2 And y1>y2 Then nd=7 If x1>x2 And y1>y2 Then nd=5 Return nd End Function Method draw() SetColor 255,255,255 For Local y:=0 Until mapheight For Local x:=0 Until mapwidth Local direction:Int = map[x][y] If direction=-1 Then Continue Local x1:Float=Float(x)*tilewidth+tilewidth/2 Local y1:Float=Float(y)*tileheight+tileheight/2 Local ang:Int= (360/8*direction) Local x2:Float=x1+(Cos(ang)*tilewidth/2) Local y2:Float=y1+(Sin(ang)*tileheight/2) Local x3:Float=x1+(Cos(ang+150)*tilewidth/4) Local y3:Float=y1+(Sin(ang+150)*tileheight/4) Local x4:Float=x1+(Cos(ang-150)*tilewidth/4) Local y4:Float=y1+(Sin(ang-150)*tileheight/4) DrawPoly([x2,y2,x3,y3,x4,y4]) Next Next End Method End Class Class MyGame Extends App Field myflowfield:flowfield Field alienx:Int=200,alieny:Int=200 Field lastx:Int,lasty:Int Method OnCreate() SetUpdateRate(60) myflowfield = New flowfield(DeviceWidth(),DeviceHeight(),50,50) alienx = myflowfield.flowlinestartx * myflowfield.tilewidth alieny = myflowfield.flowlinestarty * myflowfield.tileheight End Method Method OnUpdate() Local d:Int=myflowfield.map[alienx/myflowfield.tilewidth][alieny/myflowfield.tileheight] ' Move the alien based on the flowfield array's direction 0=right 1=rightdown 7=rightup Select d Case 0 alienx+=1 Case 1 alienx+=1;alieny+=1 Case 2 alieny+=1 Case 3 alienx-=1 alieny+=1 Case 4 alienx-=1 Case 5 alienx-=1 alieny-=1 Case 6 alieny-=1 Case 7 alieny-=1 alienx+=1 End Select ' stay inside array(screen) If alienx+10>DeviceWidth() Then alienx = DeviceWidth()-10 If alienx-10<0 Then alienx = 10 If alieny+10>DeviceHeight() Then alieny = DeviceHeight()-10 If alieny-10<0 Then alieny = 10 ' if we press the left mouse then move the alien to mouse position If MouseHit(MOUSE_LEFT) Then alienx = MouseX alieny = MouseY End If ' if pressed space or no move by alien then new flowfield If KeyHit(KEY_SPACE) Or lastx = alienx And lasty = alieny myflowfield = New flowfield(DeviceWidth(),DeviceHeight(),50,50) alienx = myflowfield.flowlinestartx * myflowfield.tilewidth alieny = myflowfield.flowlinestarty * myflowfield.tileheight End If lastx = alienx lasty = alieny End Method Method OnRender() Cls 0,0,0 SetColor 255,255,255 myflowfield.draw() SetColor 255,0,0 DrawCircle(alienx,alieny,20) SetColor 255,255,255 DrawText("Flow Fields (lines)- Press lmb to place alien - space new map.",0,0) End Method End Class 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 Function
Monkey-X - Flow Fields - code example
Import mojo Class flowfield Field mapwidth:Int,mapheight:Int Field tilewidth:Float,tileheight:Float Field screenwidth:Int,screenheight:Int Field map:Int[][] Method New(screenwidth:Int,screenheight:Int,mapwidth:Int,mapheight:Int) Self.screenwidth = screenwidth Self.screenheight = screenheight Self.tilewidth = Float(screenwidth)/Float(mapwidth) Self.tileheight = Float(screenheight)/Float(mapheight) Self.mapwidth = mapwidth Self.mapheight = mapheight map = New Int[mapwidth][] For Local i = 0 Until mapwidth map[i] = New Int[mapheight] Next pointtocenter End Method ' ' In the flowfield array there are 8 directions. ' Here we point the directions towards the center ' Method pointtocenter() For Local y:Int=0 Until mapheight For Local x:Int=0 Until mapwidth Local x2:Int=mapwidth/2 Local y2:Int=mapheight/2 Local nd:Int=0 If x<x2 Then nd=0 If x>x2 Then nd=4 If y<y2 Then nd=2 If y>y2 Then nd=6 If x<x2 And y<y2 Then nd=1 If x>x2 And y<y2 Then nd=3 If x<x2 And y>y2 Then nd=7 If x>x2 And y>y2 Then nd=5 map[x][y] = nd Next Next End Method Method draw() SetColor 255,255,255 For Local y:=0 Until mapheight For Local x:=0 Until mapwidth Local direction:Int = map[x][y] Local x1:Float=Float(x)*tilewidth+tilewidth/2 Local y1:Float=Float(y)*tileheight+tileheight/2 Local ang:Int= (360/8*direction) Local x2:Float=x1+(Cos(ang)*tilewidth/2) Local y2:Float=y1+(Sin(ang)*tileheight/2) Local x3:Float=x1+(Cos(ang+150)*tilewidth/4) Local y3:Float=y1+(Sin(ang+150)*tileheight/4) Local x4:Float=x1+(Cos(ang-150)*tilewidth/4) Local y4:Float=y1+(Sin(ang-150)*tileheight/4) DrawPoly([x2,y2,x3,y3,x4,y4]) Next Next End Method End Class Class MyGame Extends App Field myflowfield:flowfield Field alienx:Int=200,alieny:Int=200 Method OnCreate() SetUpdateRate(60) myflowfield = New flowfield(DeviceWidth(),DeviceHeight(),20,20) End Method Method OnUpdate() Local d:Int=myflowfield.map[alienx/myflowfield.tilewidth][alieny/myflowfield.tileheight] Select d Case 0 alienx+=1 Case 1 alienx+=1;alieny+=1 Case 2 alieny+=1 Case 3 alienx-=1 alieny+=1 Case 4 alienx-=1 Case 5 alienx-=1 alieny-=1 Case 6 alieny-=1 Case 7 alieny-=1 alienx+=1 End Select If rectsoverlap(alienx-10,alieny-10,20,20,DeviceWidth/2-30,DeviceHeight/2-30,60,60) alienx = Rnd(DeviceWidth) alieny = Rnd(DeviceHeight) End If If MouseHit(MOUSE_LEFT) Then alienx = MouseX alieny = MouseY End If End Method Method OnRender() Cls 0,0,0 SetColor 255,255,255 myflowfield.draw() SetColor 255,0,0 DrawCircle(alienx,alieny,20) SetColor 255,255,255 DrawText("Flow Fields - Press Left Mouse to place alien",0,0) End Method End Class 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 Function
Sunday, July 9, 2017
Monkey-X - Example - Boids Flocking - code example
' Converted to Monkey-X - from Blitzmax ( coded originally by Flanker) ' Import mojo Class obstacle Field x:Float,y:Float Field radius:Int Method New(x:Int,y:Int) Self.x = x Self.y = y Self.radius = 20 End Method Method draw() SetColor 255,255,0 DrawCircle(x,y,radius) End Method End Class Class boid Field friendlist:List<boid> = New List<boid> Field x:Float,y:Float,angle:Float Field vx:Float,vy:Float Field alignspeed:Float = 8 Field speed:Float = 3 Field smoothturn:Float = 25 Field radius:Float = 10 Field cohesionfactor:Float = 100 Field friendradius:Float = 75 Field frienddistance:Float = 30 Field friendsqradius:Float Field friendsqrdistance:Float Field obstaclemargin:Float = 2 Method New() friendsqradius = friendradius*friendradius friendsqrdistance = frienddistance*frienddistance End Method Method create(count:Int) For Local i:=0 Until count Local newboid:boid = New boid() newboid.x = Rnd(640) newboid.y = Rnd(480) newboid.angle = Rnd(360) boidlist.AddLast(newboid) Next End Method Method update() getfriends() If friendlist.Count > 0 vx = 0 vy = 0 cohesion() obstacle() distance() align() Else obstacle() End If ' Clamp the movement speed If vx < -2 Then vx = -2 If vy < -2 Then vy = -2 If vx > 2 Then vx = 2 If vy > 2 Then vy = 2 move() End Method Method obstacle() For Local i:=Eachin myobstacle Local diffx:Float = x - i.x Local diffy:Float = y - i.y Local sqrdistance:Float=diffx*diffx+diffy*diffy If diffx*diffx+diffy*diffy < i.radius*i.radius*i.radius/obstaclemargin vx -= (i.x - x) / Sqrt(sqrdistance) vy -= (i.y - y) / Sqrt(sqrdistance) End If Next End Method Method cohesion() Local centerx:Float Local centery:Float For Local i:= Eachin friendlist centerx += i.x centery += i.y Next centerx /= friendlist.Count centery /= friendlist.Count vx += (centerx-x) / cohesionfactor vy += (centery-y) / cohesionfactor End Method Method distance() For Local i:=Eachin friendlist Local diffx:Float=x-i.x Local diffy:Float=y-i.y Local sqrdistance:Float=diffx*diffx+diffy*diffy If diffx*diffx+diffy*diffy < friendsqrdistance vx -= (i.x - x) / Sqrt(sqrdistance) vy -= (i.y - y) / Sqrt(sqrdistance) End If Next End Method Method align() Local sumvx:Float Local sumvy:Float For Local i:=Eachin friendlist sumvx += i.vx sumvy += i.vy Next sumvx /= friendlist.Count sumvy /= friendlist.Count vx += (sumvx - vx) / alignspeed vy += (sumvy - vy) / alignspeed End Method Method move() x += vx y += vy angle = smoothrotate(x,y,angle,x+vx,y+vy,smoothturn) x += Cos(angle) * speed y += Sin(angle) * speed If x<0 Then x = 640 If y<0 Then y = 480 If x>640 Then x = 0 If y>480 Then y = 0 End Method Method getfriends() friendlist.Clear() For Local i:=Eachin boidlist Local diffx:Float=x-i.x Local diffy:Float=y-i.y If diffx*diffx+diffy*diffy < friendsqradius If i <> Self Then friendlist.AddLast(i) End If End If Next End Method Method updateall() For Local i:=Eachin boidlist i.update Next End Method Method drawall() For Local i:=Eachin boidlist i.draw Next End Method Method draw() SetColor 255,255,255 DrawCircle(x,y,10) End Method Function smoothrotate:Float(sourceX:Float,sourceY:Float,sourceAngle:Float,destX:Float,destY:Float,smooth:Float) ' Thanks to BlackSp1der on BB forums for this piece of code ! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Local targetAngle:Float = ATan2(sourceY-destY,sourceX-destX) Local tempAngle:Float = targetAngle - Sgn(targetAngle-sourceAngle) * 360 If Abs(targetAngle-sourceAngle) > Abs(tempAngle-sourceAngle) Then targetAngle = tempAngle If sourceAngle <> targetAngle Then sourceAngle = sourceAngle - Sgn(targetAngle-sourceAngle) * (180-Abs(targetAngle-sourceAngle)) / (1+smooth) If sourceAngle >= 360 Then sourceAngle -= 360 Else If sourceAngle < 0 Then sourceAngle += 360 Return sourceAngle End Function End Class Global myobstacle:List<obstacle> Global boidlist:List<boid> = New List<boid> Class MyGame Extends App Field myboid:boid Method OnCreate() SetUpdateRate(60) myobstacle = New List<obstacle> For Local i:Int = 0 Until 10 myobstacle.AddLast(New obstacle(Rnd(640),Rnd(480))) Next myboid = New boid() myboid.create(20) End Method Method OnUpdate() myboid.updateall() If MouseDown(MOUSE_LEFT) Then myobstacle.AddLast(New obstacle(MouseX,MouseY)) If KeyHit(KEY_SPACE) Then For Local i:Int = 0 Until 10 myobstacle.AddLast(New obstacle(Rnd(640),Rnd(480))) Next End If End Method Method OnRender() Cls 0,0,0 SetColor 255,255,255 myboid.drawall() For Local i:=Eachin myobstacle i.draw Next SetColor 255,255,255 DrawText "Hold LMB to draw obstacles.",0,0 DrawText "Press space for random obstacles.",0,20 End Method End Class Function Main() New MyGame() End Function
Monkey-X - Beginners - 2D Vector Rotation - code example
Import mojo Class vector ' A vector has a origin of 0,0. The length and direction ' is the x and y variables. Field x:Float Field y:Float Method New(x:Float=0.0,y:Float=0.0) ' Fill in the x and y Self.x = x Self.y = y End Method ' This method rotates the input vector by a value(degrees) Method rotate:vector(v:vector,val:Int) ' create a temporary vector Local u:vector = New vector() ' rotate the inputted vector and put the data in u. u.x = v.x * Cos(val) - v.y * Sin(val) u.y = v.x * Sin(val) + v.y * Cos(val) ' return the new vector Return u End Method End Class Class MyGame Extends App ' some local variables. Field alienx:Float=100,alieny:Float=100 Field myvec:vector Method OnCreate() SetUpdateRate(60) ' create the new vector (2,2) myvec = New vector(2,2) End Method Method OnUpdate() End Method Method OnRender() Cls 0,0,0 SetColor 255,255,255 ' Move the alien based on the vector's x,y alienx+=myvec.x alieny+=myvec.y ' rotate the vector. myvec = myvec.rotate(myvec,10) ' draw the alien. DrawCircle(alienx,alieny,10) ' DrawText "2D Vector Rotation",0,0 End Method End Class Function Main() New MyGame() End Function
Friday, July 7, 2017
Monkey Getting started - MouseHit - code example
'import mojo needs to be called so that it recognizes the 'mojo commands. Import mojo Class MyGame Extends App Field timedown:Int Field mytext:String = "Press the mouse." Method OnCreate() 'This method is only run when the program starts SetUpdateRate(10) 'how many times should the screen be redrawn per second End Method Method OnUpdate() ' Run every frame(put keyinput ect. in here) timedown-=1 If timedown <= 0 Then timedown = 0 mytext = "Press the mouse" End If If MouseHit(MOUSE_LEFT) Then mytext = "The left mouse was last pressed." ; timedown=10 ' Flash does not recognize middle and right mouse buttons.... If MouseHit(MOUSE_RIGHT) Then mytext = "The Right mouse was last pressed."; timedown=10 If MouseHit(MOUSE_MIDDLE) Then mytext = "The Middle mouse was last pressed."; timedown=10 End Method Method OnRender() 'Drawing commands here. ' Clear the screen with color 0,0,0 Cls 0,0,0 ' Set the Color of the next drawing commands SetColor 255,255,255 ' Draw text to the screen. txt,x,y DrawText mytext,0,0 End Method End Class Function Main() New MyGame() End Function
Monkey Getting started - SetColor - code example
Import mojo Class MyGame Extends App Method OnCreate() 'This method is only run when the program starts SetUpdateRate(10) 'how many times should the screen be redrawn per second End Method Method OnUpdate() ' Run every frame(put keyinput ect. in here) End Method Method OnRender() 'Drawing commands here. ' Clear the screen with color 0,0,0 Cls 0,0,0 ' Set the Color of the next drawing commands ' red(0..255),green(0..255),blue(0..255) SetColor 255,255,255 DrawText "This is text..",0,0 ' Set the drawing color for the next drawing commands SetColor 0,255,255 ' Draw a rectangle DrawRect 100,100,200,200 End Method End Class Function Main() New MyGame() End Function
Monkey-X - Fill Triangle with Bresenham Algorithm - code example
' ' Fill triangles using the bresenham algorithm ' Import mojo Class filledtriangle ' These variables are the points of ' the triangle. Field x1:Int,y1:Int Field x2:Int,y2:Int Field x3:Int,y3:Int ' This variable is the y of the triangle ' that has the lowest value. Field lowesty:Int ' This is the total height of the triangle. Field sizey:Int ' These arrays hold the x coordinates with ' which we draw the lines. Field lefty:Int[] Field righty:Int[] ' Here we create and draw the triangle. Method New(x1:Int,y1:int,x2:Int,y2:int,x3:int,y3:int) ' In order to draw below ZERO we add a value to the inputted ' coordinates. We decrease this amount when drawing the ' actual triangles on the canvas. Local offscreen:Int=10000 x1 += offscreen y1 += offscreen x2 += offscreen y2 += offscreen x3 += offscreen y3 += offscreen ' We need to know which coordinate has the lowest ' y value and we put that in the lowesty variable. 'find lowest If y1<y2 And y1<y3 Then lowesty = y1 If y2<y1 And y2<y3 Then lowesty = y2 If y3<y1 And y3<y2 Then lowesty = y3 ' We also need to know the total height of the ' triangle so we can create a array of that size ' where we store the left and right side line ' coordinates in. 'find height If y1>y2 And y1>y3 Then sizey = y1-lowesty If y2>y1 And y2>y3 Then sizey = y2-lowesty If y3>y1 And y3>y2 Then sizey = y3-lowesty ' ' If there is nothing to draw then ' exit this method. If sizey = 0 Then Return ' Create two arrays which will hold the coordinates ' for the lines inside the triangles. The x coordinates. lefty = New Int[sizey+1] righty = New Int[sizey+1] ' Here we fill the lefty and righty arrays with the ' x coordinates of the lines inside the triangles. bline(x1,y1,x2,y2) bline(x2,y2,x3,y3) bline(x1,y1,x3,y3) ' Here we draw the lines inside the triangles. Filling ' it. You can do per pixel for colloring ect. For Local y:Int=0 until sizey DrawLine(lefty[y]-offscreen,lowesty+y-offscreen,righty[y]-offscreen,lowesty+y-offscreen) Next End Method ' ' This is the bresenham algorithm. It is modified so ' it fills two arrays with the x coordinates of the ' lines inside the triangles. Method bline:Void(x4:Int,y4:Int,x5:Int,y5:Int) Local dx:Int, dy:Int, sx:Int, sy:Int, e:Int dx = Abs(x5 - x4) sx = -1 If x4 < x5 Then sx = 1 dy = Abs(y5 - y4) sy = -1 If y4 < y5 Then sy = 1 If dx < dy Then e = dx / 2 Else e = dy / 2 End If Local exitloop:Bool=False While exitloop = False ' Here we fill the left and right sides arrays. ' we draw lines between these later on to fill the triangle If lefty[y4-lowesty] = 0 Then 'If left not used then fill left lefty[y4-lowesty] = x4 Elseif righty[y4-lowesty] = 0 'if right not used then fill right righty[y4-lowesty] = x4 Else 'if both sides are filled If lefty[y4-lowesty] = x4 Then 'overwrite same value lefty[y4-lowesty] = x4 Else 'write new value righty[y4-lowesty] = x4 End If End If If x4 = x5 If y4 = y5 exitloop = True End If End If If dx > dy Then x4 += sx ; e -= dy If e < 0 Then e += dx ; y4 += sy Else y4 += sy ; e -= dx If e < 0 Then e += dy ; x4 += sx Endif Wend End Method End Class Class MyGame Extends App ' cnt is used for the seed Field cnt:Int ' mytriangle is used to draw a triangle Field mytriangle:filledtriangle Method OnCreate() SetUpdateRate(10) End Method Method OnUpdate() ' If pressed space/touch/lmb then new set of triangles If KeyHit(KEY_SPACE) Or MouseHit(MOUSE_LEFT) Then cnt+=1 End Method Method OnRender() Cls 0,0,0 ' Always draw the same using this seed Seed = cnt ' Draw 100 triangles For Local i:=0 Until 100 Local x1:Int=Rnd(0,DeviceWidth) Local y1:Int=Rnd(0,DeviceHeight) Local x2:Int=x1+Rnd(-80,80) Local y2:Int=y1+Rnd(-80,80) Local x3:Int=x1+Rnd(-80,80) Local y3:Int=y1+Rnd(-80,80) SetColor(Rnd(255),Rnd(255),Rnd(255)) mytriangle = New filledtriangle(x1,y1,x2,y2,x3,y3) Next ' Draw some text SetColor 255,255,255 DrawText("Press the space bar/lmb/touch to draw new set.",0,0) End Method End Class Function Main() New MyGame() End Function
Subscribe to:
Posts (Atom)