Old School II — Sine scroller made in Monkey X

I made today a scrolling version of the Old School Monkey X demo.

What’s new in this one is that it has sine wave text scrolling like in the good old Amiga demos in the late 80s. The font.png and font.dat are again made with my Font 2 PNG program.

See the video:

In the actuall program the movement is smooth.

This one has a very simple implementation of the sine scrolling.

The idea of the algorithm goes like this in short:

  • determine the width w of the first character to be drawn

  • draw a string that’s length in pixels is 640 + w starting from string index of the first character to be drawn

  • draw the determined string to position x (starting value of x is 0)

  • decrease x by 2 (speed)

  • when x <= w add the offset of the first character to drawn by 1 and set x = 0

These steps are repeated with checking if the end of the string is reached.

Mojo2 clips the graphics that are drawn out side the visible area.

The code presented here needs the string start and end with spaces so that always a string from chrStartOffset to chrEndOffset can be built and drawn to screen.

Not the best way to do the sine scrolling for each letter, but very simple. 🙂

Below is the Monkey X code:

Import mojo2
Import brl.databuffer

Function Main()
	New MyApp
End

Class MyApp Extends App
	
	Const FONT_HEIGHT:Int = 119
	Const SCROLLTEXT:String = "              Old School II - a Monkey X demo with Mojo2. This is sine wave scroller like in the good old Amiga days...                "

	Global canvas:Canvas
	Global fontDat:DataBuffer
	Global gfxFont:Image
	Global gfxBG:Image
	Global chrStartOffset:Int
	Global firstChrWidth:Int
	Global chrEndOffset:Int

	Global angle:Float[640], lightAngle:Float, lightX:Float, lightY:Float
	
	Global x:Float, y:Float[640]
	
	Method OnCreate()

		Local angl:Float
		
		canvas = New Canvas
		
		gfxBG = Image.Load("bg.png",.0,.0)
		gfxFont = Image.Load("font.png")
		fontDat = New DataBuffer(95*4*2) ' 95 characters, for each character two 4 byte integers
		fontDat = DataBuffer.Load("monkey://data/font.dat")
		
		For Local i:Int = 0 To 639
			angle[i] = angl
			angl = angl + 18
		Next

		canvas.SetAmbientLight .2,.3,.7
				
		x = 0
		chrStartOffset = 0
		firstChrWidth = charWidth(0)
		chrEndOffset = getTextEndOffset()
		
	End
	
	Method OnUpdate()
		For Local i:Int = 0 To 639
			y[i] = (480 - FONT_HEIGHT) / 2 + Sin(angle[i]) * 64
			angle[i] = angle[i] + 5
		Next
		
		lightX = Cos(lightAngle) * 150 + 640 / 2
		lightY = Sin(lightAngle) * 150 + 480 / 2
		
		lightAngle = lightAngle + 1
		
		' If the amount of scrolling is at least the width of the first
		' character to be drawn, increase the starting index where the next
		' character will be drawn by one and handle the end of the string
		If x <= -firstChrWidth Then
			chrStartOffset = chrStartOffset + 1
			
			If chrStartOffset > SCROLLTEXT.Length - 1 Then chrStartOffset = 0
			
			firstChrWidth = charWidth(chrStartOffset)
			chrEndOffset = getTextEndOffset()
			
			If chrEndOffset > SCROLLTEXT.Length - 1 Then chrEndOffset = 0
			
			x = 0
		Endif

		x = x - 2	' scrolling speed
				
	End
	
	Method OnRender()
		canvas.PushMatrix()
		canvas.Scale(DeviceWidth()/640.0,DeviceHeight()/480.0)

		canvas.Clear
		
		canvas.SetLightType 0,1
		canvas.SetLightColor 0,.7,.7,.9
		canvas.SetLightPosition 0,lightX,lightY,-100
		canvas.SetLightRange 0,200
		
		For Local sx:=0 Until DeviceWidth Step 128
			For Local sy:=0 Until DeviceHeight Step 128	
				canvas.DrawImage gfxBG,sx,sy
			Next
		Next

		canvas.SetBlendMode(BlendMode.Additive)

		' draw string to position x
		drawString(x)
		
		canvas.Flush()
		canvas.PopMatrix()	

	End
	
	' This function draws text with sine wave from indexes
	' chrStartOffset to chrEndOffset of the scrolltext string
	Function drawString(x:Float)
		Local len = SCROLLTEXT.Length()
			
		Local chrs:Int[]
		chrs = SCROLLTEXT.ToChars()
		
		For Local i = chrStartOffset To chrEndOffset
			canvas.DrawRect(x, y[i], fontDat.PeekInt((chrs[i]-32)*4*2 + 4), FONT_HEIGHT, gfxFont, fontDat.PeekInt((chrs[i]-32)*4*2), 0, fontDat.PeekInt((chrs[i]-32)*4*2 + 4), FONT_HEIGHT)
			x = x + fontDat.PeekInt((chrs[i]-32)*4*2 + 4)
		Next
		
		
	End

	' get character's width in pixels
	Function charWidth:Int(offset:Int)
		Local chrs:Int[]
		chrs = SCROLLTEXT.ToChars()
		Return fontDat.PeekInt((chrs[offset]-32)*4*2 + 4)
	End
	
	Function getTextEndOffset:Int()
		Local chrs:Int[]
		Local c:Int = chrStartOffset
		Local textWidth:Int = 0
		
		chrs = SCROLLTEXT.ToChars()
		
		' Find the end offset for a character to build a string
		' that's width in pixels is at least 640 + first character's width
		While textWidth < 640 + firstChrWidth
			textWidth = textWidth + charWidth(c)
			c = c + 1

			If c > SCROLLTEXT.Length - 1 Then c = 0
			
		Wend
		
		Return c
		
	End
	
End Class

Feel free to use the code.

%d bloggers like this: