Example of Own Font Class in Monkey X part 2

I decided to implement in an alternative way own font class to Monkey X to use with fonts converted with my Font 2 PNG, just to for passing time.

Check the previous post or the homepage of Font 2 PNG for format of the dat-file.

Screenshot of the program:

All you really have to understand is the simple format of the dat-file of a font to understand the source code below — and of course basic understanding of Monkey X.

Import mojo
Import brl.databuffer

Function Main()
	New MyApp
End

Class MyFont
	Field maxHeight:Int
	Field fontDat:DataBuffer
	Field gfxFont:Image
	Field scale:Float
End

Class MyApp Extends App
	
	Field gfxBG:Image
	Global font1:MyFont
	Global font2:MyFont

	Method OnCreate()
		
		' -------
		' Font 1
		' -------
		font1 = New MyFont
		font1.gfxFont = LoadImage("font1.png")
		font1.fontDat = New DataBuffer(95*4*2) ' 95 characters, for each character two 4 byte integers
		font1.scale = 1
		font1.maxHeight = 71
		font1.fontDat = DataBuffer.Load("monkey://data/font1.dat")

		' -------	
		' Font 2
		'--------
		font2 = New MyFont
		font2.gfxFont = LoadImage("font2.png")
		font2.fontDat = New DataBuffer(95*4*2) ' 95 characters, for each character two 4 byte integers
		font2.scale = 1.8
		font2.maxHeight = 43
		font2.fontDat = DataBuffer.Load("monkey://data/font2.dat")
		
		gfxBG = LoadImage("bg.jpg")
		
		SetDeviceWindow(640,480,0)
		
		SetUpdateRate(30)
	End
	
	Method OnRender()
		SetBlend AlphaBlend
		SetAlpha 1
		DrawImage gfxBG,0,0

		drawString(font1, "Testing font 1", 10, 10)
		drawString(font2, "Testing font 2", (640 - stringWidth(font2, "Testing font 2") * font2.scale) / 2, (480 - (font2.maxHeight * font2.scale)) / 2)
	End
	
	Function drawString(font:MyFont, text:String, x:Float, y:Float)
		Local len = text.Length()
		
		Local chrs:Int[]
		chrs = text.ToChars()
		
		For Local i = 0 To len - 1
			'                                 pos. in font.png                          width in pixels in font.png
			DrawImageRect font.gfxFont, x, y, font.fontDat.PeekInt((chrs[i]-32)*4*2), 0, font.fontDat.PeekInt((chrs[i]-32)*4*2 + 4), font.maxHeight,0,font.scale, font.scale,0
			x = x + font.fontDat.PeekInt((chrs[i]-32)*4*2 + 4) * font.scale
		Next

	End
	
	Function stringWidth:Int(font:MyFont,text:String)
		Local len:Int = text.Length()
		Local chrs:Int[]
		Local length:Int = 0
		
		chrs = text.ToChars()
		
		For Local i:Int = 0 To len - 1
			length = length + font.fontDat.PeekInt((chrs[i]-32)*4*2 + 4)
		Next
		
		Return length
	End

End Class

Feel free to use the code above.

 

Example of Own Font Class in Monkey X

I seem to live in the past… Monkey X programming language has evolved into Monkey2, but I’m still sometimes using Monkey X.

I made an example class to use in Monkey X with bitmap fonts converted with my Font 2 PNG. The example uses old Mojo-module, but old examples on scaling bitmap font made with Font 2 PNG will give you an idea of an alternative way to implementing this.

Next, let’s take a look at a screenshot:

Next to the code:

Import mojo
Import brl.stream
Import brl.filestream

Function Main()
	New MyApp
End

Class MyFont
	Field maxHeight:Int
	Field fontDat:Int[][]
	Field gfxFont:Image
	Field scale:Float
End

Class MyApp Extends App
	
	Field gfxBG:Image
	Global font1:MyFont
	Global font2:MyFont

	Method OnCreate()

		Local file:FileStream
		
		' -------
		' Font 1
		' -------
		font1 = New MyFont
		font1.gfxFont = LoadImage("font1.png")
		font1.fontDat = allocateArray(95,2)
		font1.scale = 1
		font1.maxHeight = 71

		file = FileStream.Open("monkey://data/font1.dat","r")
		
		For Local i:Int = 0 To 95 - 1
			font1.fontDat[i][0] = file.ReadInt()
			font1.fontDat[i][1] = file.ReadInt()
		Next				
		
		file.Close()

		' -------	
		' Font 2
		'--------
		font2 = New MyFont
		font2.gfxFont = LoadImage("font2.png")
		font2.fontDat = allocateArray(95,2)
		font2.scale = 1
		font2.maxHeight = 43

		file = FileStream.Open("monkey://data/font2.dat","r")
	
		For Local i:Int = 0 To 95 - 1
			font2.fontDat[i][0] = file.ReadInt()
			font2.fontDat[i][1] = file.ReadInt()
		Next				
		
		file.Close()
		
		gfxBG = LoadImage("bg.jpg")
		
		SetDeviceWindow(640,480,0)
		
		SetUpdateRate(30)
	End
	
	Method OnRender()
		SetBlend AlphaBlend
		SetAlpha 1
		DrawImage gfxBG,0,0

		drawString(font1, "Testing font 1", 10, 10)
		drawString(font2, "Testing font 2", (640 - (stringWidth(font2, "Testing font 2") * font2.scale)) / 2, (480 - (font2.maxHeight * font2.scale)) / 2)
	End
	
	Function drawString(font:MyFont, text:String, x:Float, y:Float)
		Local len = text.Length()
		
		Local chrs:Int[]
		chrs = text.ToChars()
		
		For Local i = 0 To len - 1
			'                               pos. in font.png          width in pixels in font.png
			DrawImageRect font.gfxFont, x, y, font.fontDat[chrs[i]-32][0], 0, font.fontDat[chrs[i]-32][1], font.maxHeight, 0 , font.scale, font.scale,0
			x = x + font.fontDat[chrs[i]-32][1] * font.scale
		Next

	End
	
	Function stringWidth:Int(font:MyFont, text:String)
		Local len:Int = text.Length()
		Local chrs:Int[]
		Local length:Int = 0
		
		chrs = text.ToChars()
		
		For Local i:Int = 0 To len - 1
			length = length + font.fontDat[chrs[i]-32][1]
		Next
		
		Return length
	End
	
	Function allocateArray:Int[][](i:Int, j:Int)
    	Local arr:Int[][] = New Int[i][]
    	
    	For Local index = 0 Until i
    	    arr[index] = New Int[j]
    	Next
    	
    	Return arr		
	End

End Class

Font 2 PNG prints the max height of the font after converting. The value is in practice just the height of the png-file.

As a reminder: Font 2 PNG produces two files, font.png and font.dat for one font. The font.dat-file holds the information for each character with two 4 byte integers, first tells the position in pixels in font, the second the width of the chatacter in pixels.

I hope this example gives you some ideas on how to use different fonts converted with Font 2 PNG.

Feel free to use the code above.

PS. I also made new version of part 1 of my Old School series demonstration in Monkey X. Video below:

From the source code in the video you’ll get an idea, how this font class could be used with Mojo2-module.

That’s it from my “hobby corner” tonight!

Old School IX

This morning I made new Old School demonstration in Monkey X. This is now 9th in the series.

Not much is changed in the code from the previous Old School demonstration. What actually required some work, was the font. As in all my Old School demonstrations, I used my Font 2 PNG program. With Mojo2-module one can use for one picture the following: “pic.png”, “pic_n.png” and “pic_s.png”. The programmer doesn’t need to worry about “_n” and “_s” versions of an image, Mojo2 takes care of them. I’ve written all I know from those extra pictures in the first old school post. I may make a better version of it in code-wise and perhaps add some extra too…

Anyway in this 9th version there are 3 versions of each character that are individual png-files.

See the magic: 🙂

I may share the Monkey X source code for these later Old School demonstrations later.

Rolling and Rotating scrolltext (Old School VIII)

I made today a little Monkey X Pro demonstration: Rolling and rotating scrolltext (Old School VIII). Now it works perfectly. Like in Old School VII, the letters fade in and out at the bottom of the circle of letters. I have used my Font 2 PNG program to grab individual characters of a ttf-font to png-images for the program. Perhaps I will later share the source code of the demonstration…

Enjoy the nostalgia! 🙂

The idea behind the code of the rolling and rotating scrolltext:

  • At every update frame 30 characters (png-images) from the scrolltext are drawn in a form of a circle, each character with 12 degrees step (12 *30 = 360), let angle related to this angle be angle1
  • When drawing the character images, the angle that increases in 12 steps is added to each character in addition to this angle is added other angle variable, let this be angle2, that is decreased (the direction of rolling and rotating) by 1 degrees at every update frame
  • Because of my (probably clumsy but working 🙂 )implementation:
If angle2 Mod 12 = 0 Then
  angle2 = angle2 + 12
  scrollTextOffset = scrollTextOffset + 1
Endif
  • in DrawImage method rotation angle is angle1 + angle2 + constant that adjusts the letters to the right place on the circle

As to he fade out and fade in for the letter images, you may adjust the letters with alpha values as you best you see it is sensible, probably somewhere at the bottom of the circle.

That’s it! Do try to make make your own version with programming language of your choice. I recommend my Font 2 PNG program for the font.

Good luck!

The first time I saw this kind of effect created was some time in the late 80s on Amiga in following demo:

Ah! Those good old Amiga demos. Kind of magic at their time.

Bouncing of the ball when it touches the Bat (80s Krakout style)

It’s night when I’m writing this. I came up with a little Monkey X tutorial on how to program the bouncing of the ball, when it touches the bat in the “old school way” — like in the popular C64 game Krakout in the 80s.

In the video for the tutorial you can see, that as the ball touches the bat for the first time, delta y doesn’t change. This is because both the ball and the bat are uneven as height in pixels; now both the ball and the bat have a middle point.

This is just a short piece of code, that doesn’t handle the case, when the ball is at the horizontal top or bottom of the bat. There’s some extra work for anyone who wants to make an 80s style Krakout game. 🙂

The delta y for the ball is calculated simply how the ball’s y-position is related to the middle point to the bat. The “scale” variable is used to adjust the max y-speed of the ball.

Source code below:

Import mojo

Function Main()
	New MyApp
End

Class MyApp Extends App

	Field gfxBG:Image, gfxBat:Image, gfxBall:Image
	Field scaleX:Float, scaleY:Float
	Field touchX:Float, touchY:Float
	Field prevTX:Float, prevTY:Float
	Field batY:Float
	Field ballX:Float, ballY:Float
	Field ballDX:Float, ballDY:Float
	Field scale:Float
	
	Method OnCreate()
		' Load graphics
		gfxBG = LoadImage("bg2.png")
		gfxBat = LoadImage("bat3.png")
		gfxBall = LoadImage("ball4.png")

		SetDeviceWindow(640,480,0)
		scaleX = DeviceWidth() / 640.0
		scaleY = DeviceHeight() / 480.0
		
		ballX = 42
		batY = 230
		ballY = 230 + 36 - 8

		ballDX = 2
		ballDY = 0
		
		prevTY = 0
		touchY = 0
		touchX = 0
		touchY = 0
		
		scale = 16
	End
	
	Method OnUpdate()

		' The if-sentence prevents the bat to appear at bottom of the screen at the start..
		If prevTY <> 0 Then batY = batY - (prevTY - touchY)

		prevTY = touchY
		
		touchY = TouchY()
		
		touchY = touchY / scaleY
		
		' Keep the bat in the borders of the screen
		If batY < 0 Then batY = 0
		If batY > 479 - 72 Then batY = 479 - 72
		
		' Move the ball
		ballX = ballX + ballDX
		ballY = ballY + ballDY

		' Keep the ball in the borders of the screen
		If ballY < Abs(ballDY) Then ballDY = -ballDY
		If ballY > 479 - 17 Then ballDY = -ballDY
		If ballX < -Abs(ballDX) Then ballDX = -ballDX
		If ballX > 639 - Abs(ballDX) - 16 Then ballDX = -ballDX
		
		' Calculate the deltaY value for the ball in the "old school way"...
		If ballX >= 601 - 16 And ballY + 16 > batY And ballY < batY + 72 Then
			ballDY = -((batY + 36) - (ballY + 8)) / scale		
			ballDX = -ballDX
		Endif
			
	End

	Method OnRender()
		PushMatrix()
		Scale(scaleX,scaleY)
		
		DrawImage gfxBG,0,0

		DrawImage gfxBall, ballX, ballY
		DrawImage gfxBat, 601, batY
		
		PopMatrix()
	End
	
End Class

Feel free to use and improve the source above in your own projects.

Here’s the graphics to download (license: public domain), except the background picture (right click and save as…):

 

 

The bat is 32 x 73 pixels as size, the ball is 16 x 17 pixels.

 

For comparing to the C64’s popular Krakout, see the video below:

Link: Monkey X (from itch.io), it’s free.

Many years ago I started to program Krakout style game in the spirit of the good old Commodore 64, but as usual, something went wrong. Three months work with multiple levels and a level editor programmed in Blitz3D were lost because I hadn’t taken backups of the files, when I, well, “fixed” the Windows installation I had at the time…

3D Stars With Controlled Center Point

Just little changes to old post on 3D stars with Mojo2… Now on the projection from 3D space to 2D space (screen), the center point can be controlled, just touch the screen or keep the left mouse button pushed down to control the stars… The code should compile as such to any target on Monkey X Pro.

Import mojo2
 
Function Main:Int()
	New MyApp
	Return 0
End
 
Class MyApp Extends App
 
	Const BG_WIDTH:Int = 640
	Const BG_HEIGHT:Int = 480
	Const STARS:Int = 280
	
	Global devWidth:Float, devHeight:Float, scaleX:Float, scaleY:Float
	
	Global x:Float[STARS],y:Float[STARS],z:Float[STARS]
 
	Field canvas:Canvas
	Field tx:Float, ty:Float
	
	Method OnCreate()
 
		devWidth = DeviceWidth()
		devHeight = DeviceHeight()
		
		scaleX = devWidth / BG_WIDTH
		scaleY = devHeight / BG_HEIGHT
 
		For Local i:Int = 0 To STARS - 1
			x[i] = Rnd(-50,50)
			y[i] = Rnd(-50,50)
			z[i] = Rnd(50,200)
		Next
		
		canvas = New Canvas()
 
		tx = BG_WIDTH / 2
		ty = BG_HEIGHT / 2
		
		SetUpdateRate(60)
	End
 
	Method OnUpdate()
		
		If TouchDown(0) > 0 Then
			tx = TouchX() / scaleX
			ty = TouchY() / scaleY
		Endif
			
	End
	
 
	Method OnRender()
		
		Local shade:Float
		
		' Scale the graphics
		canvas.PushMatrix()
		canvas.Scale (scaleX,scaleY)
 
		canvas.Clear()
				
		For Local i:Int = 0 To STARS - 1
			z[i] = z[i] - 1
			If z[i] < 10 Then z[i] = Rnd(50,200)
			
			' shade is 0..1
			shade = 1 - z[i] / 200
			canvas.SetColor shade,shade,shade
			canvas.DrawOval x[i] / z[i] * 200 + tx, y[i] / z[i] * 200 + ty,3,3
		Next
	
		canvas.Flush()
		
		canvas.PopMatrix()
		
	End
 
End Class

Source code license: Public Domain.

Scrolling a Picture Larger Than Visible Area in Monkey X

A little tutorial on scrolling a picture that is larger than the visible area of the screen in Monkey X.

In this example we will be using a picture of 1280 x 960 pixels in “native” resolution of 640 x 480 pixels. The source is primarily meant to Android target but works for example to desktop target too.

The picture is scrolled by moving a finger on the Android device. In order to avoid the picture to “jump” after not scrolling the picture, variables related to scrolling speed must be set to zero.

Lets have a look at the source code:

Import mojo

Function Main()
	New MyApp
End

Class MyApp Extends App

	Field bg:Image
	Global touchX,touchY:Float
	Global prevTX,prevTY:Float
	Global scaleX,scaleY:Float
	Global scrollX,scrollY:Float
	Global touchXD,touchYD:Float
	Global scroll:Bool
	
	Method OnCreate()
		' Change this to picture, you want to use
		bg = LoadImage("bg1280x960.png")

		SetDeviceWindow(640,480,0)
		scaleX = DeviceWidth() / 640.0
		scaleY = DeviceHeight() / 480.0
		
	End
	
	Method OnUpdate()

		touchX = TouchX()
		touchY = TouchY()
		
		touchX = touchX / scaleX
		touchY = touchY / scaleY
										
		If TouchDown(0) > 0 Then
			If scroll = True Then
		
				' touchXD & touchYD variables prevent the picture
				' to "jump", if scrolling is stopped and user then
				' touches somewhere on the screen

				touchXD = touchX
				touchYD = touchY
			Else
				' if not scrolling, values below are set to zero,
				' because when the scrolling starts again, otherwise
				' scrollX & scrollY could change too much because of
				' values of previous scrolling
				
				touchXD = 0
				touchYD = 0
				prevTX = 0
				prevTY = 0
			Endif
			
			scroll = True
			
			scrollX = scrollX - (touchXD - prevTX)
			scrollY = scrollY - (touchYD - prevTY)
		
			prevTX = touchX
			prevTY = touchY
		Else
			scroll = False
		Endif

	End

	Method OnRender()
		PushMatrix()
		Scale(scaleX,scaleY)
				
		If scrollX > 0 Then scrollX = 0
		If scrollX < -(1280 - 640) + 1 Then scrollX = -(1280 - 640) + 1
		If scrollY > 0 Then scrollY = 0
		If scrollY < -(960 - 480) + 1 Then scrollY = -(960 - 480) + 1
		
		DrawImage bg,scrollX,scrollY
		PopMatrix()
	End
	
End Class

Examine the source code and learn. Source code license: Public Domain.

Below is a video related to this post:

 

Missile Attack in Monkey X

Again, some nostalgia. In older blog post I presented a shortened version of my old implementation of Amiga’s “Missile Attack”. This night I made the game in Monkey X and the source can be directly compiled to Android target.

The game is quite simple one: Just shoot the missiles before they get to the bottom of the screen.

If a missile goes to the left or right side of the screen, you see the colors of the background changing — and also when you fire a shot. This gives the game more life. 🙂

Below is the source code:

Import mojo2

Function Main()
	New MyApp
End

Class Missile
	Field x:Float		' x-coordinate of a missile
	Field y:Float		' y-coordinate of a missile
	Field startx:Float
	Field addx:Float
	' the color of the missile
	Field red:Float
	Field green:Float
	Field blue:Float
End Class

Class MyApp Extends App

	Field bg:Image
	Global canvas:Canvas
	Global nrOfMissiles:Int
	Global mx:Float, my:Float
	Global shot:Bool
	Global gameOver:Bool = False	
	Global px:Float, py:Float, pr:Float
	Global scalex:Float, scaley:Float
	
	Global missileList := New List<Missile>	' build a missile list
	
	Method OnCreate()
		SetDeviceWindow(640,480,0)
		canvas = New Canvas
		shot = False
		nrOfMissiles = 0
		bg = Image.Load("bg.png",0,0)
		scalex = DeviceWidth() / 640.0
		scaley = DeviceHeight() / 480.0
		SetUpdateRate(60)
	End
	
	Method OnUpdate()

		If gameOver = False Then
			
			If nrOfMissiles < 8 Then
			
				Local mssl:Missile = New Missile
				mssl.x = Rnd(100,539)
				mssl.startx = mssl.x
				mssl.y = 0
				mssl.addx = Rnd(-2,2)
				mssl.red = Rnd(0.2,1)
				mssl.green = Rnd(0.2,1)
				mssl.blue = Rnd(0.2,1)
				missileList.AddLast(mssl)
			
				nrOfMissiles = nrOfMissiles + 1
			Endif

			If TouchHit(0) > 0 Then
				mx = TouchX() / scalex
				my = TouchY() / scaley
				pr = 4
				px = mx
				py = my
				shot = True
			Endif
		
		Endif
		
	End

	Method OnRender()

		canvas.PushMatrix()
		canvas.Scale(scalex, scaley)
		
		canvas.DrawImage bg,0,0
		
		If gameOver = False Then
			
			If nrOfMissiles > 0 Then
								
				For Local mssl:Missile = Eachin missileList
				
					If mssl <> Null Then
						canvas.SetColor mssl.red,mssl.green,mssl.blue	
						canvas.DrawLine(mssl.startx,0,mssl.x,mssl.y)
						mssl.y = mssl.y + 1
				
						If mssl.y >= 479 Then gameOver = True
						
						mssl.x = mssl.x + mssl.addx
					
						If mssl.x < 0 Or mssl.x > 639 Then
							missileList.Remove(mssl)
							nrOfMissiles = nrOfMissiles - 1
						Endif
					
					Endif
				Next
			Endif
		
			If shot = True Then
				canvas.SetColor 0,0,1
				canvas.DrawCircle(px,py,pr)
			Endif

			If shot = True And pr < 50 Then pr = pr + 1 Else shot = False
			
			For Local mssl:Missile = Eachin missileList
				Local removeMissile:Bool = False
				
				If mssl <> Null And shot = True Then
				
					' Mathematical way to determine if player's shot has hit the missile...
					For Local angle:Int = 0 To 360
						If Abs((px + Cos(angle) * pr) - mssl.x) <= 1 And Abs((py + Sin(angle) * pr) - mssl.y) <= 1 Then
							removeMissile = True
							score = score + 1
							Exit
						Endif
					Next
					
					If removeMissile = True Then
						missileList.Remove(mssl)
						nrOfMissiles = nrOfMissiles - 1
					Endif
					
				Endif

			Next

		Else
			canvas.SetColor 1,1,1
			canvas.DrawText "Game Over",(640 - 9 * 8) / 2, (480 - 8) / 2
		Endif
		
		canvas.Flush()
		canvas.PopMatrix()	
	End
	
End Class

Source code license: GNU General Public License 3.0.

Below is the video of the game on Android tablet and on computer screen:

I may make a better version of the game later on this summer…

How to Make a Worm Game Part 2

(Updated 03/05/2017 with improved source code and new video)

A little update to older post. As the title of the post says we’re making a worm game (in Monkey X). In this version the worm is controlled by touching the screen keeping in mind that the game is really aimed to Android.

I’ll explain here how the worm is controlled.

If you move your finger ”up” from the worm’s head, the worm goes to that direction and respectively to other directions.

See the video below:

The direction is determined by comparing two subsequent update rounds’ TouchX() and TouchY() coordinates.

The test can’t be straightforward TouchX() or TouchY() test, because the player probably won’t move his/her finger absolutely to one of the four directions the worm is to be controlled.

This is why there is another test in controlling the worm: The absolute values of difference of the two subsequent update round’s TouchX() and TouchY() coordinates. If the player wants to control the worm ”up”, the player probably has moved his/her finger more vertically than horizontally.

See the source code:

Import mojo

Function Main:Int()
	New MyApp
	Return 0
End

Class MyApp Extends App

	Const STARTSCREEN = 0
	Const PLAY = 1

	Field gfxBG:Image
	
	Const BG_WIDTH:Int = 640
	Const BG_HEIGHT:Int = 480

	Field devWidth:Float, devHeight:Float, scaleX:Float, scaleY:Float
	Global wormLength:Int = 8
	Global wormX:Int[wormLength * 17], wormY:Int[wormLength * 17]
	Field dx, dy:Int
	Field foodX:Int, foodY:Int
	Field drawFood:Bool
	Field gameState:Int
	Field touchX:Float, touchY:Float
	Field prevTX:Float, prevTY:Float
	Field prevHorChange:Float, prevVerChange:Float

	Method OnCreate()
	
		gfxBG = LoadImage("bg.png")

		devWidth = DeviceWidth()
		devHeight = DeviceHeight()
		
		scaleX = devWidth / BG_WIDTH
		scaleY = devHeight / BG_HEIGHT

		' Init worm
		For Local w:Int = 0 To 7 * 17
			wormX[w] = 200-w
			wormY[w] = 10*17
		Next
		
		dx = 1
		dy = 0
		
		drawFood = True
		SetUpdateRate(60)
	End

	Method OnUpdate()
		
		If TouchHit(0) > 0 Then gameState = PLAY
		
		If gameState = STARTSCREEN Then Return
		
		
		If TouchDown() > 0 Then
			touchX = TouchX() / scaleX
			touchY = TouchY() / scaleY

			' Calculate the differences between current and previous update rounds' touch values		
			If prevTX < touchX Then prevHorChange = Abs(prevTX - touchX) Else prevHorChange = Abs(touchX - prevTX)
			If prevTY < touchY Then prevVerChange = Abs(prevTY - touchY) Else prevVerChange = Abs(touchY - prevTY)
			
			' Up
			If touchY - prevTY < 0 And Abs(touchY - prevTY) > prevHorChange Then
				dx = 0
				dy = -1
			Endif
		
			' Down
			If touchY - prevTY > 0 And Abs(prevTY - touchY) > prevHorChange Then
				dx = 0
				dy = 1
			Endif
			
			' Left
			If touchX - prevTX < 0 And Abs(touchX - prevTX) > prevVerChange Then
				dx = -1
				dy = 0
			Endif
		
			' Right
			If touchX - prevTX > 0 And Abs(prevTX - touchX) > prevVerChange Then
				dx = 1
				dy = 0
			Endif

			prevTX = touchX
			prevTY = touchY
			
		Endif
		
		If drawFood = True Then
			foodX = Rnd()*(639-17)
			foodY = Rnd()*(479-17)
			drawFood = False
		Endif

		If Abs(wormX[0] - foodX) < 17 And Abs(wormY[0] - foodY) < 17 Then
			wormLength = wormLength + 1
			' Dynamically resize the arrays
			wormX = wormX.Resize(wormLength * 17)
			wormY = wormY.Resize(wormLength * 17)

			wormX[(wormLength-1)*17] = wormX[(wormLength-2)*17]
			wormY[(wormLength-1)*17] = wormY[(wormLength-2)*17]

			drawFood = True
		Endif
		
		For Local w:Int = (wormLength - 1) * 17 To 1 Step -1
			wormX[w] = wormX[w-1]
			wormY[w] = wormY[w-1]
		Next	

		wormX[0] = wormX[0] + dx
		wormY[0] = wormY[0] + dy
	End
	

	Method OnRender()
				
		' Scale the graphics
		PushMatrix()
		Scale (scaleX,scaleY)

		DrawImage gfxBG,0,0

		Select gameState
			Case STARTSCREEN
				SetColor 180,120,180
				SetBlend AdditiveBlend
				
				DrawText "Simple worm game",(640 - TextWidth("Simple worm game")) / 2,10
				DrawText "Move your finger on the screen to control the worm",(640 - TextWidth("Move your finger on the screen to control the worm")) / 2,40
				DrawText "Touch anywhere to start",(640 - TextWidth("Touch anywhere to start")) / 2,70
	
			Case PLAY
				SetColor 180,120,180
				SetBlend AdditiveBlend
				DrawText "Worm Length: " + wormLength,0,0
				SetColor 0,255,0
				
				SetBlend AlphaBlend
				SetAlpha 1
				SetColor 0,255,0

				For Local w:Int = 0 To wormLength - 1
					DrawOval wormX[w * 17],wormY[w * 17],17,17
				Next
				
				SetColor 255,0,0
	
				DrawOval wormX[0],wormY[0],17,17

				SetColor 255,255,0
				DrawOval foodX,foodY,17,17
		End Select
		
		PopMatrix()
	End

End Class

Source code license: Public domain.

Notice, that in this code one part of the worm’s “body” is 17 x 17 pixels, but the worm moves with step of one pixel and can be controlled with accuracy of one pixel. The example code above is simple implementation of this kind of worm game. The down side of the code is, that the sizes of the arrays for x– and y-coordinates depend of the length of the worm in pixels.

I may come back later with some implementation with different concept of moving the worm of which “body” is built with “blocks” of different size than one pixel, but the worm is controlled  with accuracy of one pixel, without using arrays of which lengths depend on the size of the worm in pixels.

Scaling Bitmap Font Made with Font 2 PNG in Monkey X part 2

Just a quick update to old code, this one can be compiled to Android target.

Source code copyright: public domain.

Import mojo
Import brl.databuffer


Function Main()
	New MyApp
End

Class MyApp Extends App
	
	Const FONT_HEIGHT:Float = 49

	Field gfxBG:Image
	Global angle:Float	
	Global fontDat:DataBuffer
	Global gfxFont:Image

	Global textScale:Float
	
	Method OnCreate()

		gfxFont = LoadImage("font.png")
		
		fontDat = New DataBuffer(95*4*2) ' 95 characters, for each character two 4 byte integers
		fontDat = DataBuffer.Load("monkey://data/font.dat")
				
		gfxBG = LoadImage("bg.png")
		
		SetDeviceWindow(1024,768,0)
		
		angle = 180
		SetUpdateRate(60)
	End
	
	Method OnUpdate()
		textScale = (2 - Cos(angle))
		angle = angle + 4
	End
	
	Method OnRender()
		SetBlend AlphaBlend
		SetAlpha 1
		DrawImage gfxBG,0,0
		SetBlend AdditiveBlend
		'                             x-coordinate                                         y-coordinate                           scale
		drawString("Sample Text", (1024 - (stringWidth("Sample Text") * textScale)) / 2, (768 - (FONT_HEIGHT * textScale)) / 2, textScale)
		
		
	End
	
	Function drawString(text:String, x:Float, y:Float,scale:Float)
		Local len = text.Length()
		
		Local chrs:Int[]
		chrs = text.ToChars()
		
		For Local i = 0 To len - 1
			'                            pos. in font.png                      width in pixels in font.png
			DrawImageRect gfxFont, x, y, fontDat.PeekInt((chrs[i]-32)*4*2), 0, fontDat.PeekInt((chrs[i]-32)*4*2 + 4), FONT_HEIGHT,0,scale,scale,0
			x = x + fontDat.PeekInt((chrs[i]-32)*4*2 + 4) * scale
		Next

	End
	
	Function stringWidth:Int(text:String)
		Local len:Int = text.Length()
		Local chrs:Int[]
		Local length:Int = 0
		
		chrs = text.ToChars()
		
		For Local i:Int = 0 To len - 1
			length = length + fontDat.PeekInt((chrs[i]-32)*4*2 + 4)
		Next
		
		Return length
	End

End Class

Below is a YouTube video of this post: