Refined Debug Info

Refined Debug Info

Strict

Import mojo
Import functions

' Store the device width and height
Global SCREEN_WIDTH%
Global SCREEN_HEIGHT%
' Half of SCREEN_WIDTH and HEIGHT
Global SCREEN_WIDTH2%
Global SCREEN_HEIGHT2%
' Used for Virtual Res
Global SCREENX_RATIO# = 1
Global SCREENY_RATIO# = 1

' THE GAME!!
Global game:DiddyApp

' Used for delta timing movement
Global dt:DeltaTimer

Class DiddyApp Extends App

	Field debugOn:Bool = False
	Field drawFPSOn:Bool = False

	Field FPS% = 60

	' current Screen
	Field currentScreen:Screen
	' next Screen
	Field nextScreen:Screen
	' exit Screen
	Field exitScreen:ExitScreen = new ExitScreen()
	' used for fading
	Field screenFade:ScreenFade = New ScreenFade

	' mouse
	Field mouseX:Int, mouseY:Int
	Field mouseHit:Int

	' Store the images here
	Global images:ImageBank = New ImageBank
	' Store the sounds here
	Global sounds:SoundBank = New SoundBank

	Method OnCreate:Int()
		' Store the device width and height
		SCREEN_WIDTH = DeviceWidth()
		SCREEN_HEIGHT = DeviceHeight()
		SCREEN_WIDTH2 = SCREEN_WIDTH / 2
		SCREEN_HEIGHT2 = SCREEN_HEIGHT / 2

		' set the mouse x,y
		mouseX = MouseX() / SCREENX_RATIO
		mouseY = MouseY() / SCREENY_RATIO

		' Set the Random seed
		Seed = RealMillisecs()
		' Create the delta timer
		dt = New DeltaTimer(FPS)
		SetUpdateRate FPS

		'create all the particles
		Particle.Cache()

		Return 0
	End

	Method OnRender:Int()
		FPSCounter.Update()
		currentScreen.Render()
		If screenFade.active then screenFade.Render()
		If debugOn
			DrawDebug()
		End
		If drawFPSOn
			DrawFPS()
		End
		Return 0
	End

	Method OnUpdate:Int()
		dt.UpdateDelta()
		ScreenLogic()

		Return 0
	End

	Method ScreenLogic:Int()
		mouseX = MouseX() / SCREENX_RATIO
		mouseY = MouseY() / SCREENY_RATIO
		mouseHit = MouseHit()

		If screenFade.active then screenFade.Update()
		currentScreen.Update()
	End

	Method DrawDebug:Void()
		FPSCounter.Draw(0,0)
		DrawText "Delta   = "+dt.delta, 0, 10
		DrawText "Screen  = "+currentScreen.name,0, 20
		DrawText "VMouseX = "+Self.mouseX,0, 30
		DrawText "VMouseY = "+Self.mouseY,0, 40
		DrawText "MouseX  = "+MouseX(),0, 50
		DrawText "MouseY  = "+MouseY(),0, 60
	End

	Method DrawFPS:Void()
		DrawText FPSCounter.totalFPS, 0, 0
	End
End

Class ScreenFade
	Field fadeTime:Float
	Field fadeOut:Bool
	Field ratio# = 0
	Field active:Bool
	Field counter:Float

	Method Start:Void(fadeTime:Float, fadeOut:Bool)
		If active Then Return
		active = true
		self.fadeTime = fadeTime
		self.fadeOut = fadeOut

		If fadeOut Then
			ratio = 1
		Else
			ratio = 0
		End
		counter = 0
	End

	Method Update:Void()
		if not active return
		counter += dt.delta
		CalcRatio()

		if counter > fadeTime
			active = false
			if fadeOut
				game.currentScreen.PostFadeOut()
			else
				game.currentScreen.PostFadeIn()
			End
		End
	End

	Method CalcRatio:Void()
		ratio = counter/fadeTime
		If ratio < 0 Then ratio = 0
		If ratio > 1 Then ratio = 1
		If fadeOut Then
			ratio = 1 - ratio
		End
	End

	Method Render:Void()
		if not active return

		SetAlpha 1 - ratio
		SetColor 0, 0, 0
		DrawRect 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT
		SetAlpha 1
		SetColor 255, 255, 255
	End

End Class

Class ExitScreen Extends Screen
	Method New()
		name = "exit"
	End

	method Start:Void()
		ExitApp()
	End

	method Render:Void()

	End

	method Update:Void()

	End

End

Class Screen Abstract
	Field name$ = ""

	Method PreStart:Void()
		game.currentScreen = self
		Start()
	End

	Method Start:Void() Abstract

	Method Render:Void() Abstract

	Method Update:Void() Abstract

	Method PostFadeOut:Void()
		game.nextScreen.PreStart()
	End

	Method PostFadeIn:Void()

	End
End Class

Class FPSCounter Abstract
	Global fpsCount:Int
	Global startTime:Int
	Global totalFPS:Int

	Function Update:Void()
		If Millisecs() - startTime >= 1000
			totalFPS = fpsCount
			fpsCount = 0
			startTime = Millisecs()
		Else
			fpsCount+=1
		End
	End

	Function Draw:Void(x% = 0, y% = 0, ax# = 0, ay# = 0)
		DrawText("FPS: " + totalFPS, x, y, ax, ay)
	End
End Class

' From James Boyd
Class DeltaTimer
	Field targetfps:Float = 60
	Field currentticks:Float
	Field lastticks:Float
	Field frametime:Float
	Field delta:Float

	Method New (fps:Float)
		targetfps = fps
		lastticks = Millisecs()
	End

	Method UpdateDelta:Void()
		currentticks = Millisecs()
		frametime = currentticks - lastticks
		delta = frametime / (1000.0 / targetfps)
		lastticks = currentticks
	End
End

Class ImageBank Extends StringMap<GameImage>

	Field path$ = "graphics/"

	Method Load:Void(name:String, nameoverride:String = "", midhandle:bool=true)
		Local i:GameImage = New GameImage
		i.Load(path + name, midhandle)

		If nameoverride <> "" Then i.name = nameoverride.ToUpper()
		Self.Set(i.name , i)
	End

	Method LoadAnim:Void(name:String, w%, h%, total%, tmpImage:Image, midhandle:Bool=true)
		Local i:GameImage = New GameImage
		i.LoadAnim(path + name, w, h, total, tmpImage, midhandle)
		Self.Set(i.name, i)
	End

	Method Find:GameImage(name:String)
		name = name.ToUpper()

		' debug: print all keys in the map
	'	For Local key:String = EachIn self.Keys()
	'		Print key + " is stored in the map."
	'	Next

		Local i:GameImage =  self.Get(name)
		AssertNotNull(i, "Image '" + name + "' not found in the ImageBank")
		Return i
	End
End Class

Class GameImage
	Field name$
	Field image:Image
	Field w%
	Field h%
	Field w2#
	Field h2#
	Field midhandled%=0

	Method Load:Void(file$, midhandle:bool=true)
		name = StripAll(file.ToUpper())
		image = LoadBitmap(file)
		CalcSize()
		MidHandle(midhandle)
	End

	Method LoadAnim:Void(file$, w%, h%, total%, tmpImage:Image, midhandle:Bool=true)
		name = StripAll(file.ToUpper())
		image = LoadAnimBitmap(file, w, h, total, tmpImage)
		CalcSize()
		MidHandle(midhandle)
	End

	Method CalcSize:Void()
		If image <> Null Then
			w = image.Width()
			h = image.Height()
			w2 = w/2
			h2 = h/2
		End
	End

	Method MidHandle:Void(On:Bool)
		If On Then
			image.SetHandle(w2, h2)
			midhandled=1
		Else
			image.SetHandle(0, 0)
			midhandled=0
		End
	End

	Method Draw:Void(x#, y#, rotation# = 0, scaleX# = 1, scaleY# = 1, frame% = 0)
		DrawImage(self.image, x, y, rotation, scaleX, scaleY, frame)
	End

End Class

Class SoundBank Extends StringMap<GameSound>

	Global path$ = "sounds/"

	Method Load:Void(name:String, nameoverride:String = "")
		Local i:GameSound = New GameSound
		i.Load(name)

		If nameoverride <> "" Then i.name = nameoverride.ToUpper()
		Self.Set(i.name , i)
	End

	Method Find:GameSound(name:String)
		name = name.ToUpper()

		' debug: print all keys in the map
	'	For Local key:String = EachIn self.Keys()
	'		Print key + " is stored in the map."
	'	Next

		Local i:GameSound =  Self.Get(name)
		AssertNotNull(i, "Sound '" + name + "' not found in the SoundBank")
		Return i
	End
End

Class GameSound
	Field name$
	Field sound:Sound
	Field rate# = 1
	Field pan# = 0
	Field volume# = 1
	Field loop% = 0

	Method Load:Void(file$)
		#if TARGET="flash"
			sound = LoadSoundSample(SoundBank.path + file +".mp3")
		#else If TARGET="android"
			sound = LoadSoundSample(SoundBank.path + file +".ogg")
		#else
			sound = LoadSoundSample(SoundBank.path + file +".wav")
		#endif

		name = StripAll(file.ToUpper())
	End Method

	Method Play:Void()
		SoundPlayer.PlayFx(sound, pan, rate, volume, loop)
	End Method
End Class

Class SoundPlayer
	Global channel:Int
	Const MAX_CHANNELS:Int = 31
	Function PlayFx:Void(s:Sound, pan#=0, rate#=1, volume#=1, loop% = 0)
		channel += 1
		If (channel > MAX_CHANNELS) Then channel = 0

		StopChannel(channel)
		PlaySound(s, channel, loop)
		SetChannelPan(channel, pan)
		SetChannelRate(channel, rate)
		SetChannelVolume(channel, volume)
	End
End

Class Sprite
	Field name$
	Field x#, y#
	Field ox#, oy#
	Field dx#, dy#
	Field speedX#, speedY#, speed#
	Field maxXSpeed#, maxYSpeed#
	Field image:GameImage
	Field scaleX# = 1, scaleY# = 1

	Field red% = 255, green% = 255, blue% = 255, alpha# = 1
	Field hitBoxX:Int = 0
	Field hitBoxY:Int = 0
	Field hitBoxWidth:Int
	Field hitBoxHeight:Int

	' Animation
	Field frame:Int
	Field frameTimer:Int
	Field frameStart:Int
	Field frameEnd:Int
	Field frameSpeed:Int = 0
	Field reverse:Bool = false
	Field pingPong:Bool = false
	Field loop:Bool = true
	Field ping%

	' Scale
	Field scaleCounter#=0
	Field scaleXSpeed# = 0.1
	Field scaleYSpeed# = 0.1
	Field ygravity#
	Field maxFrame:Int

	' Rotation
	Field rotationCounter#=0
	Field rotationLength%=1000
	Field rotationLoop% = 0
	Field rotation#, rotationSpeed# = 1

	Method New(img:GameImage,x#, y#)
		Self.image = img
		Self.x = x
		Self.y = y
		self.alpha = 1
		self.SetHitBox(-img.w2, -img.h2, img.w, img.h)
	End

	Method SetImage:Void(gi:GameImage)
		image = gi
		GetSize()
	End

	Method GetSize:Void()
		'Sets w and h based on the current image.
		If image <> Null Then
			image.w = image.image.Width()
			image.h = image.image.Height()
			image.w2 = image.w/2
			image.h2 = image.h/2
		End
	End

	Method Precache:Void()
		DrawImage image.image, -image.w-50, -image.h-50
	End

	Method SetRGB:Void(r%,g%,b%)
		Self.red = r
		Self.green = g
		Self.blue = b
	End

	Method SetScaleXY:Void(sx#, sy#)
		self.scaleX = sx
		self.scaleY = sy
	End

	Method Move:Void()
		Self.x+=Self.dx * dt.delta
		Self.y+=Self.dy * dt.delta

		If ygravity > 0 Then dy += ygravity * dt.delta
	End

	Method ManageScale:Void()
		If scaleCounter>0 Then
			scaleCounter-=1*dt.delta
			scaleX+=scaleXSpeed*dt.delta
			scaleY+=scaleYSpeed*dt.delta
		End
	End

	Method ManageRotation:Void()
		If rotationLoop Then
			rotation+=rotationSpeed*dt.delta
			If rotation >= 360 Then rotation-=360
			If rotation <0 Then rotation+=360
		Else
			If rotationCounter>0 Then
				rotationCounter-=1 * dt.delta
				rotation+=rotationSpeed * dt.delta
			End
		End
	End

	Method MoveForward:Void()
		dx = -Sin(rotation) * speed
        dy = -Cos(rotation) * speed

		move()
	End

	Method SetFrame:Void(startFrame:Int=0, endFrame:Int=0, speed:Int=125, pingPong:Bool = false, loop:Bool = true)
		frame = startFrame
		frameStart = startFrame
		frameEnd = endFrame
		if startFrame > endFrame
			reverse = true
		else
			reverse = false
		End
		self.pingPong = pingPong
		self.loop = loop
		frameSpeed = speed
		frameTimer = Millisecs()
		ping = 0
	End

	Method UpdateAnimation:Void()
		if frameSpeed > 0
			If Millisecs() > frameTimer + frameSpeed
				if not reverse
					frame+=1
					If frame > frameEnd
						ResetAnim()
					End
				else
					frame-=1
					If frame < frameEnd
						ResetAnim()
					End
				End
				frameTimer = Millisecs()
			End
		end
	End

	Method ResetAnim:Void()
		if loop then
			if pingPong
				reverse = Not reverse
				frame = frameEnd
				local ts% = frameStart
				frameStart = frameEnd
				frameEnd = ts
			else
				frame = frameStart
			End
		else
			if pingPong and ping <1
				reverse = Not reverse
				frame = frameEnd
				local ts% = frameStart
				frameStart = frameEnd
				frameEnd = ts
				ping+=1
			else
				frame = frameEnd
			End
		End
	End

	Method Draw:Void()
		Draw(0,0)
	End

	Method Draw:Void(offsetx#=0, offsety#=0)
		If x - offsetx + image.w < 0 Or x - offsetx - image.w >= SCREEN_WIDTH Or y - offsety + image.h < 0 Or y - offsety - image.h >= SCREEN_HEIGHT Then Return
		SetAlpha self.alpha
		SetColor red, green, blue ' doesnt work with images!?!??!
		DrawImage(image.image, x - offsetx, y - offsety, rotation, scaleX, scaleY, frame)
		SetColor 255, 255, 255
		SetAlpha 1

	'	if debug
	'		drawRectOutline(x + hitBoxX, y + hitBoxY, hitBoxWidth, hitBoxHeight)
	'	End
	End

	Method Collide:Int(sprite:Sprite)
		Return RectsOverlap(x + hitBoxX, y + hitBoxY, hitBoxWidth, hitBoxHeight,
							sprite.x + sprite.hitBoxX, sprite.y + sprite.hitBoxY, sprite.hitBoxWidth, sprite.hitBoxHeight)
	End

	Method SetHitBox:Void(hitX:Int, hitY:Int, hitWidth:Int, hitHeight:Int)
		hitBoxX = hitX
		hitBoxY = hitY
		hitBoxWidth = hitWidth
		hitBoxHeight = hitHeight
	End
End

Class Particle Extends Sprite
	Global MAX_PARTICLES% = 800
	Global particles:Particle[MAX_PARTICLES]
	Global lastDeath% = 0
	Global maxIndex% = -1
	Global minIndex% = -1
	Global particleCount% = 0
	Field lifeCounter# = 0
	Field fadeIn# = 0
	Field fadeCounter#
	Field fadeInLength# = 0
	Field fadeLength#=0
	Field active% = 0

	Function Cache:Void()
		For Local i% = 0 to MAX_PARTICLES - 1
			particles[i] = New Particle()
		Next
	End

	Function Create:Particle(gi:GameImage, x#, y#, dx#=0, dy#=0, gravity#=0, fadeLength#=0, lifeCounter%=0)
		Local i%=lastDeath
		Repeat
			If particles[i] = Null Then particles[i] = New Particle()
			If Not particles[i].active Then
				particles[i].SetImage(gi)
				particles[i].x = x
				particles[i].y = y
				particles[i].dx = dx
				particles[i].dy = dy

				particles[i].ygravity = gravity
				particles[i].fadeLength = fadeLength / 10
				particles[i].fadeCounter = particles[i].fadeLength
				If lifeCounter>0 Then particles[i].lifeCounter = lifeCounter / 10
				particles[i].active = 1
				If maxIndex < 0 Or i > maxIndex Then maxIndex = i
				If minIndex < 0 Or i < minIndex Then minIndex = i
				particleCount += 1
				Return particles[i]
			End
			i += 1
			If i >= MAX_PARTICLES Then i = 0
		Until i = lastDeath
		Return Null
	End

	Function Clear:Void()
		For Local i% = 0 to MAX_PARTICLES - 1
			particles[i].alpha = 0
			particles[i].active = False
		Next
		minIndex = -1
		maxIndex = -1
		particleCount = 0
		lastDeath = 0
	End

	Function DrawAll:Void()
		If minIndex < 0 Or maxIndex < 0 Then Return
		For Local i% = minIndex to maxIndex
			if particles[i] <> null And particles[i].image <> null
				If particles[i].fadeCounter > 0 and particles[i].active Then
					If particles[i].fadeIn Then
						particles[i].alpha = particles[i].fadeCounter/particles[i].fadeInLength
					Else
						particles[i].alpha = particles[i].fadeCounter/particles[i].fadeLength
					End
				End
				particles[i].Draw()
			End
		Next
	End

	Function UpdateAll:Void()
		If minIndex < 0 Or maxIndex < 0 Then Return
		Local newMinIndex% = -1
		Local newMaxIndex% = -1
		For Local i% = minIndex to maxIndex
			if particles[i] <> null And particles[i].image <> null
				If particles[i].active
					particles[i].Update()
					If particles[i].active Then
						If newMinIndex < 0 Then newMinIndex = i
						newMaxIndex = i
					Else
						lastDeath = i
						particleCount -= 1
					End
				End
			End
		Next
		minIndex = newMinIndex
		maxIndex = newMaxIndex
	End

	Method Update:Void()
		Super.Move()

		If fadeIn Then
			fadeCounter+=dt.delta

			If fadeCounter >= fadeInLength Then
				fadeCounter = fadeLength
				fadeIn = 0
				alpha = 1
			End
		ElseIf fadeCounter>0 Then
			fadeCounter-=dt.delta
			If fadeCounter <= 0 Then
				alpha = 0
				active = 0
			End
		End
	End

End

Strict

Import mojo
Import functions

' Store the device width and height
Global SCREEN_WIDTH%
Global SCREEN_HEIGHT%
' Half of SCREEN_WIDTH and HEIGHT
Global SCREEN_WIDTH2%
Global SCREEN_HEIGHT2%

' THE GAME!!
Global game:DiddyApp

' Used for delta timing movement
Global dt:DeltaTimer

Class DiddyApp Extends App

	Field debugOn:Bool = False

	Field FPS% = 60

	' current Screen
	Field currentScreen:Screen
	' next Screen
	Field nextScreen:Screen
	' exit Screen
	Field exitScreen:ExitScreen = new ExitScreen()
	' used for fading
	Field screenFade:ScreenFade = New ScreenFade

	' mouse
	Field mouseX:Int, mouseY:Int
	Field mouseHit:Int

	' Store the images here
	Global images:ImageBank = New ImageBank
	' Store the sounds here
	Global sounds:SoundBank = New SoundBank

	Method OnCreate:Int()
		' Store the device width and height
		SCREEN_WIDTH = DeviceWidth()
		SCREEN_HEIGHT = DeviceHeight()
		SCREEN_WIDTH2 = SCREEN_WIDTH / 2
		SCREEN_HEIGHT2 = SCREEN_HEIGHT / 2

		' set the mouse x,y
		mouseX = MouseX()
		mouseY = MouseY()

		' Set the Random seed
		Seed = RealMillisecs()
		' Create the delta timer
		dt = New DeltaTimer(FPS)
		SetUpdateRate FPS

		'create all the particles
		Particle.Cache()

		Return 0
	End

	Method OnRender:Int()
		FPSCounter.Update()
		currentScreen.Render()
		If screenFade.active then screenFade.Render()
		If debugOn
			DrawDebug()
		End
		Return 0
	End

	Method OnUpdate:Int()
		dt.UpdateDelta()
		ScreenLogic()

		Return 0
	End

	Method ScreenLogic:Int()
		mouseX = MouseX()
		mouseY = MouseY()
		mouseHit = MouseHit()

		If screenFade.active then screenFade.Update()
		currentScreen.Update()
	End

	Method DrawDebug:Void()
		SetAlpha 0.2
		SetColor 0, 0, 0
		DrawRect 0, 0, 200, 200
		SetColor 255, 255, 255
		SetAlpha 1
		FPSCounter.Draw(0,0)
		DrawText "Delta = "+dt.delta, 0, 10
		DrawText "Screen = "+currentScreen.name,0, 20
	End

End

Class ScreenFade
	Field fadeTime:Float
	Field fadeOut:Bool
	Field ratio# = 0
	Field active:Bool
	Field counter:Float

	Method Start:Void(fadeTime:Float, fadeOut:Bool)
		If active Then Return
		active = true
		self.fadeTime = fadeTime
		self.fadeOut = fadeOut

		If fadeOut Then
			ratio = 1
		Else
			ratio = 0
		End
		counter = 0
	End

	Method Update:Void()
		if not active return
		counter += dt.delta
		CalcRatio()

		if counter > fadeTime
			active = false
			if fadeOut
				game.currentScreen.PostFadeOut()
			else
				game.currentScreen.PostFadeIn()
			End
		End
	End

	Method CalcRatio:Void()
		ratio = counter/fadeTime
		If ratio < 0 Then ratio = 0
		If ratio > 1 Then ratio = 1
		If fadeOut Then
			ratio = 1 - ratio
		End
	End

	Method Render:Void()
		if not active return

		SetAlpha 1 - ratio
		SetColor 0, 0, 0
		DrawRect 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT
		SetAlpha 1
		SetColor 255, 255, 255
	End

End Class

Class ExitScreen Extends Screen
	Method New()
		name = "exit"
	End

	method Start:Void()
		ExitApp()
	End

	method Render:Void()

	End

	method Update:Void()

	End

End

Class Screen Abstract
	Field name$ = ""

	Method PreStart:Void()
		game.currentScreen = self
		Start()
	End

	Method Start:Void() Abstract

	Method Render:Void() Abstract

	Method Update:Void() Abstract

	Method PostFadeOut:Void()
		game.nextScreen.PreStart()
	End

	Method PostFadeIn:Void()

	End
End Class

Class FPSCounter Abstract
	Global fpsCount:Int
	Global startTime:Int
	Global totalFPS:Int

	Function Update:Void()
		If Millisecs() - startTime >= 1000
			totalFPS = fpsCount
			fpsCount = 0
			startTime = Millisecs()
		Else
			fpsCount+=1
		End
	End

	Function Draw:Void(x% = 0, y% = 0, ax# = 0, ay# = 0)
		DrawText("FPS: " + totalFPS, x, y, ax, ay)
	End
End Class

' From James Boyd
Class DeltaTimer
	Field targetfps:Float = 60
	Field currentticks:Float
	Field lastticks:Float
	Field frametime:Float
	Field delta:Float

	Method New (fps:Float)
		targetfps = fps
		lastticks = Millisecs()
	End

	Method UpdateDelta:Void()
		currentticks = Millisecs()
		frametime = currentticks - lastticks
		delta = frametime / (1000.0 / targetfps)
		lastticks = currentticks
	End
End

Class ImageBank Extends StringMap<GameImage>

	Field path$ = "graphics/"

	Method Load:Void(name:String, nameoverride:String = "", midhandle:bool=true)
		Local i:GameImage = New GameImage
		i.Load(path + name, midhandle)

		If nameoverride <> "" Then i.name = nameoverride.ToUpper()
		Self.Set(i.name , i)
	End

	Method LoadAnim:Void(name:String, w%, h%, total%, tmpImage:Image, midhandle:Bool=true)
		Local i:GameImage = New GameImage
		i.LoadAnim(path + name, w, h, total, tmpImage, midhandle)
		Self.Set(i.name, i)
	End

	Method Find:GameImage(name:String)
		name = name.ToUpper()

		' debug: print all keys in the map
	'	For Local key:String = EachIn self.Keys()
	'		Print key + " is stored in the map."
	'	Next

		Local i:GameImage =  self.Get(name)
		AssertNotNull(i, "Image '" + name + "' not found in the ImageBank")
		Return i
	End
End Class

Class GameImage
	Field name$
	Field image:Image
	Field w%
	Field h%
	Field w2#
	Field h2#
	Field midhandled%=0

	Method Load:Void(file$, midhandle:bool=true)
		name = StripAll(file.ToUpper())
		image = LoadBitmap(file)
		CalcSize()
		MidHandle(midhandle)
	End

	Method LoadAnim:Void(file$, w%, h%, total%, tmpImage:Image, midhandle:Bool=true)
		name = StripAll(file.ToUpper())
		image = LoadAnimBitmap(file, w, h, total, tmpImage)
		CalcSize()
		MidHandle(midhandle)
	End

	Method CalcSize:Void()
		If image <> Null Then
			w = image.Width()
			h = image.Height()
			w2 = w/2
			h2 = h/2
		End
	End

	Method MidHandle:Void(On:Bool)
		If On Then
			image.SetHandle(w2, h2)
			midhandled=1
		Else
			image.SetHandle(0, 0)
			midhandled=0
		End
	End

	Method Draw:Void(x#, y#, rotation# = 0, scaleX# = 1, scaleY# = 1, frame% = 0)
		DrawImage(self.image, x, y, rotation, scaleX, scaleY, frame)
	End

End Class

Class SoundBank Extends StringMap<GameSound>

	Global path$ = "sounds/"

	Method Load:Void(name:String, nameoverride:String = "")
		Local i:GameSound = New GameSound
		i.Load(name)

		If nameoverride <> "" Then i.name = nameoverride.ToUpper()
		Self.Set(i.name , i)
	End

	Method Find:GameSound(name:String)
		name = name.ToUpper()

		' debug: print all keys in the map
	'	For Local key:String = EachIn self.Keys()
	'		Print key + " is stored in the map."
	'	Next

		Local i:GameSound =  Self.Get(name)
		AssertNotNull(i, "Sound '" + name + "' not found in the SoundBank")
		Return i
	End
End

Class GameSound
	Field name$
	Field sound:Sound
	Field rate# = 1
	Field pan# = 0
	Field volume# = 1
	Field loop% = 0

	Method Load:Void(file$)
		#if TARGET="flash"
			sound = LoadSoundSample(SoundBank.path + file +".mp3")
		#else If TARGET="android"
			sound = LoadSoundSample(SoundBank.path + file +".ogg")
		#else
			sound = LoadSoundSample(SoundBank.path + file +".wav")
		#endif

		name = StripAll(file.ToUpper())
	End Method

	Method Play:Void()
		SoundPlayer.PlayFx(sound, pan, rate, volume, loop)
	End Method
End Class

Class SoundPlayer
	Global channel:Int
	Const MAX_CHANNELS:Int = 31
	Function PlayFx:Void(s:Sound, pan#=0, rate#=1, volume#=1, loop% = 0)
		channel += 1
		If (channel > MAX_CHANNELS) Then channel = 0

		StopChannel(channel)
		PlaySound(s, channel, loop)
		SetChannelPan(channel, pan)
		SetChannelRate(channel, rate)
		SetChannelVolume(channel, volume)
	End
End

Class Sprite
	Field name$
	Field x#, y#
	Field ox#, oy#
	Field dx#, dy#
	Field speedX#, speedY#, speed#
	Field maxXSpeed#, maxYSpeed#
	Field image:GameImage
	Field scaleX# = 1, scaleY# = 1

	Field red% = 255, green% = 255, blue% = 255, alpha# = 1
	Field hitBoxX:Int = 0
	Field hitBoxY:Int = 0
	Field hitBoxWidth:Int
	Field hitBoxHeight:Int

	' Animation
	Field frame:Int
	Field frameTimer:Int
	Field frameStart:Int
	Field frameEnd:Int
	Field frameSpeed:Int = 0
	Field reverse:Bool = false
	Field pingPong:Bool = false
	Field loop:Bool = true
	Field ping%

	' Scale
	Field scaleCounter#=0
	Field scaleXSpeed# = 0.1
	Field scaleYSpeed# = 0.1
	Field ygravity#
	Field maxFrame:Int

	' Rotation
	Field rotationCounter#=0
	Field rotationLength%=1000
	Field rotationLoop% = 0
	Field rotation#, rotationSpeed# = 1

	Method New(img:GameImage,x#, y#)
		Self.image = img
		Self.x = x
		Self.y = y
		self.alpha = 1
		self.SetHitBox(-img.w2, -img.h2, img.w, img.h)
	End

	Method SetImage:Void(gi:GameImage)
		image = gi
		GetSize()
	End

	Method GetSize:Void()
		'Sets w and h based on the current image.
		If image <> Null Then
			image.w = image.image.Width()
			image.h = image.image.Height()
			image.w2 = image.w/2
			image.h2 = image.h/2
		End
	End

	Method Precache:Void()
		DrawImage image.image, -image.w-50, -image.h-50
	End

	Method SetRGB:Void(r%,g%,b%)
		Self.red = r
		Self.green = g
		Self.blue = b
	End

	Method SetScaleXY:Void(sx#, sy#)
		self.scaleX = sx
		self.scaleY = sy
	End

	Method Move:Void()
		Self.x+=Self.dx * dt.delta
		Self.y+=Self.dy * dt.delta

		If ygravity > 0 Then dy += ygravity * dt.delta
	End

	Method ManageScale:Void()
		If scaleCounter>0 Then
			scaleCounter-=1*dt.delta
			scaleX+=scaleXSpeed*dt.delta
			scaleY+=scaleYSpeed*dt.delta
		End
	End

	Method ManageRotation:Void()
		If rotationLoop Then
			rotation+=rotationSpeed*dt.delta
			If rotation >= 360 Then rotation-=360
			If rotation <0 Then rotation+=360
		Else
			If rotationCounter>0 Then
				rotationCounter-=1 * dt.delta
				rotation+=rotationSpeed * dt.delta
			End
		End
	End

	Method MoveForward:Void()
		dx = -Sin(rotation) * speed
        dy = -Cos(rotation) * speed

		move()
	End

	Method SetFrame:Void(startFrame:Int=0, endFrame:Int=0, speed:Int=125, pingPong:Bool = false, loop:Bool = true)
		frame = startFrame
		frameStart = startFrame
		frameEnd = endFrame
		if startFrame > endFrame
			reverse = true
		else
			reverse = false
		End
		self.pingPong = pingPong
		self.loop = loop
		frameSpeed = speed
		frameTimer = Millisecs()
		ping = 0
	End

	Method UpdateAnimation:Void()
		if frameSpeed > 0
			If Millisecs() > frameTimer + frameSpeed
				if not reverse
					frame+=1
					If frame > frameEnd
						ResetAnim()
					End
				else
					frame-=1
					If frame < frameEnd
						ResetAnim()
					End
				End
				frameTimer = Millisecs()
			End
		end
	End

	Method ResetAnim:Void()
		if loop then
			if pingPong
				reverse = Not reverse
				frame = frameEnd
				local ts% = frameStart
				frameStart = frameEnd
				frameEnd = ts
			else
				frame = frameStart
			End
		else
			if pingPong and ping <1
				reverse = Not reverse
				frame = frameEnd
				local ts% = frameStart
				frameStart = frameEnd
				frameEnd = ts
				ping+=1
			else
				frame = frameEnd
			End
		End
	End

	Method Draw:Void()
		Draw(0,0)
	End

	Method Draw:Void(offsetx#=0, offsety#=0)
		If x - offsetx + image.w < 0 Or x - offsetx - image.w >= SCREEN_WIDTH Or y - offsety + image.h < 0 Or y - offsety - image.h >= SCREEN_HEIGHT Then Return
		SetAlpha self.alpha
		SetColor red, green, blue ' doesnt work with images!?!??!
		DrawImage(image.image, x - offsetx, y - offsety, rotation, scaleX, scaleY, frame)
		SetColor 255, 255, 255
		SetAlpha 1

	'	if debug
	'		drawRectOutline(x + hitBoxX, y + hitBoxY, hitBoxWidth, hitBoxHeight)
	'	End
	End

	Method Collide:Int(sprite:Sprite)
		Return RectsOverlap(x + hitBoxX, y + hitBoxY, hitBoxWidth, hitBoxHeight,
							sprite.x + sprite.hitBoxX, sprite.y + sprite.hitBoxY, sprite.hitBoxWidth, sprite.hitBoxHeight)
	End

	Method SetHitBox:Void(hitX:Int, hitY:Int, hitWidth:Int, hitHeight:Int)
		hitBoxX = hitX
		hitBoxY = hitY
		hitBoxWidth = hitWidth
		hitBoxHeight = hitHeight
	End
End

Class Particle Extends Sprite
	Global MAX_PARTICLES% = 800
	Global particles:Particle[MAX_PARTICLES]
	Global lastDeath% = 0
	Global maxIndex% = -1
	Global minIndex% = -1
	Global particleCount% = 0
	Field lifeCounter# = 0
	Field fadeIn# = 0
	Field fadeCounter#
	Field fadeInLength# = 0
	Field fadeLength#=0
	Field active% = 0

	Function Cache:Void()
		For Local i% = 0 to MAX_PARTICLES - 1
			particles[i] = New Particle()
		Next
	End

	Function Create:Particle(gi:GameImage, x#, y#, dx#=0, dy#=0, gravity#=0, fadeLength#=0, lifeCounter%=0)
		Local i%=lastDeath
		Repeat
			If particles[i] = Null Then particles[i] = New Particle()
			If Not particles[i].active Then
				particles[i].SetImage(gi)
				particles[i].x = x
				particles[i].y = y
				particles[i].dx = dx
				particles[i].dy = dy

				particles[i].ygravity = gravity
				particles[i].fadeLength = fadeLength / 10
				particles[i].fadeCounter = particles[i].fadeLength
				If lifeCounter>0 Then particles[i].lifeCounter = lifeCounter / 10
				particles[i].active = 1
				If maxIndex < 0 Or i > maxIndex Then maxIndex = i
				If minIndex < 0 Or i < minIndex Then minIndex = i
				particleCount += 1
				Return particles[i]
			End
			i += 1
			If i >= MAX_PARTICLES Then i = 0
		Until i = lastDeath
		Return Null
	End

	Function Clear:Void()
		For Local i% = 0 to MAX_PARTICLES - 1
			particles[i].alpha = 0
			particles[i].active = False
		Next
		minIndex = -1
		maxIndex = -1
		particleCount = 0
		lastDeath = 0
	End

	Function DrawAll:Void()
		If minIndex < 0 Or maxIndex < 0 Then Return
		For Local i% = minIndex to maxIndex
			if particles[i] <> null And particles[i].image <> null
				If particles[i].fadeCounter > 0 and particles[i].active Then
					If particles[i].fadeIn Then
						particles[i].alpha = particles[i].fadeCounter/particles[i].fadeInLength
					Else
						particles[i].alpha = particles[i].fadeCounter/particles[i].fadeLength
					End
				End
				particles[i].Draw()
			End
		Next
	End

	Function UpdateAll:Void()
		If minIndex < 0 Or maxIndex < 0 Then Return
		Local newMinIndex% = -1
		Local newMaxIndex% = -1
		For Local i% = minIndex to maxIndex
			if particles[i] <> null And particles[i].image <> null
				If particles[i].active
					particles[i].Update()
					If particles[i].active Then
						If newMinIndex < 0 Then newMinIndex = i
						newMaxIndex = i
					Else
						lastDeath = i
						particleCount -= 1
					End
				End
			End
		Next
		minIndex = newMinIndex
		maxIndex = newMaxIndex
	End

	Method Update:Void()
		Super.Move()

		If fadeIn Then
			fadeCounter+=dt.delta

			If fadeCounter >= fadeInLength Then
				fadeCounter = fadeLength
				fadeIn = 0
				alpha = 1
			End
		ElseIf fadeCounter>0 Then
			fadeCounter-=dt.delta
			If fadeCounter <= 0 Then
				alpha = 0
				active = 0
			End
		End
	End

End


Create Main.monkey

Create Main.monkey

error: pathspec 'examples/Graphics/Main.monkey' did not match any file(s) known to git


Create maniacMisc.monkey

Create maniacMisc.monkey

#Rem monkeydoc Module maniac.maniacMisc
	Misc Module - Version 1.0 (alpha)  ~n
	Copyright (C) 2015  Stephan Duckerschein~n

	Here are all Functions and Classes, that have no Special set or something.

#End

Import mojo
Import maniacDebug
#If (TARGET <> "html5") And (TARGET <> "flash")
	Import brl.FileSystem
#Endif

#Rem monkeydoc
	This function creates a new 2 Dimensional Int Array with i and j dimensions.
	optionaly You can add a initial Value fill. Standard fill value will then be 0.

	Import maniac

	Function Main:int()
		local array:Int[][] = Array2D(10,5)
	End Function

#End
Function Array2D:Int[][] (i:Int, j:Int,fill:Int = 0)

    Local arr:Int[][] = New Int[i][]
    For Local ind = 0 Until i
        arr[ind] = New Int[j]
    Next

    For Local w:Int = 0 Until i
    	For Local h:Int = 0 Until j
    		arr[w][h] = fill
    	Next
    Next
    Return arr
End

#Rem monkeydoc
	This function creates a new 2 Dimensional Int Array with i and j dimensions.
	optionaly You can add a initial Value fill. Standard fill value will then be 0.

	Import maniac

	Function Main:int()
		local array:Int[][] = Array2D(10,5)
	End Function

#End
Function Array2Dmf:ManiacField[][] (i:Int, j:Int)

    Local arr:ManiacField[][] = New ManiacField[i][]
    For Local ind = 0 Until i
        arr[ind] = New ManiacField[j]
    Next

    Return arr
End
#rem
Function Array3D:Int[][][] (i:Int, j:Int,k:int,fill:Int = 0)
    Local arr:Int[][][] = New Int[i][][]
    For Local ind = 0 Until i
        arr[ind] = New Int[j][]
        For Local ind2:Int = 0 Until j
        	arr[ind][j] = New Int[k]
        Next
    Next

    For Local w:Int = 0 Until i
    	For Local h:Int = 0 Until j
    		For Local o:Int = 0 Until k
    		arr[w][h][o] = fill
    	Next
    Next
    Return arr
End
#end

#Rem monkeydoc
	This Functions converts movement Data to Movements per Second.
	It uses the built-in Updating System.

	if you want to Move like 200 Pixel in 1 Second, you call
	EqToFPS(PixelPerSecond)
#End
Function EqToFPS:Float(unitsPerSecond:Float)
	Maniac_Debug.addCalc()
  'Convert the given units-per-second value to units-per-frame
  Return unitsPerSecond * maniac_timeScale
End Function

#Rem monkeydoc
	This Functions Checks if the MouseCursor is within this rectangle dimensions.

	_X & _Y are the Top-Left Corner
#End
Function MOBox:Bool(_X:Float, _Y:Float, _Width:Float, _Height:float)
	Maniac_Debug.addTotCall()
	Maniac_Debug.addTotCalc()
		'Maniac_Debug.addTotDraws(2)
	Maniac_Debug.addCalc()
	If _X < MouseX() And _X + _Width > MouseX() And _Y < MouseY() And _Y + _Height > MouseY()
		Return True
	Else
		Return False
	Endif

End Function

#Rem monkeydoc
	This Functions Checks if the MouseCursor is within this circle dimensions.
#End
Function MOCircle:Bool(ix:Int,iy:Int,ir:Int)
	Maniac_Debug.addTotCall()
	Maniac_Debug.addTotCalc()
	Maniac_Debug.addCalc()
	Local dx:Float = ix - MouseX()
	Local dy:Float = iy - MouseY()

	Local distance:float = Sqrt( dx*dx + dy*dy )		'berechne den Abstand

	'Wenn Abstand geringer als 2*Radius >> Kollision
	If distance < ir
		Return True
	Else
		Return False
	Endif
End Function

#Rem monkeydoc
	This Function returns the Time Stamp of the underlaying Operating System as a String.
#End
Const TIMESTAMP_TIME_DATE:Int = 0
Const TIMESTAMP_DATE_TIME:Int = 1
Function GetTimeStamp:String(_Style:Int = 0,_Order:Int = 0)
	'Local currDate:String
	Maniac_Debug.addCalc()
	Local date:=GetDate()

    Local months:=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]

    Local day:=("0"+date[2])[-2..]
    Local month:=months[date[1]-1]
    Local year:=date[0]
    Local hour:=("0"+date[3])[-2..]
    Local min:=("0"+date[4])[-2..]
    Local sec:=("0"+date[5])[-2..] + "." + ("00"+date[6])[-3..]

    Local now:String '=hour+":"+min+":"+sec+"  "+day+" "+month+" "+year
    Select _Style
    	Case TIMESTAMP_TIME_DATE
    		now = hour+":"+min+":"+sec+"  "+day+" "+month+" "+year
    	Case TIMESTAMP_DATE_TIME
    		Select _Order
    			Case 0
    				now = year+" "+month+" "+day+"   "+hour+":"+min+":"+sec
    			Case 1
    				now = year+" "+month+" "+day+"   "+hour+":"+min
    			Case 2
    				now = year+" "+month+" "+day
    		End Select
    		Default
    End Select

	Return now
End Function

Function Screenshot:Image()
    Local width:Int  = mojo.app.DeviceWidth()
    Local height:Int = mojo.app.DeviceHeight()
    Local img:Image  = mojo.graphics.CreateImage(width,height)
    If img
        Local mem:Int[] = New Int[width*height]
        If mem
            mojo.graphics.ReadPixels(mem,0,0,width,height)
            img.WritePixels(mem,0,0,width,height)
            Return img
        Endif
    Endif
    Return Null
End

#Rem monkeydoc
	This Functions Returns all Files within a Paths as an Array of String
#End
Function GetFolderFiles:String[](path:String)
	Local i:=0
	Local lfiles:String[] = New String[1000]

    For Local f:=Eachin LoadDir( path,True )
    	Local p:=path+f
        Local nm:=(f+"                    ")[..20]
       	Local ty:=""
        If FileType( p )=FILETYPE_FILE
        	lfiles[i] = p
       	 	i +=1
       		Print p
    	Else
            Print "### DIR ### " + i
       Endif

       'Print i

    Next

    Local files:String[] = New String[i]
    For Local j:Int = 0 Until i
       	files[j] = lfiles[j]
       	'Print files[j] '+" | " + lfiles[j]
    Next
    #rem
    For Local i:Int = 0 Until files.Length()
    	Print "loeaded: " + files[i]
    Next
    #end
       'Print "files: " + files.Length()
      Return files
End Function

Function GetFolderFiles2:List<String>(_Path:String)
	Local list:List<String> = New List<String>

	For Local f:=Eachin LoadDir(_Path,True )
    	Local p:=_Path+f
        'Local nm:=(f+"                    ")[..20]
       	'Local ty:=""
        If FileType( p )=FILETYPE_FILE
        	list.AddLast(p)
       		Print p
    	Else
            Print "### DIR ### "
       Endif

    Next

	Print "loaded Files: " + list.Count()

	Return list
End Function

error: pathspec 'maniac/maniacMisc.monkey' did not match any file(s) known to git


Added a new StringBuilder class since Monkey now has String.FromChars.

--HG--
extra : convert_revision : svn%3Ae934d3cd-0d57-f34a-94d0-9e8d31ae1c29/trunk%40337

Import arrays

Class StringBuilder
Public
	Const DEFAULT_SIZE:Int = 128

Private
	Field characters:Int[]
	Field length:Int

	Field dirty:Bool = False
	Field cache:String = ""

	Method ResizeArray:Void(targetSize:Int=-1, shrink:Bool=False)
		Local temp:Int = 2
		If targetSize < 0 Then targetSize = length
		While temp < targetSize
			temp *= 2
		End
		If temp = characters.Length Or temp < characters.Length And Not shrink Then Return
		If characters.Length = 0 Then
			characters = New Int[temp]
		Else
			characters = characters.Resize(temp)
		End
	End

	Method CachedString:String()
		If length <= 0 Then
			cache = ""
		Else
			cache = String.FromChars(characters[0..length])
		End
	End

Public
	Method Capacity:Int() Property
		Return characters.Length
	End

	Method Length:Int() Property
		Return length
	End

	Method Length:Void(length:Int) Property
		If length < 0 Then length = 0
		Local oldLength:Int = Self.length
		ResizeArray(length, True)
		If oldLength < length Then
			For Local i:Int = oldLength Until length
				characters[i] = $20 ' pad with spaces
			Next
		End
		Self.length = length
		dirty = True
	End

	Method New()
		characters = New Int[DEFAULT_SIZE]
		length = 0
		dirty = False
		cache = ""
	End

	Method New(defaultSize:Int)
		If defaultSize <= 0 Then defaultSize = DEFAULT_SIZE
		characters = New Int[defaultSize]
		length = 0
		dirty = False
		cache = ""
	End

	Method New(defaultValue:String)
		SetValue(defaultValue)
	End

	Method ToString:String()
		If length <= 0 Then Return ""
		If dirty Then
			cache = String.FromChars(characters[0..length])
			dirty = False
		End
		Return cache
	End

' SetValue
	Method SetValue:StringBuilder(value:Int)
		Return SetValue(String(value))
	End

	Method SetValue:StringBuilder(value:Float)
		Return SetValue(String(value))
	End

	Method SetValue:StringBuilder(value:Bool)
		If value Then Return SetValue("True")
		Return SetValue("False")
	End

	Method SetValue:StringBuilder(value:StringBuilder)
		Return SetValue(value.ToString())
	End

	Method SetValue:StringBuilder(value:String)
		dirty = True
		length = 0
		Return Append(value)
	End

	Method SetValue:StringBuilder(value:Int[])
		dirty = True
		length = 0
		Return Append(value)
	End

' Append
	Method Append:StringBuilder(value:Int)
		Return Append(String(value))
	End

	Method Append:StringBuilder(value:Float)
		Return Append(String(value))
	End

	Method Append:StringBuilder(value:Bool)
		If value Then Return Append("True")
		Return Append("False")
	End

	Method Append:StringBuilder(value:StringBuilder)
		Return Append(value.ToString())
	End

	Method Append:StringBuilder(value:String)
		dirty = True
		Local temp:Int = length + value.Length
		ResizeArray(temp)
		For Local i:Int = 0 Until value.Length
			characters[length+i] = value[i]
		Next
		length += value.Length
		Return Self
	End

	Method Append:StringBuilder(value:Int[])
		dirty = True
		Local temp:Int = length + value.Length
		ResizeArray(temp)
		Arrays<Int>.Copy(value, 0, characters, length, value.Length)
		length += value.Length
		Return Self
	End

' Delete
	Method Delete:StringBuilder(startIndex:Int, endIndex:Int)
		If startIndex < 0 Or startIndex > length Then Error("Start index ("+startIndex+") out of range [0-"+(length-1)+"]")
		If startIndex > endIndex Then Error("Start index ("+startIndex+") greater than end index ("+endIndex+")")
		If endIndex > length Then endIndex = length
		Local len:Int = endIndex - startIndex
		If len > 0 Then
			dirty = True
			Arrays<Int>.Copy(characters, endIndex, characters, startIndex, length-endIndex)
			Self.length -= len
		End
		Return Self
	End

' Find/FindLast (from Monkey strings)
	Method Find:Int(str:String, start:Int=0)
		Return ToString().Find(str, start)
	End

	Method FindLast:Int(str:String)
		Return ToString().FindLast(str)
	End

	Method FindLast:Int(str:String, start:Int)
		Return ToString().FindLast(str, start)
	End

' Insert
	Method Insert:StringBuilder(index:Int, value:Int)
		Return Insert(index, String(value))
	End

	Method Insert:StringBuilder(index:Int, value:Float)
		Return Insert(index, String(value))
	End

	Method Insert:StringBuilder(index:Int, value:Bool)
		If value Then Return Insert(index, "True")
		Return Insert(index, "False")
	End

	Method Insert:StringBuilder(index:Int, value:StringBuilder)
		Return Insert(index, value.ToString())
	End

	Method Insert:StringBuilder(index:Int, value:String)
		dirty = True
		If index < 0 Or index > length Then Error("Index ("+index+") out of range [0-"+(length-1)+"]")
		Local len:Int = value.Length()
		Local newlen:Int = length + len
		ResizeArray(newlen)
		Arrays<Int>.Copy(characters, index, characters, index+len, length-index)
		For Local i:Int = 0 Until len
			characters[index+i] = value[i]
		Next
		length += value.Length
		Return Self
	End

	Method Insert:StringBuilder(index:Int, value:Int[])
		dirty = True
		If index < 0 Or index > length Then Error("Index ("+index+") out of range [0-"+(length-1)+"]")
		Local len:Int = value.Length
		Local newlen:Int = length + len
		ResizeArray(newlen)
		Arrays<Int>.Copy(characters, index, characters, index+len, length-index)
		Arrays<Int>.Copy(value, 0, characters, index, len)
		length += value.Length
		Return Self
	End

' Replace
	Method Replace:StringBuilder(startIndex:Int, endIndex:Int, value:Int)
		Return Replace(startIndex, endIndex, String(value))
	End

	Method Replace:StringBuilder(startIndex:Int, endIndex:Int, value:Float)
		Return Replace(startIndex, endIndex, String(value))
	End

	Method Replace:StringBuilder(startIndex:Int, endIndex:Int, value:Bool)
		If value Then Return Replace(startIndex, endIndex, "True")
		Return Replace(startIndex, endIndex, "False")
	End

	Method Replace:StringBuilder(startIndex:Int, endIndex:Int, value:StringBuilder)
		Return Replace(startIndex, endIndex, value.ToString())
	End

	Method Replace:StringBuilder(startIndex:Int, endIndex:Int, value:String)
		If startIndex < 0 Or startIndex > length Then Error("Start index ("+startIndex+") out of range [0-"+(length-1)+"]")
		If startIndex > endIndex Then Error("Start index ("+startIndex+") greater than end index ("+endIndex+")")
		If endIndex > length Then endIndex = length
		dirty = True
		Local len:Int = value.Length()
		Local newlen:Int = length + len - (endIndex - startIndex)
		ResizeArray(newlen)
		Arrays<Int>.Copy(characters, endIndex, characters, startIndex + len, length - endIndex)
		For Local i:Int = 0 Until len
			characters[startIndex+i] = value[i]
		Next
		length -= endIndex-startIndex
		length += value.Length
		Return Self
	End

	Method Replace:StringBuilder(startIndex:Int, endIndex:Int, value:Int[])
		If startIndex < 0 Or startIndex > length Then Error("Start index ("+startIndex+") out of range [0-"+(length-1)+"]")
		If startIndex > endIndex Then Error("Start index ("+startIndex+") greater than end index ("+endIndex+")")
		If endIndex > length Then endIndex = length
		dirty = True
		Local len:Int = value.Length
		Local newlen:Int = length + len - (endIndex - startIndex)
		ResizeArray(newlen)
		Arrays<Int>.Copy(characters, endIndex, characters, startIndex + len, length - endIndex)
		Arrays<Int>.Copy(value, 0, characters, startIndex, len)
		length -= endIndex-startIndex
		length += value.Length
		Return Self
	End

' Reverse
	Method Reverse:StringBuilder()
		If length <= 0 Then Return Self
		dirty = True
		Arrays<Int>.Reverse(characters)
		Return Self
	End

' Substring
	Method Substring:String(startIndex:Int, endIndex:Int)
		If startIndex < 0 Or startIndex > length Then Error("Start index ("+startIndex+") out of range [0-"+(length-1)+"]")
		If startIndex > endIndex Then Error("Start index ("+startIndex+") greater than end index ("+endIndex+")")
		If endIndex > length Then endIndex = length
		Local len:Int = endIndex-startIndex
		If len = 0 Then Return ""
		Return ToString()[startIndex..endIndex]
	End

' GetChars
	Method GetChars:Void(startIndex:Int, endIndex:Int, dest:Int[], destIndex:Int)
		If startIndex < 0 Or startIndex > length Then Error("Start index ("+startIndex+") out of range [0-"+(length-1)+"]")
		If startIndex > endIndex Then Error("Start index ("+startIndex+") greater than end index ("+endIndex+")")
		If endIndex > length Then endIndex = length
		Local len:Int = endIndex-startIndex
		If len > 0 Then Arrays<Int>.Copy(characters, startIndex, dest, destIndex, len)
	End

	Method GetChars:Int[](startIndex:Int, endIndex:Int)
		If startIndex < 0 Or startIndex > length Then Error("Start index ("+startIndex+") out of range [0-"+(length-1)+"]")
		If startIndex > endIndex Then Error("Start index ("+startIndex+") greater than end index ("+endIndex+")")
		If endIndex > length Then endIndex = length
		Local len:Int = endIndex-startIndex
		If len = 0 Then Return []
		Return Arrays<Int>.Slice(characters, startIndex, endIndex)
	End

' SetCharAt
	Method SetCharAt:Void(index:Int, ch:Int)
		If index < 0 Or index > length Then Error("Index ("+index+") out of range [0-"+(length-1)+"]")
		characters[index] = ch
	End

' DeleteCharAt
	Method DeleteCharAt:Void(index:Int)
		If index < 0 Or index > length Then Error("Index ("+index+") out of range [0-"+(length-1)+"]")
		Arrays<Int>.Copy(characters, index+1, characters, index, characters.Length-index-1)
		length -= 1
	End
End

error: pathspec 'src/diddy/stringbuilder.monkey' did not match any file(s) known to git


Added FlxTile

Added FlxTile

Strict

Import flixel.flxextern
Import flixel.flxobject
Import flixel.flxtilemap

Class FlxTile Extends FlxObject

	Field callback:FlxTileListener

	Field filter:FlxClass

	Field tilemap:FlxTilemap

	Field index:Int

	Field mapIndex:Int

	Method New(tilemap:FlxTilemap, index:Int, width:Float, height:Float, visible:Bool, allowCollisions:Int)
		Super.New(0, 0, width, height)
		immovable = True
		moves = False
		callback = Null
		filter = Null

		Self.tilemap = tilemap
		Self.index = index
		Self.visible = visible
		Self.allowCollisions = allowCollisions

		mapIndex = 0
	End Method

	Method Destroy:Void()
		Super.Destroy()
		callback = Null
		tilemap = Null
		filter = Null
	End Method

End Class

Interface FlxTileListener

	Method OnTileHit:Void(tile:FlxTile, object:FlxObject)

End Interface

error: pathspec 'system/flxtile.monkey' did not match any file(s) known to git


Create Main.monkey

Create Main.monkey

error: pathspec 'examples/GUI/Main.monkey' did not match any file(s) known to git


Create maniac.monkey

Create maniac.monkey

#Rem monkeydoc Module maniac
	Copyright (C) 2015  Stephan Duckerschein~n
	This Framework provides many additional Graphical Effects and primite Drawings, like unfilled rectangular , ellipsis etc. Diverse GUI Elements.~n
	It has it's own TileMap Engine included and even a Debug Tracking-System. ~n
	~n
	Installation:~n
	to use this Module, you have to Copy the "lib/" Folder data to Your App's Data.~n
	~n
	In the following is an Example, how to Include the maniac Framework to your Monkey Project.~n
Example:
<pre>
'This Example Shows how to integrate the Maniac-Framework to your App

'1. First You have to Import the Libs
import mojo
import maniac

'2. Main Function and App extending Class
Function Main:Int()
	New Example
	Return 0
End

Class Example extends App
	Method OnCreate:Int()
		SetUpdateRate( 60 )
		initManiac()			' THIS INITS THE MANIAC FRAMEWORK! THIS NEED TO BE DONE BEFORE USING IT!!!!!
	end Method

	Method OnUpdate:int()

	end method

	Method OnRender:int()
		Cls
	end Method
End class
</pre>

~n
Featurelist:
	GUI: - Textfield, Button, Dialog, GalleryViewer, Slider, DropDown, ListView, Checkbox ~n
	Graphics: - Outlined: Rect, Ellipsis ; LighningFX, Grid ~n
	TileMap: TileMapEngine featuring an Editor~n
	Font: Including a Font~n

#End

#rem
 <The Duke Game Framework. It provides useful little helperfunctions and class to develope 2D Games with Monkey X>
    Copyright (C) 2014-2015  Stephan Duckerschein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #end

#rem
	The main Aim is to provide a wideranged kit for developing games with Monkey X.
	It tries to be as lightweight as possible.
	And it should be usable without changeging the mojo framework.

	Features:
		DebugSystem: It tracks all used Elements from Maniac within the DebugClass.
		So you can easily monitor your Objects.
#end

#rem
	Importing the Module-Parts of the maniac Framework.
#end

Import maniacLowLevel			'325		364
Import maniacFont				'249
Import maniacDebug				'334
Import maniacGraphics			'686		763
Import maniacMisc				'248
Import maniacSimpleGUI			'1214		1515
Import maniacTween				'667
Import maniacMap				'168

#rem
	These are all global accessable Objects to your project.They will be initialised automatically within the initManiac() Method.
#end
Global MANIAC_FONT:ManiacFont
Global MANIAC_IMG_LOGO:Image
Global MANIAC_IMG_STAR:Image
Global MANIAC_IMG_STARBLUR:Image
Global MANIAC_IMG_BACKGROUND:Image
Global MANIAC_IMG_FRAME_RAW:Image 		'
Global MANIAC_IMG_FRAME_BLUR:Image
Global MANIAC_IMG_SLIDERLINE:Image
Global MANIAC_IMG_SLIDERPICKER:Image
Global MANIAC_IMG_EDITICON:Image
Global MANIAC_IMG_CHECK:Image
Global MANIAC_IMG_DROPDOWN:Image
Global MANIAC_IMG_ARROWDOWN:Image
Global MANIAC_CHARACTERSCOUNT:Int = 30

Const FPSGRAPH_OFF:Int = 0
Const FPSGRAPH_FPS_ONLY:Int = 1
Const FPSGRAPH_GRAPH:Int = 2

Global MANIAC_FPSGRAPH:Maniac_Debug' = New fpsCounter
Global MODULE_INITED_CORRECT:Bool 		'if false, the whole Maniac-Module uses a fallback Drawings-Stuff

Global DW:Float,DH:Float,MX:Float,MY:Float
'Mouse Button States
Global gl_clicked:Bool
Global gl_mousereleased:Bool

Global MANIAC_DEBUG:Bool = False

Global maniac_lastTime:Int
Global maniac_timeScale:Float

#Rem monkeydoc
	This Function Inits this Module.
	It Loads all necessary Images and Sounds and stuff from the lib/ folder.
	if No Images were found, it falls back to a "at least running without any Image" mode. so it just shows up, that there are Graphics missing
#End
Function initManiac(_Debug:Bool = False)
	MANIAC_DEBUG = _Debug
	DW = DeviceWidth()
	DH = DeviceHeight()
	MODULE_INITED_CORRECT = True
	MANIAC_FONT = New ManiacFont(22,27,["lib/font2.png"],[[32,5,27,0,0,0,0,0,0,19],[33,5,27,0,393,46,7,18,-1,4],[34,9,27,0,122,99,10,10,-1,3],[35,15,27,0,51,66,17,17,-1,5],[36,16,27,0,478,0,18,22,-1,2],[37,20,27,0,332,25,21,21,-1,2],[38,16,27,0,34,66,17,17,-1,5],[39,5,27,0,116,99,6,10,-1,3],[40,9,27,0,89,0,11,24,-1,2],[41,9,27,0,78,0,11,24,-1,2],[42,14,27,0,378,46,15,18,-1,4],[43,12,27,0,386,83,14,14,-1,6],[44,6,27,0,109,99,7,10,-1,14],[45,10,27,0,174,99,12,7,-1,10],[46,5,27,0,219,99,6,6,-1,15],[47,12,27,0,366,25,13,21,-1,2],[48,18,27,0,24,83,19,16,-1,5],[49,12,27,0,60,83,14,16,-1,5],[50,14,27,0,171,83,15,15,-1,6],[51,16,27,0,154,83,17,15,-1,6],[52,15,27,0,154,66,17,17,-1,5],[53,15,27,0,138,66,16,17,-1,5],[54,16,27,0,121,66,17,17,-1,5],[55,13,27,0,106,66,15,17,-1,5],[56,15,27,0,89,66,17,17,-1,5],[57,15,27,0,43,83,17,16,-1,6],[58,5,27,0,424,83,6,14,-1,7],[59,6,27,0,68,66,7,17,-1,7],[60,10,27,0,412,83,12,14,-1,7],[61,14,27,0,79,99,16,11,-1,7],[62,10,27,0,400,83,12,14,-1,7],[63,13,27,0,75,66,14,17,-1,5],[64,21,27,0,14,46,22,20,-1,6],[65,17,27,0,461,66,18,17,-1,5],[66,14,27,0,446,66,15,17,-1,5],[67,15,27,0,430,66,16,17,-1,5],[68,15,27,0,414,66,16,17,-1,5],[69,14,27,0,399,66,15,17,-1,5],[70,13,27,0,385,66,14,17,-1,5],[71,15,27,0,369,66,16,17,-1,5],[72,14,27,0,353,66,16,17,-1,5],[73,11,27,0,142,83,12,16,-1,6],[74,15,27,0,126,83,16,16,-1,5],[75,14,27,0,337,66,16,17,-1,5],[76,14,27,0,322,66,15,17,-1,5],[77,17,27,0,304,66,18,17,-1,5],[78,15,27,0,287,66,17,17,-1,5],[79,18,27,0,107,83,19,16,-1,5],[80,15,27,0,416,46,16,18,-1,4],[81,18,27,0,268,66,19,17,-1,5],[82,15,27,0,400,46,16,18,-1,4],[83,16,27,0,250,66,18,17,-1,5],[84,15,27,0,319,83,16,15,-1,6],[85,15,27,0,90,83,17,16,-1,5],[86,16,27,0,233,66,17,17,-1,5],[87,16,27,0,215,66,18,17,-1,5],[88,15,27,0,199,66,16,17,-1,5],[89,14,27,0,184,66,15,17,-1,5],[90,15,27,0,74,83,16,16,-1,5],[91,9,27,0,67,0,11,24,-1,2],[92,12,27,0,353,25,13,21,-1,2],[93,9,27,0,56,0,11,24,-1,2],[94,12,27,0,26,99,13,12,-1,2],[95,15,27,0,203,99,16,6,-1,20],[96,7,27,0,141,99,8,9,-1,3],[97,14,27,0,304,83,15,15,-1,7],[98,12,27,0,287,46,13,19,-1,3],[99,12,27,0,472,83,13,14,-1,7],[100,12,27,0,70,46,14,20,-1,2],[101,13,27,0,290,83,14,15,-1,7],[102,12,27,0,274,46,13,19,-1,3],[103,13,27,0,260,46,14,19,-1,7],[104,13,27,0,246,46,14,19,-1,3],[105,5,27,0,239,46,7,19,-1,3],[106,5,27,0,315,0,7,23,-1,3],[107,12,27,0,56,46,14,20,-1,2],[108,5,27,0,50,46,6,20,-1,2],[109,16,27,0,272,83,18,15,-1,7],[110,13,27,0,258,83,14,15,-1,7],[111,12,27,0,458,83,14,14,-1,7],[112,12,27,0,36,46,14,20,-1,7],[113,13,27,0,225,46,14,19,-1,7],[114,10,27,0,246,83,12,15,-1,7],[115,13,27,0,232,83,14,15,-1,7],[116,12,27,0,171,66,13,17,-1,4],[117,12,27,0,218,83,14,15,-1,7],[118,13,27,0,443,83,15,14,-1,7],[119,16,27,0,200,83,18,15,-1,7],[120,13,27,0,186,83,14,15,-1,7],[121,13,27,0,211,46,14,19,-1,7],[122,12,27,0,430,83,13,14,-1,8],[123,12,27,0,28,0,14,25,-1,2],[124,5,27,0,309,0,6,23,-1,3],[125,12,27,0,14,0,14,25,-1,2],[126,15,27,0,157,99,17,8,-1,10],[127,13,27,0,0,46,14,20,-1,3],[161,5,27,0,371,46,7,18,-1,9],[162,12,27,0,465,0,13,22,-1,3],[163,14,27,0,18,66,16,17,-1,5],[164,16,27,0,0,66,18,17,-1,4],[165,14,27,0,481,46,15,17,-1,5],[166,5,27,0,303,0,6,23,-1,3],[167,13,27,0,317,25,15,21,-1,5],[168,9,27,0,192,99,11,6,-1,5],[169,21,27,0,189,46,22,19,-1,5],[170,13,27,0,65,99,14,11,-1,5],[171,17,27,0,368,83,18,14,-1,7],[172,12,27,0,95,99,14,10,-1,10],[174,21,27,0,167,46,22,19,-1,5],[176,12,27,0,52,99,13,11,-1,4],[177,13,27,0,357,46,14,18,-1,4],[178,12,27,0,0,99,13,13,-1,4],[179,12,27,0,13,99,13,12,-1,5],[180,8,27,0,132,99,9,9,-1,3],[181,14,27,0,152,46,15,19,-1,7],[182,18,27,0,297,25,20,21,-1,4],[183,5,27,0,186,99,6,6,-1,10],[184,7,27,0,149,99,8,8,-1,17],[185,7,27,0,498,83,8,13,-1,5],[186,11,27,0,39,99,13,11,-1,5],[187,17,27,0,350,83,18,14,-1,7],[188,17,27,0,278,25,19,21,-1,2],[189,18,27,0,259,25,19,21,-1,2],[190,18,27,0,239,25,20,21,-1,2],[191,13,27,0,467,46,14,17,-1,10],[192,17,27,0,285,0,18,23,-1,-1],[193,17,27,0,267,0,18,23,-1,-1],[194,17,27,0,249,0,18,23,-1,-1],[195,17,27,0,447,0,18,22,-1,0],[196,17,27,0,221,25,18,21,-1,1],[197,17,27,0,231,0,18,23,-1,-1],[198,22,27,0,0,83,24,16,-1,6],[199,15,27,0,486,25,16,20,-1,5],[200,14,27,0,216,0,15,23,-1,-1],[201,14,27,0,201,0,15,23,-1,-1],[202,14,27,0,186,0,15,23,-1,-1],[203,14,27,0,206,25,15,21,-1,1],[204,11,27,0,174,0,12,23,-1,-1],[205,11,27,0,162,0,12,23,-1,-1],[206,12,27,0,148,0,14,23,-1,-1],[207,11,27,0,194,25,12,21,-1,1],[208,17,27,0,448,46,19,17,-1,5],[209,15,27,0,430,0,17,22,-1,0],[210,18,27,0,411,0,19,22,-1,-1],[211,18,27,0,392,0,19,22,-1,-1],[212,18,27,0,373,0,19,22,-1,-1],[213,18,27,0,175,25,19,21,-1,0],[214,18,27,0,467,25,19,20,-1,1],[215,12,27,0,485,83,13,13,-1,7],[216,18,27,0,129,0,19,23,-1,2],[217,15,27,0,356,0,17,22,-1,-1],[218,15,27,0,339,0,17,22,-1,-1],[219,15,27,0,322,0,17,22,-1,-1],[220,15,27,0,450,25,17,20,-1,1],[221,14,27,0,114,0,15,23,-1,-1],[222,14,27,0,432,46,16,17,-1,5],[223,14,27,0,342,46,15,18,-1,4],[224,14,27,0,160,25,15,21,-1,1],[225,14,27,0,145,25,15,21,-1,1],[226,14,27,0,130,25,15,21,-1,1],[227,14,27,0,435,25,15,20,-1,2],[228,14,27,0,137,46,15,19,-1,3],[229,14,27,0,115,25,15,21,-1,1],[230,21,27,0,479,66,23,16,-1,6],[231,12,27,0,329,46,13,18,-1,7],[232,13,27,0,101,25,14,21,-1,1],[233,13,27,0,87,25,14,21,-1,1],[234,13,27,0,72,25,15,21,-1,1],[235,13,27,0,123,46,14,19,-1,3],[236,7,27,0,64,25,8,21,-1,1],[237,8,27,0,55,25,9,21,-1,1],[238,11,27,0,42,25,13,21,-1,1],[239,9,27,0,112,46,11,19,-1,3],[240,14,27,0,314,46,15,18,-1,3],[241,13,27,0,421,25,14,20,-1,2],[242,12,27,0,407,25,14,20,-1,1],[243,12,27,0,393,25,14,20,-1,1],[244,12,27,0,379,25,14,20,-1,1],[245,12,27,0,98,46,14,19,-1,2],[246,12,27,0,300,46,14,18,-1,3],[247,14,27,0,335,83,15,14,-1,5],[248,12,27,0,28,25,14,21,-1,4],[249,12,27,0,14,25,14,21,-1,1],[250,12,27,0,0,25,14,21,-1,1],[251,12,27,0,496,0,14,21,-1,1],[252,12,27,0,84,46,14,19,-1,3],[253,13,27,0,0,0,14,25,-1,1],[254,12,27,0,42,0,14,24,-1,3],[255,13,27,0,100,0,14,23,-1,3]])
	MANIAC_IMG_BACKGROUND = LoadImage("lib/Hintergrund.png")
	MANIAC_IMG_STAR = LoadImage("lib/star.png")
	MANIAC_IMG_LOGO = LoadImage("lib/logo.png")
	MANIAC_IMG_FRAME_RAW = LoadImage("lib/Frame_raw2.png",1,Image.MidHandle)
	MANIAC_IMG_FRAME_BLUR = LoadImage("lib/Frame_blur.png",1,Image.MidHandle)
	MANIAC_IMG_EDITICON = LoadImage("lib/ico_edit.png")
	MANIAC_IMG_SLIDERLINE = LoadImage("lib/Slider_Line.png")
	MANIAC_IMG_SLIDERPICKER = LoadImage("lib/Slider_Picker.png",1,Image.MidHandle)
	MANIAC_IMG_CHECK = LoadImage("lib/ico_check.png")
	MANIAC_IMG_DROPDOWN = LoadImage("lib/ico_dropdown.png")
	MANIAC_IMG_ARROWDOWN = LoadImage("lib/ico_arrowdown.png")

	If MANIAC_DEBUG = True
		MANIAC_FPSGRAPH = New Maniac_Debug(DW*0.2,DH*0.8,DW*0.65,DH*0.19)
	Endif
	If MANIAC_FONT = Null
		Print "Found no Font Data"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_IMG_FRAME_RAW = Null
		Print "Found no Raw Frame Data"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_IMG_FRAME_BLUR = Null
		Print "Found no blurred Frame Data"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_IMG_EDITICON = Null
		Print "Found no Edit_Icon"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_FPSGRAPH = Null
		Print "Couldnt create an FPS Graph"
		MODULE_INITED_CORRECT = False
	Endif

End Function

#Rem monkeydoc
	This Function should called on every Update() MEthod within your App.
	It keeps some important states of the ManiacModule active
#End
Function maniacUpdate()
	UpdateAsyncEvents()
	If MANIAC_DEBUG = True
		Maniac_Debug.addCall()
	Endif

	MX = MouseX()
	MY = MouseY()

	Maniac_CheckMouseState()

	ll_UpdateSpeeds()
End Function

Function maniacSetDebug(b:Bool = True)
	MANIAC_DEBUG = b
End Function

error: pathspec 'maniac/maniac.monkey' did not match any file(s) known to git


Added missing Assests class for FlxInvaders

Strict

Class Assets

	Const IMAGE_PLAYER_SHIP:String = "ship"

	Const IMAGE_ALIEN_SHIP:String = "alien"

End Class

error: pathspec 'examples/flxinvaders/src/assets.monkey' did not match any file(s) known to git


only start the intro if there was an previous scene

Strict

Private

Import bono

Public

Class SceneTransitionFlash Extends SceneTransitionProxy Implements Colorable
    Private

    Field animation:Animation
    Field intro:Animation
    Field effect := New EffectColorAlpha(1.0, 0.0)
    Field blend := New ColorBlend()
    Field switched := True

    Public

    Method New()
        Throw New InvalidConstructorException("use New(Float, Transition)")
    End

    Method New(duration:Float, transition:Transition)
        animation = New Animation(duration, transition)
        animation.AddLast(effect)

        effect.AddLast(blend)
    End

    Method WithIntro:Void()
        WithIntro(animation.GetDuration())
    End

    Method WithIntro:Void(duration:Float)
        WithIntro(duration, animation.GetTransition())
    End

    Method WithIntro:Void(duration:Float, transition:Transition)
        intro = New Animation(duration, transition)
        intro.AddLast(New EffectReverse(effect))
    End

    Method SetColor:Void(newColor:Color)
        blend.SetColor(newColor)
    End

    Method GetColor:Color()
        Return blend.GetColor()
    End

    Method Switch:Void(prevScene:Sceneable, nextScene:Sceneable)
        Self.prevScene = prevScene
        Self.nextScene = nextScene
        switched = False
        animation.Restart()

        If intro And prevScene
            intro.Restart()
            activeScene = prevScene
        Else
            SwitchOver()
        End
    End

    Method Finish:Void()
        If intro Then intro.Stop()
        animation.Stop()

        SwitchOver()
    End

    Method OnRender:Void()
        Super.OnRender()
        blend.OnRender()
    End

    Method OnUpdate:Void(timer:DeltaTimer)
        If intro
            intro.OnUpdate(timer)
            If intro.IsPlaying()
                Super.OnUpdate(timer)
                Return
            Else
                SwitchOver()
            End
        End

        animation.OnUpdate(timer)
        Super.OnUpdate(timer)

        If Not animation.IsPlaying()
            Director.Shared().GetApp().SetHandler(nextScene)
        End
    End

    Private

    Method SwitchOver:Void()
        If switched Then Return
        switched = True

        activeScene = nextScene
        TriggerSceneLeaveAndEnter()
    End

    Method TriggerSceneLeaveAndEnter:Void()
        If prevScene Then prevScene.OnSceneLeave()
        If nextScene Then nextScene.OnSceneEnter()
    End
End

Strict

Private

Import bono

Public

Class SceneTransitionFlash Extends SceneTransitionProxy Implements Colorable
    Private

    Field animation:Animation
    Field intro:Animation
    Field effect := New EffectColorAlpha(1.0, 0.0)
    Field blend := New ColorBlend()
    Field switched := True

    Public

    Method New()
        Throw New InvalidConstructorException("use New(Float, Transition)")
    End

    Method New(duration:Float, transition:Transition)
        animation = New Animation(duration, transition)
        animation.AddLast(effect)

        effect.AddLast(blend)
    End

    Method WithIntro:Void()
        WithIntro(animation.GetDuration())
    End

    Method WithIntro:Void(duration:Float)
        WithIntro(duration, animation.GetTransition())
    End

    Method WithIntro:Void(duration:Float, transition:Transition)
        intro = New Animation(duration, transition)
        intro.AddLast(New EffectReverse(effect))
    End

    Method SetColor:Void(newColor:Color)
        blend.SetColor(newColor)
    End

    Method GetColor:Color()
        Return blend.GetColor()
    End

    Method Switch:Void(prevScene:Sceneable, nextScene:Sceneable)
        Self.prevScene = prevScene
        Self.nextScene = nextScene
        switched = False
        animation.Restart()

        If intro
            intro.Restart()
            activeScene = prevScene
        Else
            SwitchOver()
        End
    End

    Method Finish:Void()
        If intro Then intro.Stop()
        animation.Stop()

        SwitchOver()
    End

    Method OnRender:Void()
        Super.OnRender()
        blend.OnRender()
    End

    Method OnUpdate:Void(timer:DeltaTimer)
        If intro
            intro.OnUpdate(timer)
            If intro.IsPlaying()
                Super.OnUpdate(timer)
                Return
            Else
                SwitchOver()
            End
        End

        animation.OnUpdate(timer)
        Super.OnUpdate(timer)

        If Not animation.IsPlaying()
            Director.Shared().GetApp().SetHandler(nextScene)
        End
    End

    Private

    Method SwitchOver:Void()
        If switched Then Return
        switched = True

        activeScene = nextScene
        TriggerSceneLeaveAndEnter()
    End

    Method TriggerSceneLeaveAndEnter:Void()
        If prevScene Then prevScene.OnSceneLeave()
        If nextScene Then nextScene.OnSceneEnter()
    End
End