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.

%d bloggers like this: