Soundtray support virtual resolution fixed

Strict

Import mojo

Import flxextern
Import flxbasic
Import flxstate
Import flxcamera
Import flxtimer
Import flxtext
Import flxg
Import flxu
Import flxtilemap
Import system.flxassetsmanager
Import system.flxfont
Import system.flxdebugger
Import system.flxreplay
Import plugin.timermanager

Import "data/flx_beep.mp3"

'#HTML5_SUSPEND_ON_BLUR_ENABLED = "true"

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field useVirtualResolution:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Float

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:FlxClass

	Field _created:Bool

	Field _total:Int

	Field _accumulator:Float

	Field _step:Float

	Field _maxAccumulation:Float

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _updaterate:Int

	Field _framerate:Int

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:FlxClass, zoom:Float = 1, updaterate:Int = 60, framerate:Int = 30, useSystemCursor:Bool = False)
		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 60
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Framerate = framerate
		FlxG.Updaterate = updaterate
		_total = 0

		_state = Null

		useSoundHotKeys = Not IsMobile()
		Self.useSystemCursor = useSystemCursor
		useVirtualResolution = True

		If (Not useSystemCursor) HideMouse()

		forceDebugger = False
		_debuggerUp = False

		_replay = New FlxReplay()
		_replayRequested = False
		_recordingRequested = False
		_replaying = False
		_recording = False

		_iState = initialState
		_requestedState = Null
		_requestedReset = True
		_created = False
	End Method

	Method OnCreate:Int()
		_InitData()
		_Step()

		_soundTrayX	= (FlxG.Width / 2) * FlxCamera.DefaultZoom * FlxG._DeviceScaleFactorX - (_soundTrayWidth / 2) + FlxG.Camera.X
		_soundTrayLabel = New FlxText(10, 32, _soundTrayWidth, "VOLUME")
		_soundTrayLabel.SetFormat(FlxText.SYSTEM_FONT, 16, FlxG.WHITE, FlxText.ALIGN_CENTER)
		Return 0
	End Method

	Method OnUpdate:Int()
		#If TARGET <> "ios" Or TARGET <> "android"
			If (useSoundHotKeys) Then
				If (KeyHit(KEY_0)) Then
					FlxG.Mute = Not FlxG.Mute

					If (FlxG.VolumeHandler <> Null) Then
						If (FlxG.Mute) Then
							FlxG.VolumeHandler.OnVolumeChange(0)
						Else
							FlxG.VolumeHandler.OnVolumeChange(FlxG.Volume())
						End If
					End If

					_ShowSoundTray()
				End If

				If (KeyHit(KEY_MINUS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() - .1)
					_ShowSoundTray()
				End If

				If (KeyHit(KEY_EQUALS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() + .1)
					_ShowSoundTray()
				End If
			End If

			_UpdateSoundTray(_step)
		#End

		Return 0
	End Method

	Method OnRender:Int()
		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Local mark:Int = Millisecs()
		Local elapsedMS:Int = mark - _total
		_total = mark

		If (_debugger <> Null) Then
			'TODO!
		Else
			_accumulator += elapsedMS

			if (_accumulator > _maxAccumulation) Then
				_accumulator = _maxAccumulation
			End If

			While (_accumulator >= _step)
				_Step()
				_accumulator -= _step
			Wend
		End If

		FlxBasic._VisibleCount = 0

		_Draw()

		Return 0
	End Method

	Method OnSuspend:Int()
		ShowMouse()
		FlxG.PauseSounds()
		Return 0
	End Method

	Method OnResume:Int()
		If (Not _debuggerUp And Not useSystemCursor) Then
			HideMouse()
		End If

		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnContentInit:Void()
	End Method

Private
	Method _ShowSoundTray:Void(silent:Bool = False)
		If (Not silent) Then
			FlxG.Play(FlxG.DATA_PREFIX + "beep")
		End If

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()
		FlxG.ResetInput()
		FlxG.DestroySounds()
		FlxG.ClearBitmapCache()

		If (_debugger <> Null) Then
			'TODO!
		End If

		Local timeManager:TimerManager = FlxTimer.Manager()
		If (timeManager <> Null) timeManager.Clear()

		If (_state <> Null) _state.Destroy()

		_state = _requestedState
		_state.Create()

		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If
	End Method

	Method _Step:Void()
		If (_requestedReset) Then
			_requestedReset = False
			_requestedState = FlxState(_iState.CreateInstance())
			_replayTimer = 0
			_replayCancelKeys = []
			_Reset()
			FlxG.Reset()
		End If

		If (_recordingRequested) Then
			_recordingRequested = False
			_replay.Create(FlxG.GlobalSeed)
			_recording = True

			If (_debugger <> Null) Then
				'TODO
				FlxG.Log("FLIXEL: starting new flixel gameplay record.")
			End If

		ElseIf (_replayRequested)
			_replayRequested = False
			_replay.Rewind()
			FlxG.GlobalSeed = _replay.seed

			If (_debugger <> Null) Then
				'TODO
			End If

			_replaying = True
		End If

		If (_state <> _requestedState) _SwitchState()

		FlxBasic._ActiveCount = 0

		If (_replaying) Then
			If (_replayCancelKeys.Length() > 0 And Not KeyDown(192) And Not KeyDown(220)) Then
				Local i:Int = 0
				Local l:Int = _replayCancelKeys.Length()

				While (i < l)
					If (KeyDown(_replayCancelKeys[i])) Then
						If (_replayCallback <> Null) Then
							_replayCallback.OnReplayComplete()
							_replayCallback = Null
						Else
							FlxG.StopReplay()
						End If

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

				If (_replayTimer <= 0) Then
					If (_replayCallback <> Null) Then
						_replayCallback.OnReplayComplete()
						_replayCallback = Null
					Else
						FlxG.StopReplay()
					End If
				End If
			End If

			If (_replaying And _replay.finished) Then
				FlxG.StopReplay()

				If (_replayCallback <> Null) Then
					_replayCallback.OnReplayComplete()
					_replayCallback = Null
				End If
			End If

			If (_debugger <> Null) Then
				'TODO
			End If
		Else
			FlxG.UpdateInput()
		End If

		If (_recording) Then
			_replay.RecordFrame()

			If (_debugger <> Null) Then
				'TODO
			End If
		End If

		_Update()

		If (_debugger <> Null) Then
			'TODO
		End If
	End Method

	Method _Update:Void()
		FlxG.Elapsed = FlxG.TimeScale * (_step / 1000.0)

		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.Update()
		FlxG.UpdateCameras()

		If (_debuggerUp) Then
			'TODO!
		End If
	End Method

	Method _UpdateSoundTray:Void(ms:Int)
		If (Not _soundTrayVisible) Return

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= ms / 1000.0

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (ms / 1000.0 * FlxG.Height * 2)

			If (_soundTrayY <= -_soundTrayHeight) Then
				_soundTrayVisible = False

				'TODO Save sound settings
			End If
		End If
	End Method

	Method _Draw:Void()
		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)

		PushMatrix()
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

		FlxG._LastDrawingColor = FlxG.WHITE
		FlxG._LastDrawingBlend = GetBlend()
		FlxG._LastDrawingAlpha = GetAlpha()
		FlxG._CurrentCamera = Null

		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG._CurrentCamera = FlxG.Cameras.Get(i)

			If (Not FlxG._CurrentCamera.active) Then
				i+=1
				Continue
			End If

			FlxG._CurrentCameraID = i

			If (FlxG._CurrentCamera = Null Or Not FlxG._CurrentCamera.exists Or Not FlxG._CurrentCamera.visible) Continue

			FlxG._CurrentCamera.DrawFX() 'not realy draw. Only calculation
			FlxG._CurrentCamera.Lock()
			_state.Draw()
			FlxG.DrawPlugins()
			FlxG._CurrentCamera.Unlock()

			i+=1
		Wend

		PopMatrix()

		#If TARGET <> "ios" Or TARGET <> "android"
			_DrawSoundTray()
		#End

		FlxG.Mouse.Draw()
	End Method

	Method _DrawSoundTray:Void()
		If (_soundTrayVisible) Then
			Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
			If (FlxG.Mute) globalVolume = 0

			PushMatrix()
			Translate(_soundTrayX, _soundTrayY)

			If (FlxG._LastDrawingAlpha <> .5) Then
				SetAlpha(.5)
				FlxG._LastDrawingAlpha = .5
			End If

			If (FlxG._LastDrawingColor <> FlxG.BLACK) Then
				SetColor(0, 0, 0)
			End If

			DrawRect(0, 0, _soundTrayWidth, _soundTrayHeight)

			SetColor(255, 255, 255)
			FlxG._LastDrawingColor = FlxG.WHITE

			Local bx:Int = 20
			Local by:Int = 28

			Local i:Int = 0
			While (i < 10)
				If (i < globalVolume) Then
					If (FlxG._LastDrawingAlpha <> 1) Then
						SetAlpha(1)
						FlxG._LastDrawingAlpha = 1
					End If

				Else
					If (FlxG._LastDrawingAlpha <> .5) Then
						SetAlpha(.5)
						FlxG._LastDrawingAlpha = .5
					End If
				End If

				DrawRect(bx, by, 8, i * 2)

				bx += 12
				by -= 2
				i += 1
			Wend

			_soundTrayLabel.Draw()

			PopMatrix()
		End If
	End Method

	Method _Reset:Void()
		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Seed = SystemMillisecs()

		FlxG.DeviceWidth = DeviceWidth()
		FlxG.DeviceHeight = DeviceHeight()

		If (useVirtualResolution) Then
			FlxG._DeviceScaleFactorX = FlxG.DeviceWidth / Float(FlxG.Width)
			FlxG._DeviceScaleFactorY = FlxG.DeviceHeight / Float(FlxG.Height)
		Else
			FlxG._DeviceScaleFactorX = 1
			FlxG._DeviceScaleFactorY = 1
		End If
	End Method

	Method _ResetFramerate:Void()
		SetUpdateRate(FlxG.Framerate)

		_step = 1000.0 / FlxG.Updaterate
		_maxAccumulation = 2000.0 / FlxG.Framerate - 1

		If (_maxAccumulation < _step) Then
			_maxAccumulation = _step
		End If

		_updaterate = FlxG.Updaterate
		_framerate = FlxG.Framerate
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

		Local minSystemFontSize:Int = 8
		Local maxSystemFontSize:Int = 24
		Local fontPathPrefix:String = FlxG.DATA_PREFIX + FlxText.SYSTEM_FONT + "_font_"

		Local system:FlxFont = 	FlxAssetsManager.AddFont(FlxText.SYSTEM_FONT)

		For Local size:Int = minSystemFontSize To maxSystemFontSize
			system.SetPath(size, fontPathPrefix + Min(size, 17) + ".png")
		Next

		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "default", FlxG.DATA_PREFIX + "default.png")
		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "button", FlxG.DATA_PREFIX + "button.png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES, FlxTilemap.AUTOTILES + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES_ALT, FlxTilemap.AUTOTILES_ALT + ".png")
		FlxAssetsManager.AddCursor(FlxG.DATA_PREFIX + "cursor", FlxG.DATA_PREFIX + "cursor.png")
		FlxAssetsManager.AddSound(FlxG.DATA_PREFIX + "beep", FlxG.DATA_PREFIX + "beep.mp3")

		Self.OnContentInit()
	End Method
End Class

Private
Class FlxFPSCounter

	Field FPS:Int

Private
	Field _FPSCounter:Int

	Field _lastUpdateTime:Int

Public
	Method New()
		Reset()
	End Method

	Method Update:Void()
		If (_lastUpdateTime = 0) Then
			_lastUpdateTime = Millisecs()
		ElseIf (Millisecs() - _lastUpdateTime >= 1000) Then
			FPS = _FPSCounter
			_lastUpdateTime = Millisecs()
			_FPSCounter = 0
		End If

		_FPSCounter += 1
	End Method

	Method Reset:Void()
		FPS = FlxG.Framerate
		_FPSCounter = 0
		_lastUpdateTime = 0
	End Method

End Class

Strict

Import mojo

Import flxextern
Import flxbasic
Import flxstate
Import flxcamera
Import flxtimer
Import flxtext
Import flxg
Import flxu
Import flxtilemap
Import system.flxassetsmanager
Import system.flxfont
Import system.flxdebugger
Import system.flxreplay
Import plugin.timermanager

Import "data/flx_beep.mp3"

'#HTML5_SUSPEND_ON_BLUR_ENABLED = "true"

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field useVirtualResolution:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Float

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:FlxClass

	Field _created:Bool

	Field _total:Int

	Field _accumulator:Float

	Field _step:Float

	Field _maxAccumulation:Float

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _updaterate:Int

	Field _framerate:Int

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:FlxClass, zoom:Float = 1, updaterate:Int = 60, framerate:Int = 30, useSystemCursor:Bool = False)
		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 60
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Framerate = framerate
		FlxG.Updaterate = updaterate
		_total = 0

		_state = Null

		useSoundHotKeys = Not IsMobile()
		Self.useSystemCursor = useSystemCursor
		useVirtualResolution = True

		If (Not useSystemCursor) HideMouse()

		forceDebugger = False
		_debuggerUp = False

		_replay = New FlxReplay()
		_replayRequested = False
		_recordingRequested = False
		_replaying = False
		_recording = False

		_iState = initialState
		_requestedState = Null
		_requestedReset = True
		_created = False
	End Method

	Method OnCreate:Int()
		_InitData()
		_Step()

		_soundTrayX	= (FlxG.Width / 2) * FlxCamera.DefaultZoom - (_soundTrayWidth / 2)
		_soundTrayLabel = New FlxText(10, 32, _soundTrayWidth, "VOLUME")
		_soundTrayLabel.SetFormat(FlxText.SYSTEM_FONT, 16, FlxG.WHITE, FlxText.ALIGN_CENTER)
		Return 0
	End Method

	Method OnUpdate:Int()
		#If TARGET <> "ios" Or TARGET <> "android"
			If (useSoundHotKeys) Then
				If (KeyHit(KEY_0)) Then
					FlxG.Mute = Not FlxG.Mute

					If (FlxG.VolumeHandler <> Null) Then
						If (FlxG.Mute) Then
							FlxG.VolumeHandler.OnVolumeChange(0)
						Else
							FlxG.VolumeHandler.OnVolumeChange(FlxG.Volume())
						End If
					End If

					_ShowSoundTray()
				End If

				If (KeyHit(KEY_MINUS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() - .1)
					_ShowSoundTray()
				End If

				If (KeyHit(KEY_EQUALS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() + .1)
					_ShowSoundTray()
				End If
			End If

			_UpdateSoundTray(_step)
		#End

		Return 0
	End Method

	Method OnRender:Int()
		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Local mark:Int = Millisecs()
		Local elapsedMS:Int = mark - _total
		_total = mark

		If (_debugger <> Null) Then
			'TODO!
		Else
			_accumulator += elapsedMS

			if (_accumulator > _maxAccumulation) Then
				_accumulator = _maxAccumulation
			End If

			While (_accumulator >= _step)
				_Step()
				_accumulator -= _step
			Wend
		End If

		FlxBasic._VisibleCount = 0

		_Draw()

		Return 0
	End Method

	Method OnSuspend:Int()
		ShowMouse()
		FlxG.PauseSounds()
		Return 0
	End Method

	Method OnResume:Int()
		If (Not _debuggerUp And Not useSystemCursor) Then
			HideMouse()
		End If

		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnContentInit:Void()
	End Method

Private
	Method _ShowSoundTray:Void(silent:Bool = False)
		If (Not silent) Then
			FlxG.Play(FlxG.DATA_PREFIX + "beep")
		End If

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()
		FlxG.ResetInput()
		FlxG.DestroySounds()
		FlxG.ClearBitmapCache()

		If (_debugger <> Null) Then
			'TODO!
		End If

		Local timeManager:TimerManager = FlxTimer.Manager()
		If (timeManager <> Null) timeManager.Clear()

		If (_state <> Null) _state.Destroy()

		_state = _requestedState
		_state.Create()

		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If
	End Method

	Method _Step:Void()
		If (_requestedReset) Then
			_requestedReset = False
			_requestedState = FlxState(_iState.CreateInstance())
			_replayTimer = 0
			_replayCancelKeys = []
			_Reset()
			FlxG.Reset()
		End If

		If (_recordingRequested) Then
			_recordingRequested = False
			_replay.Create(FlxG.GlobalSeed)
			_recording = True

			If (_debugger <> Null) Then
				'TODO
				FlxG.Log("FLIXEL: starting new flixel gameplay record.")
			End If

		ElseIf (_replayRequested)
			_replayRequested = False
			_replay.Rewind()
			FlxG.GlobalSeed = _replay.seed

			If (_debugger <> Null) Then
				'TODO
			End If

			_replaying = True
		End If

		If (_state <> _requestedState) _SwitchState()

		FlxBasic._ActiveCount = 0

		If (_replaying) Then
			If (_replayCancelKeys.Length() > 0 And Not KeyDown(192) And Not KeyDown(220)) Then
				Local i:Int = 0
				Local l:Int = _replayCancelKeys.Length()

				While (i < l)
					If (KeyDown(_replayCancelKeys[i])) Then
						If (_replayCallback <> Null) Then
							_replayCallback.OnReplayComplete()
							_replayCallback = Null
						Else
							FlxG.StopReplay()
						End If

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

				If (_replayTimer <= 0) Then
					If (_replayCallback <> Null) Then
						_replayCallback.OnReplayComplete()
						_replayCallback = Null
					Else
						FlxG.StopReplay()
					End If
				End If
			End If

			If (_replaying And _replay.finished) Then
				FlxG.StopReplay()

				If (_replayCallback <> Null) Then
					_replayCallback.OnReplayComplete()
					_replayCallback = Null
				End If
			End If

			If (_debugger <> Null) Then
				'TODO
			End If
		Else
			FlxG.UpdateInput()
		End If

		If (_recording) Then
			_replay.RecordFrame()

			If (_debugger <> Null) Then
				'TODO
			End If
		End If

		_Update()

		If (_debugger <> Null) Then
			'TODO
		End If
	End Method

	Method _UpdateSoundTray:Void(ms:Int)
		If (Not _soundTrayVisible) Return

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= ms / 1000.0

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (ms / 1000.0 * FlxG.Height * 2)

			If (_soundTrayY <= -_soundTrayHeight) Then
				_soundTrayVisible = False

				'TODO Save sound settings
			End If
		End If
	End Method

	Method _Update:Void()
		FlxG.Elapsed = FlxG.TimeScale * (_step / 1000.0)

		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.Update()
		FlxG.UpdateCameras()

		If (_debuggerUp) Then
			'TODO!
		End If
	End Method

	Method _Draw:Void()
		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

		FlxG._LastDrawingColor = FlxG.WHITE
		FlxG._LastDrawingBlend = GetBlend()
		FlxG._LastDrawingAlpha = GetAlpha()
		FlxG._CurrentCamera = Null

		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG._CurrentCamera = FlxG.Cameras.Get(i)

			If (Not FlxG._CurrentCamera.active) Then
				i+=1
				Continue
			End If

			FlxG._CurrentCameraID = i

			If (FlxG._CurrentCamera = Null Or Not FlxG._CurrentCamera.exists Or Not FlxG._CurrentCamera.visible) Continue

			FlxG._CurrentCamera.DrawFX() 'not realy draw. Only calculation
			FlxG._CurrentCamera.Lock()
			_state.Draw()
			FlxG.DrawPlugins()
			FlxG._CurrentCamera.Unlock()

			i+=1
		Wend

		#If TARGET <> "ios" Or TARGET <> "android"
			If (_soundTrayVisible) Then
				Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
				If (FlxG.Mute) globalVolume = 0

				If (useVirtualResolution) Then
					Scale(1, 1)
				End If

				PushMatrix()
				Translate(_soundTrayX, _soundTrayY)

				If (FlxG._LastDrawingAlpha <> .5) Then
					SetAlpha(.5)
					FlxG._LastDrawingAlpha = .5
				End If

				If (FlxG._LastDrawingColor <> FlxG.BLACK) Then
					SetColor(0, 0, 0)
				End If

				DrawRect(0, 0, _soundTrayWidth, _soundTrayHeight)

				SetColor(255, 255, 255)
				FlxG._LastDrawingColor = FlxG.WHITE

				Local bx:Int = 20
				Local by:Int = 28

				Local i:Int = 0
				While (i < 10)
					If (i < globalVolume) Then
						If (FlxG._LastDrawingAlpha <> 1) Then
							SetAlpha(1)
							FlxG._LastDrawingAlpha = 1
						End If

					Else
						If (FlxG._LastDrawingAlpha <> .5) Then
							SetAlpha(.5)
							FlxG._LastDrawingAlpha = .5
						End If
					End If

					DrawRect(bx, by, 8, i * 2)

					bx += 12
					by -= 2
					i += 1
				Wend

				_soundTrayLabel.Draw()

				PopMatrix()
			End If
		#End

		FlxG.Mouse.Draw()
	End Method

	Method _Reset:Void()
		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Seed = SystemMillisecs()

		FlxG.DeviceWidth = DeviceWidth()
		FlxG.DeviceHeight = DeviceHeight()

		If (useVirtualResolution) Then
			FlxG._DeviceScaleFactorX = FlxG.DeviceWidth / Float(FlxG.Width)
			FlxG._DeviceScaleFactorY = FlxG.DeviceHeight / Float(FlxG.Height)
		Else
			FlxG._DeviceScaleFactorX = 1
			FlxG._DeviceScaleFactorY = 1
		End If
	End Method

	Method _ResetFramerate:Void()
		SetUpdateRate(FlxG.Framerate)

		_step = 1000.0 / FlxG.Updaterate
		_maxAccumulation = 2000.0 / FlxG.Framerate - 1

		If (_maxAccumulation < _step) Then
			_maxAccumulation = _step
		End If

		_updaterate = FlxG.Updaterate
		_framerate = FlxG.Framerate
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

		Local minSystemFontSize:Int = 8
		Local maxSystemFontSize:Int = 24
		Local fontPathPrefix:String = FlxG.DATA_PREFIX + FlxText.SYSTEM_FONT + "_font_"

		Local system:FlxFont = 	FlxAssetsManager.AddFont(FlxText.SYSTEM_FONT)

		For Local size:Int = minSystemFontSize To maxSystemFontSize
			system.SetPath(size, fontPathPrefix + Min(size, 17) + ".png")
		Next

		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "default", FlxG.DATA_PREFIX + "default.png")
		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "button", FlxG.DATA_PREFIX + "button.png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES, FlxTilemap.AUTOTILES + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES_ALT, FlxTilemap.AUTOTILES_ALT + ".png")
		FlxAssetsManager.AddCursor(FlxG.DATA_PREFIX + "cursor", FlxG.DATA_PREFIX + "cursor.png")
		FlxAssetsManager.AddSound(FlxG.DATA_PREFIX + "beep", FlxG.DATA_PREFIX + "beep.mp3")

		Self.OnContentInit()
	End Method
End Class

Private
Class FlxFPSCounter

	Field FPS:Int

Private
	Field _FPSCounter:Int

	Field _lastUpdateTime:Int

Public
	Method New()
		Reset()
	End Method

	Method Update:Void()
		If (_lastUpdateTime = 0) Then
			_lastUpdateTime = Millisecs()
		ElseIf (Millisecs() - _lastUpdateTime >= 1000) Then
			FPS = _FPSCounter
			_lastUpdateTime = Millisecs()
			_FPSCounter = 0
		End If

		_FPSCounter += 1
	End Method

	Method Reset:Void()
		FPS = FlxG.Framerate
		_FPSCounter = 0
		_lastUpdateTime = 0
	End Method

End Class


always handle failed LoadImage() in Sprite

Strict

Private

Import align
Import basedisplayobject
Import bono.src.kernel
Import bono.src.utils
Import mojo.graphics

Public

Class Sprite Extends BaseDisplayObject Implements Updateable, Renderable
    Private

    Field currentFrame:Int
    Field frameCount:Int
    Field frameSize:Vector2D
    Field frameTimer:Int
    Field image:Image
    Field renderPos:Vector2D = New Vector2D()
    Field imageName:String
    Field _scale:Vector2D = New Vector2D(1, 1)
    Global cacheImage:StringMap<Image> = New StringMap<Image>()
    Global cacheSize:StringMap<Vector2D> = New StringMap<Vector2D>()

    Public

    Field frameSpeed:Int
    Field loopAnimation:Bool
    Field rotation:Float

    Method New(imageName:String, pos:Vector2D=Null)
        Self.imageName = imageName

        LoadImage()
    End

    Method New(imageName:String, frameSize:Vector2D, frameCount:Int, frameSpeed:Int, pos:Vector2D=Null)
        Self.imageName = imageName
        Self.frameSize = frameSize
        Self.frameCount = frameCount
        Self.frameSpeed = frameSpeed

        LoadImage()
    End

    Method OnRender:Void()
        GetColor().Activate()
        renderPos.Set(GetCenter()).Mul(scale).Add(GetPosition())
        DrawImage(image, renderPos.x, renderPos.y, rotation, scale.x, scale.y, currentFrame)
        GetColor().Deactivate()
    End

    Method OnUpdate:Void(deltaTimer:DeltaTimer)
        If frameCount <= 0 Then Return
        If animationIsDone Then Return

        If frameTimer < frameSpeed
            frameTimer += deltaTimer.frameTime
            Return
        End

        If (currentFrame + 1) = frameCount
            If loopAnimation
                currentFrame = 1
            End
        Else
            currentFrame += 1
        End
        frameTimer = 0
    End

    Method Restart:Void()
        currentFrame = 0
    End

    Method animationIsDone:Bool() Property
        If loopAnimation Then Return False
        Return (currentFrame = frameCount)
    End

    Method scale:Vector2D() Property
        Return _scale
    End

    Method scale:Void(newScale:Vector2D) Property
        If image Then GetSize().Div(_scale).Mul(newScale)
        _scale = newScale
    End

    Method filepath:String() Property
        Return imageName
    End

    Method DrawImageRect:Void(pos:Vector2D, rectPos:Vector2D, rectSize:Vector2D)
        DrawImageRect(pos.x, pos.y, rectPos.x, rectPos.y, rectSize.x, rectSize.y)
    End

    Method DrawImageRect:Void(x:Float, y:Float, srcX:Float, srcY:Float, srcWidth:Float, srcHeight:Float)
        x += GetCenter().x
        y += GetCenter().y
        graphics.DrawImageRect(image, x, y, srcX, srcY, srcWidth, srcHeight, rotation, scale.x, scale.y, currentFrame)
    End

    Private

    Method CacheSet:Void(name:String, image:Image, size:Vector2D)
        cacheImage.Set(name, image)
        cacheSize.Set(name, size)
    End

    Method CacheGetSize:Vector2D(name:String)
        Return cacheSize.Get(name)
    End

    Method CacheGetImage:Image(name:String)
        Return cacheImage.Get(name)
    End

    Method LoadImage:Void()
        ' Try the cache first ...
        image = CacheGetImage(imageName)
        If image
            SetSize(CacheGetSize(imageName))
        End

        ' ... but handle misses aswell
        If Not image
            If frameSize
                image = graphics.LoadImage(imageName, frameSize.x, frameSize.y, frameCount, Image.MidHandle)
                FailIfImageNotLoaded()
                SetSize(frameSize.Copy())
            Else
                image = graphics.LoadImage(imageName, 1, Image.MidHandle)
                FailIfImageNotLoaded()
                SetSize(New Vector2D(image.Width(), image.Height()))
            End
            CacheSet(imageName, image, GetSize())
        End

        GetSize().Mul(scale)
    End

    Method FailIfImageNotLoaded:Void()
        If Not image Then Error("Unable to load: " + imageName)
    End
End

Strict

Private

Import align
Import basedisplayobject
Import bono.src.kernel
Import bono.src.utils
Import mojo.graphics

Public

Class Sprite Extends BaseDisplayObject Implements Updateable, Renderable
    Private

    Field currentFrame:Int
    Field frameCount:Int
    Field frameSize:Vector2D
    Field frameTimer:Int
    Field image:Image
    Field renderPos:Vector2D = New Vector2D()
    Field imageName:String
    Field _scale:Vector2D = New Vector2D(1, 1)
    Global cacheImage:StringMap<Image> = New StringMap<Image>()
    Global cacheSize:StringMap<Vector2D> = New StringMap<Vector2D>()

    Public

    Field frameSpeed:Int
    Field loopAnimation:Bool
    Field rotation:Float

    Method New(imageName:String, pos:Vector2D=Null)
        Self.imageName = imageName

        LoadImage()
    End

    Method New(imageName:String, frameSize:Vector2D, frameCount:Int, frameSpeed:Int, pos:Vector2D=Null)
        Self.imageName = imageName
        Self.frameSize = frameSize
        Self.frameCount = frameCount
        Self.frameSpeed = frameSpeed

        LoadImage()
    End

    Method OnRender:Void()
        GetColor().Activate()
        renderPos.Set(GetCenter()).Mul(scale).Add(GetPosition())
        DrawImage(image, renderPos.x, renderPos.y, rotation, scale.x, scale.y, currentFrame)
        GetColor().Deactivate()
    End

    Method OnUpdate:Void(deltaTimer:DeltaTimer)
        If frameCount <= 0 Then Return
        If animationIsDone Then Return

        If frameTimer < frameSpeed
            frameTimer += deltaTimer.frameTime
            Return
        End

        If (currentFrame + 1) = frameCount
            If loopAnimation
                currentFrame = 1
            End
        Else
            currentFrame += 1
        End
        frameTimer = 0
    End

    Method Restart:Void()
        currentFrame = 0
    End

    Method animationIsDone:Bool() Property
        If loopAnimation Then Return False
        Return (currentFrame = frameCount)
    End

    Method scale:Vector2D() Property
        Return _scale
    End

    Method scale:Void(newScale:Vector2D) Property
        If image Then GetSize().Div(_scale).Mul(newScale)
        _scale = newScale
    End

    Method filepath:String() Property
        Return imageName
    End

    Method DrawImageRect:Void(pos:Vector2D, rectPos:Vector2D, rectSize:Vector2D)
        DrawImageRect(pos.x, pos.y, rectPos.x, rectPos.y, rectSize.x, rectSize.y)
    End

    Method DrawImageRect:Void(x:Float, y:Float, srcX:Float, srcY:Float, srcWidth:Float, srcHeight:Float)
        x += GetCenter().x
        y += GetCenter().y
        graphics.DrawImageRect(image, x, y, srcX, srcY, srcWidth, srcHeight, rotation, scale.x, scale.y, currentFrame)
    End

    Private

    Method CacheSet:Void(name:String, image:Image, size:Vector2D)
        cacheImage.Set(name, image)
        cacheSize.Set(name, size)
    End

    Method CacheGetSize:Vector2D(name:String)
        Return cacheSize.Get(name)
    End

    Method CacheGetImage:Image(name:String)
        Return cacheImage.Get(name)
    End

    Method LoadImage:Void()
        ' Try the cache first ...
        image = CacheGetImage(imageName)
        If image
            SetSize(CacheGetSize(imageName))
        End

        ' ... but handle misses aswell
        If Not image
            If frameSize
                image = graphics.LoadImage(imageName, frameSize.x, frameSize.y, frameCount, Image.MidHandle)
                SetSize(frameSize.Copy())
            Else
                image = graphics.LoadImage(imageName, 1, Image.MidHandle)
                SetSize(New Vector2D(image.Width(), image.Height()))
            End
            CacheSet(imageName, image, GetSize())
        End

        If Not image Then Error("Unable to load: " + imageName)
        GetSize().Mul(scale)
    End
End


If OnUpdate was used to update the logic, then it will be used until the next reset

Strict

Import mojo

Import flxextern
Import flxbasic
Import flxstate
Import flxcamera
Import flxtimer
Import flxtext
Import flxg
Import flxu
Import flxtilemap
Import system.flxassetsmanager
Import system.flxfont
Import system.flxdebugger
Import system.flxreplay
Import plugin.timermanager

Import "data/flx_beep.mp3"

'#HTML5_SUSPEND_ON_BLUR_ENABLED = "true"

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field useVirtualResolution:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Int

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:FlxClass

	Field _created:Bool

	Field _lostFocus:Bool

	Field _step:Int

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _updatesCounter:FlxFPSCounter

	Field _rendersCounter:FlxFPSCounter

	Field _updatesLoopUsed:Bool

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:FlxClass, zoom:Float = 1, framerate:Int = 60, useSystemCursor:Bool = False)
		_lostFocus = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Framerate = framerate

		useSoundHotKeys = Not IsMobile()
		Self.useSystemCursor = useSystemCursor
		useVirtualResolution = True
		If (Not useSystemCursor) HideMouse()
		_debuggerUp = False

		_state = Null

		_replay = New FlxReplay()
		_replayRequested = False
		_recordingRequested = False
		_replaying = False
		_recording = False

		_iState = initialState
		_requestedState = Null
		_requestedReset = True
		_created = False

		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 60
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False

		_updatesCounter = New FlxFPSCounter()
		_rendersCounter = New FlxFPSCounter()
	End Method

	Method OnCreate:Int()
		_Reset()
		_InitData()
		_Step()

		_soundTrayX	= (FlxG.Width / 2) * FlxCamera.DefaultZoom - (_soundTrayWidth / 2)
		_soundTrayLabel = New FlxText(10, 32, _soundTrayWidth, "VOLUME")
		_soundTrayLabel.SetFormat(FlxText.SYSTEM_FONT, 16, FlxG.WHITE, FlxText.ALIGN_CENTER)
		Return 0
	End Method

	Method OnUpdate:Int()
		_updatesCounter.Update()

		If (_updatesLoopUsed Or (_rendersCounter.FPS >= 0 And _rendersCounter.FPS < FlxG.Framerate - 10)) Then
			'Real elapsed time very unstable in Monkey. TODO!
			FlxG.Elapsed = FlxG.TimeScale * (1.0 / _updatesCounter.FPS)
			_Step()

			_updatesLoopUsed = True
		End If
		Return 0
	End Method

	Method OnRender:Int()
		If (Not _updatesLoopUsed) Then
			_rendersCounter.Update()

			'Real elapsed time very unstable in Monkey. TODO!
			FlxG.Elapsed = FlxG.TimeScale * (1.0 / _rendersCounter.FPS)
			_Step()
		End If

		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

		FlxG._LastDrawingColor = FlxG.WHITE
		FlxG._LastDrawingBlend = GetBlend()
		FlxG._LastDrawingAlpha = GetAlpha()
		FlxG._CurrentCamera = Null

		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG._CurrentCamera = FlxG.Cameras.Get(i)

			If (Not FlxG._CurrentCamera.active) Then
				i+=1
				Continue
			End If

			FlxG._CurrentCameraID = i

			If (FlxG._CurrentCamera = Null Or Not FlxG._CurrentCamera.exists Or Not FlxG._CurrentCamera.visible) Continue

			FlxG._CurrentCamera.DrawFX() 'not realy draw. Only calculation
			FlxG._CurrentCamera.Lock()
			_state.Draw()
			FlxG.DrawPlugins()
			FlxG._CurrentCamera.Unlock()

			i+=1
		Wend

		#If TARGET <> "ios" Or TARGET <> "android"
			If (_soundTrayVisible) Then
				Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
				If (FlxG.Mute) globalVolume = 0

				Local bx:Int = 20
				Local by:Int = 28

				If (FlxG._LastDrawingColor <> FlxG.WHITE) Then
					SetColor(255, 255, 255)
					FlxG._LastDrawingColor = FlxG.WHITE
				End If

				PushMatrix()
				Translate(_soundTrayX, _soundTrayY)

				Local i:Int = 0
				While (i < 10)
					If (i < globalVolume) Then
						If (FlxG._LastDrawingAlpha <> 1) Then
							SetAlpha(1)
							FlxG._LastDrawingAlpha = 1
						End If

					Else
						If (FlxG._LastDrawingAlpha <> .5) Then
							SetAlpha(.5)
							FlxG._LastDrawingAlpha = .5
						End If
					End If

					DrawRect(bx, by, 8, i * 2)

					bx += 12
					by -= 2
					i += 1
				Wend

				_soundTrayLabel.Draw()

				PopMatrix()
			End If
		#End

		FlxG.Mouse.Draw()

		#If CONFIG = "debug"
			SetColor(255, 255, 255)
			DrawText("FPS: " + _rendersCounter.FPS, 10, 10)
		#End

		Return 0
	End Method

	Method OnSuspend:Int()
		ShowMouse()
		FlxG.PauseSounds()
		Return 0
	End Method

	Method OnResume:Int()
		If (Not _debuggerUp And useSystemCursor) Then
			HideMouse()
		End If
		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnContentInit:Void()
	End Method

Private
	Method _ShowSoundTray:Void(silent:Bool = False)
		If (Not silent) Then
			FlxG.Play(FlxG.DATA_PREFIX + "beep")
		End If

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()

		Local timeManager:TimerManager = FlxTimer.Manager()
		If (timeManager <> Null) timeManager.Clear()

		If (_state <> Null) _state.Destroy()

		_state = _requestedState
		_state.Create()
	End Method

	Method _Step:Void()
		#If TARGET <> "ios" Or TARGET <> "android"
			If (useSoundHotKeys) Then
				If (KeyHit(KEY_0)) Then
					FlxG.Mute = Not FlxG.Mute

					If (FlxG.VolumeHandler <> Null) Then
						If (FlxG.Mute) Then
							FlxG.VolumeHandler.OnVolumeChange(0)
						Else
							FlxG.VolumeHandler.OnVolumeChange(FlxG.Volume())
						End If
					End If

					_ShowSoundTray()
				End If

				If (KeyHit(KEY_MINUS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() - .1)
					_ShowSoundTray()
				End If

				If (KeyHit(KEY_EQUALS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() + .1)
					_ShowSoundTray()
				End If
			End If

			_UpdateSoundTray()
		#End

		If (_requestedReset) Then
			_requestedReset = False
			_requestedState = FlxState(_iState.CreateInstance())
			_replayTimer = 0
			_replayCancelKeys = []
			_Reset()
			FlxG.Reset()
		End If

		If (_recordingRequested) Then
			_recordingRequested = False
			_replay.Create(FlxG.GlobalSeed)
			_recording = True

			If (_debugger <> Null) Then
				'TODO
				FlxG.Log("FLIXEL: starting new flixel gameplay record.")
			End If

		ElseIf (_replayRequested)
			_replayRequested = False
			_replay.Rewind()
			FlxG.GlobalSeed = _replay.seed

			If (_debugger <> Null) Then
				'TODO
			End If

			_replaying = True
		End If

		If (_state <> _requestedState) _SwitchState()

		FlxBasic._ActiveCount = 0

		If (_replaying) Then
			If (_replayCancelKeys.Length() > 0 And Not KeyDown(192) And Not KeyDown(220)) Then
				Local i:Int = 0
				Local l:Int = _replayCancelKeys.Length()

				While (i < l)
					If (KeyDown(_replayCancelKeys[i])) Then
						If (_replayCallback <> Null) Then
							_replayCallback.OnReplayComplete()
							_replayCallback = Null
						Else
							FlxG.StopReplay()
						End If

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

				If (_replayTimer <= 0) Then
					If (_replayCallback <> Null) Then
						_replayCallback.OnReplayComplete()
						_replayCallback = Null
					Else
						FlxG.StopReplay()
					End If
				End If
			End If

			If (_replaying And _replay.finished) Then
				FlxG.StopReplay()

				If (_replayCallback <> Null) Then
					_replayCallback.OnReplayComplete()
					_replayCallback = Null
				End If
			End If

			If (_debugger <> Null) Then
				'TODO
			End If
		Else
			FlxG.UpdateInput()
		End If

		If (_recording) Then
			_replay.RecordFrame()

			If (_debugger <> Null) Then
				'TODO
			End If
		End If

		_Update()

		If (_debugger <> Null) Then
			'TODO
		End If
	End Method

	Method _UpdateSoundTray:Void()
		If (Not _soundTrayVisible) Return

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= FlxG.Elapsed

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (FlxG.Elapsed * FlxG.Height * 2)

			If (_soundTrayY <= -_soundTrayHeight) Then
				_soundTrayVisible = False

				'TODO Save sound settings
			End If
		End If
	End Method

	Method _Update:Void()
		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.Update()
		FlxG.UpdateCameras()
	End Method

	Method _Reset:Void()
		SetUpdateRate(FlxG.Framerate)
		Seed = SystemMillisecs()

		FlxG.DeviceWidth = DeviceWidth()
		FlxG.DeviceHeight = DeviceHeight()

		If (useVirtualResolution) Then
			FlxG._DeviceScaleFactorX = FlxG.DeviceWidth / Float(FlxG.Width)
			FlxG._DeviceScaleFactorY = FlxG.DeviceHeight / Float(FlxG.Height)
		Else
			FlxG._DeviceScaleFactorX = 1
			FlxG._DeviceScaleFactorY = 1
		End If

		_step = 1000.0 / FlxG.Framerate

		_updatesCounter.Reset()
		_rendersCounter.Reset()
		_updatesLoopUsed = False
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

		Local minSystemFontSize:Int = 8
		Local maxSystemFontSize:Int = 24
		Local fontPathPrefix:String = FlxG.DATA_PREFIX + FlxText.SYSTEM_FONT + "_font_"

		Local system:FlxFont = 	FlxAssetsManager.AddFont(FlxText.SYSTEM_FONT)

		For Local size:Int = minSystemFontSize To maxSystemFontSize
			system.SetPath(size, fontPathPrefix + Min(size, 17) + ".png")
		Next

		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "default", FlxG.DATA_PREFIX + "default.png")
		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "button", FlxG.DATA_PREFIX + "button.png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES, FlxTilemap.AUTOTILES + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES_ALT, FlxTilemap.AUTOTILES_ALT + ".png")
		FlxAssetsManager.AddCursor(FlxG.DATA_PREFIX + "cursor", FlxG.DATA_PREFIX + "cursor.png")
		FlxAssetsManager.AddSound(FlxG.DATA_PREFIX + "beep", FlxG.DATA_PREFIX + "beep.mp3")

		Self.OnContentInit()
	End Method
End Class

Private
Class FlxFPSCounter

	Field FPS:Int

Private
	Field _FPSCounter:Int

	Field _lastFPSCounter:Int

	Field _lastUpdateTime:Int

Public
	Method New()
		Reset()
	End Method

	Method Update:Void()
		If (FPS < 0) Then
			_lastUpdateTime = Millisecs()
			FPS = FlxG.Framerate
			_lastFPSCounter = FPS
		Else
			If (Millisecs() - _lastUpdateTime > 1000) Then
				If (Abs(_lastFPSCounter - _FPSCounter) < 10) Then
					FPS = _FPSCounter
				End If

				_lastFPSCounter = _FPSCounter
				_FPSCounter = 0
				_lastUpdateTime = Millisecs()
			Else
				_FPSCounter += 1
			End If
		End If
	End Method

	Method Reset:Void()
		FPS = -1
		_FPSCounter = 0
		_lastFPSCounter = 0
		_lastUpdateTime = 0
	End Method

End Class

Strict

Import mojo

Import flxextern
Import flxbasic
Import flxstate
Import flxcamera
Import flxtimer
Import flxtext
Import flxg
Import flxu
Import flxtilemap
Import system.flxassetsmanager
Import system.flxfont
Import system.flxdebugger
Import system.flxreplay
Import plugin.timermanager

Import "data/flx_beep.mp3"

'#HTML5_SUSPEND_ON_BLUR_ENABLED = "true"

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field useVirtualResolution:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Int

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:FlxClass

	Field _created:Bool

	Field _lostFocus:Bool

	Field _step:Int

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _updatesCounter:FlxFPSCounter

	Field _rendersCounter:FlxFPSCounter

	Field _updatesLoopUsed:Bool

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:FlxClass, zoom:Float = 1, framerate:Int = 60, useSystemCursor:Bool = False)
		_lostFocus = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Framerate = framerate

		useSoundHotKeys = Not IsMobile()
		Self.useSystemCursor = useSystemCursor
		useVirtualResolution = True
		If (Not useSystemCursor) HideMouse()
		_debuggerUp = False

		_state = Null

		_replay = New FlxReplay()
		_replayRequested = False
		_recordingRequested = False
		_replaying = False
		_recording = False

		_iState = initialState
		_requestedState = Null
		_requestedReset = True
		_created = False

		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 60
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False

		_updatesCounter = New FlxFPSCounter()
		_rendersCounter = New FlxFPSCounter()
	End Method

	Method OnCreate:Int()
		_Reset()
		_InitData()
		_Step()

		_soundTrayX	= (FlxG.Width / 2) * FlxCamera.DefaultZoom - (_soundTrayWidth / 2)
		_soundTrayLabel = New FlxText(10, 32, _soundTrayWidth, "VOLUME")
		_soundTrayLabel.SetFormat(FlxText.SYSTEM_FONT, 16, FlxG.WHITE, FlxText.ALIGN_CENTER)
		Return 0
	End Method

	Method OnUpdate:Int()
		If (_rendersCounter.FPS >= 0 And _rendersCounter.FPS < FlxG.Framerate - 10) Then
			_updatesCounter.Update()

			'Real elapsed time very unstable in Monkey. TODO!
			FlxG.Elapsed = FlxG.TimeScale * (1.0 / _updatesCounter.FPS)
			_Step()

			_updatesLoopUsed = True
		Else
			_updatesLoopUsed = False
		End If
		Return 0
	End Method

	Method OnRender:Int()
		_rendersCounter.Update()

		If (Not _updatesLoopUsed) Then
			'Real elapsed time very unstable in Monkey. TODO!
			FlxG.Elapsed = FlxG.TimeScale * (1.0 / _rendersCounter.FPS)
			_Step()
		End If

		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

		FlxG._LastDrawingColor = FlxG.WHITE
		FlxG._LastDrawingBlend = GetBlend()
		FlxG._LastDrawingAlpha = GetAlpha()
		FlxG._CurrentCamera = Null

		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG._CurrentCamera = FlxG.Cameras.Get(i)

			If (Not FlxG._CurrentCamera.active) Then
				i+=1
				Continue
			End If

			FlxG._CurrentCameraID = i

			If (FlxG._CurrentCamera = Null Or Not FlxG._CurrentCamera.exists Or Not FlxG._CurrentCamera.visible) Continue

			FlxG._CurrentCamera.DrawFX() 'not realy draw. Only calculation
			FlxG._CurrentCamera.Lock()
			_state.Draw()
			FlxG.DrawPlugins()
			FlxG._CurrentCamera.Unlock()

			i+=1
		Wend

		#If TARGET <> "ios" Or TARGET <> "android"
			If (_soundTrayVisible) Then
				Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
				If (FlxG.Mute) globalVolume = 0

				Local bx:Int = 20
				Local by:Int = 28

				If (FlxG._LastDrawingColor <> FlxG.WHITE) Then
					SetColor(255, 255, 255)
					FlxG._LastDrawingColor = FlxG.WHITE
				End If

				PushMatrix()
				Translate(_soundTrayX, _soundTrayY)

				Local i:Int = 0
				While (i < 10)
					If (i < globalVolume) Then
						If (FlxG._LastDrawingAlpha <> 1) Then
							SetAlpha(1)
							FlxG._LastDrawingAlpha = 1
						End If

					Else
						If (FlxG._LastDrawingAlpha <> .5) Then
							SetAlpha(.5)
							FlxG._LastDrawingAlpha = .5
						End If
					End If

					DrawRect(bx, by, 8, i * 2)

					bx += 12
					by -= 2
					i += 1
				Wend

				_soundTrayLabel.Draw()

				PopMatrix()
			End If
		#End

		FlxG.Mouse.Draw()

		#If CONFIG = "debug"
			SetColor(255, 255, 255)
			DrawText("FPS: " + _rendersCounter.FPS, 10, 10)
		#End

		Return 0
	End Method

	Method OnSuspend:Int()
		ShowMouse()
		FlxG.PauseSounds()
		Return 0
	End Method

	Method OnResume:Int()
		If (Not _debuggerUp And useSystemCursor) Then
			HideMouse()
		End If
		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnContentInit:Void()
	End Method

Private
	Method _ShowSoundTray:Void(silent:Bool = False)
		If (Not silent) Then
			FlxG.Play(FlxG.DATA_PREFIX + "beep")
		End If

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()

		Local timeManager:TimerManager = FlxTimer.Manager()
		If (timeManager <> Null) timeManager.Clear()

		If (_state <> Null) _state.Destroy()

		_state = _requestedState
		_state.Create()
	End Method

	Method _Step:Void()
		#If TARGET <> "ios" Or TARGET <> "android"
			If (useSoundHotKeys) Then
				If (KeyHit(KEY_0)) Then
					FlxG.Mute = Not FlxG.Mute

					If (FlxG.VolumeHandler <> Null) Then
						If (FlxG.Mute) Then
							FlxG.VolumeHandler.OnVolumeChange(0)
						Else
							FlxG.VolumeHandler.OnVolumeChange(FlxG.Volume())
						End If
					End If

					_ShowSoundTray()
				End If

				If (KeyHit(KEY_MINUS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() - .1)
					_ShowSoundTray()
				End If

				If (KeyHit(KEY_EQUALS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() + .1)
					_ShowSoundTray()
				End If
			End If

			_UpdateSoundTray()
		#End

		If (_requestedReset) Then
			_requestedReset = False
			_requestedState = FlxState(_iState.CreateInstance())
			_replayTimer = 0
			_replayCancelKeys = []
			_Reset()
			FlxG.Reset()
		End If

		If (_recordingRequested) Then
			_recordingRequested = False
			_replay.Create(FlxG.GlobalSeed)
			_recording = True

			If (_debugger <> Null) Then
				'TODO
				FlxG.Log("FLIXEL: starting new flixel gameplay record.")
			End If

		ElseIf (_replayRequested)
			_replayRequested = False
			_replay.Rewind()
			FlxG.GlobalSeed = _replay.seed

			If (_debugger <> Null) Then
				'TODO
			End If

			_replaying = True
		End If

		If (_state <> _requestedState) _SwitchState()

		FlxBasic._ActiveCount = 0

		If (_replaying) Then
			If (_replayCancelKeys.Length() > 0 And Not KeyDown(192) And Not KeyDown(220)) Then
				Local i:Int = 0
				Local l:Int = _replayCancelKeys.Length()

				While (i < l)
					If (KeyDown(_replayCancelKeys[i])) Then
						If (_replayCallback <> Null) Then
							_replayCallback.OnReplayComplete()
							_replayCallback = Null
						Else
							FlxG.StopReplay()
						End If

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

				If (_replayTimer <= 0) Then
					If (_replayCallback <> Null) Then
						_replayCallback.OnReplayComplete()
						_replayCallback = Null
					Else
						FlxG.StopReplay()
					End If
				End If
			End If

			If (_replaying And _replay.finished) Then
				FlxG.StopReplay()

				If (_replayCallback <> Null) Then
					_replayCallback.OnReplayComplete()
					_replayCallback = Null
				End If
			End If

			If (_debugger <> Null) Then
				'TODO
			End If
		Else
			FlxG.UpdateInput()
		End If

		If (_recording) Then
			_replay.RecordFrame()

			If (_debugger <> Null) Then
				'TODO
			End If
		End If

		_Update()

		If (_debugger <> Null) Then
			'TODO
		End If
	End Method

	Method _UpdateSoundTray:Void()
		If (Not _soundTrayVisible) Return

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= FlxG.Elapsed

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (FlxG.Elapsed * FlxG.Height * 2)

			If (_soundTrayY <= -_soundTrayHeight) Then
				_soundTrayVisible = False

				'TODO Save sound settings
			End If
		End If
	End Method

	Method _Update:Void()
		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.Update()
		FlxG.UpdateCameras()
	End Method

	Method _Reset:Void()
		SetUpdateRate(FlxG.Framerate)
		Seed = SystemMillisecs()

		FlxG.DeviceWidth = DeviceWidth()
		FlxG.DeviceHeight = DeviceHeight()

		If (useVirtualResolution) Then
			FlxG._DeviceScaleFactorX = FlxG.DeviceWidth / Float(FlxG.Width)
			FlxG._DeviceScaleFactorY = FlxG.DeviceHeight / Float(FlxG.Height)
		Else
			FlxG._DeviceScaleFactorX = 1
			FlxG._DeviceScaleFactorY = 1
		End If

		_step = 1000.0 / FlxG.Framerate

		_updatesCounter.Reset()
		_rendersCounter.Reset()
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

		Local minSystemFontSize:Int = 8
		Local maxSystemFontSize:Int = 24
		Local fontPathPrefix:String = FlxG.DATA_PREFIX + FlxText.SYSTEM_FONT + "_font_"

		Local system:FlxFont = 	FlxAssetsManager.AddFont(FlxText.SYSTEM_FONT)

		For Local size:Int = minSystemFontSize To maxSystemFontSize
			system.SetPath(size, fontPathPrefix + Min(size, 17) + ".png")
		Next

		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "default", FlxG.DATA_PREFIX + "default.png")
		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "button", FlxG.DATA_PREFIX + "button.png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES, FlxTilemap.AUTOTILES + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES_ALT, FlxTilemap.AUTOTILES_ALT + ".png")
		FlxAssetsManager.AddCursor(FlxG.DATA_PREFIX + "cursor", FlxG.DATA_PREFIX + "cursor.png")
		FlxAssetsManager.AddSound(FlxG.DATA_PREFIX + "beep", FlxG.DATA_PREFIX + "beep.mp3")

		Self.OnContentInit()
	End Method
End Class

Private
Class FlxFPSCounter

	Field FPS:Int

Private
	Field _FPSCounter:Int

	Field _lastFPSCounter:Int

	Field _lastUpdateTime:Int

Public
	Method New()
		Reset()
	End Method

	Method Update:Void()
		If (FPS < 0) Then
			_lastUpdateTime = Millisecs()
			FPS = FlxG.Framerate
			_lastFPSCounter = FPS
		Else
			If (Millisecs() - _lastUpdateTime > 1000) Then
				If (Abs(_lastFPSCounter - _FPSCounter) < 10) Then
					FPS = _FPSCounter
				End If

				_lastFPSCounter = _FPSCounter
				_FPSCounter = 0
				_lastUpdateTime = Millisecs()
			Else
				_FPSCounter += 1
			End If
		End If
	End Method

	Method Reset:Void()
		FPS = -1
		_FPSCounter = 0
		_lastFPSCounter = 0
		_lastUpdateTime = 0
	End Method

End Class


Fixed hide of system cursor on app startup

Strict

Import mojo
Import reflection

Import flxextern
Import flxbasic
Import flxstate
Import flxcamera
Import flxtimer
Import flxtext
Import flxg
Import flxu
Import flxtilemap
Import system.flxassetsmanager
Import system.flxfont
Import system.flxdebugger
Import system.flxreplay
Import plugin.timermanager

#If  FLX_SOUND_EXTENSION = "unknown"

	Import "data/beep_flx.wav"
	Import "data/beep_flx.ogg"
	Import "data/beep_flx.mp3"

#Else

	Import "data/beep_flx.${FLX_SOUND_EXTENSION}"

#End

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Float

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:ClassInfo

	Field _step:Int

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _updaterate:Int

	Field _switchStateListener:FlxSwitchStateListener

	'note: BUG: It seems we have bug in HTML5 vesion fo mojo
#If TARGET = "html5" And FLX_WEBGL_ENABLED = "0"

	Field _stateIsReady:Bool

#End

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:ClassInfo, zoom:Float = 1, updaterate:Int = 60, useSystemCursor:Bool = False)
		Local classObject:GlobalInfo

		For Local classInfo:ClassInfo = EachIn GetClasses()
			classObject = classInfo.GetGlobal("__CLASS__", False)

			If (classObject <> Null) Then
				classObject.SetValue(classInfo)
			End If
		Next

		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 45
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Updaterate = updaterate

		_state = Null

		useSoundHotKeys = Not FlxG.Mobile
		Self.useSystemCursor = useSystemCursor

		forceDebugger = False
		_debuggerUp = False

		_replay = New FlxReplay()
		_replayRequested = False
		_recordingRequested = False
		_replaying = False
		_recording = False

		_iState = initialState
		_requestedState = Null
		_requestedReset = True
	End Method

	Method OnCreate:Int()
		If ( Not useSystemCursor) HideMouse()
		_InitData()
		_Reset()

		#Rem
		_soundTrayLabel = New FlxText(10, 32, _soundTrayWidth, "VOLUME")
		_soundTrayLabel.SetFormat(FlxText.SYSTEM_FONT, 16, FlxG.WHITE, FlxText.ALIGN_CENTER)
		#End
		Return 0
	End Method

	Method OnUpdate:Int()
		If (FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

	#If FLX_ASYNC_EVENTS_ENABLED = "1"
		UpdateAsyncEvents()
	#End

		FlxG.UpdateDevice()
		_Step()

	#If TARGET <> "ios" And TARGET <> "android" And TARGET <> "psm"
		If (useSoundHotKeys) Then
			If (KeyHit(KEY_0)) Then
				FlxG.Mute = Not FlxG.Mute

				If (FlxG.VolumeHandler <> Null) Then
					If (FlxG.Mute) Then
						FlxG.VolumeHandler.OnVolumeChange(0)
					Else
						FlxG.VolumeHandler.OnVolumeChange(FlxG.Volume())
					End If
				End If

				_ShowSoundTray()
			End If

			If (KeyHit(KEY_MINUS)) Then
				FlxG.Mute = False
				FlxG.Volume(FlxG.Volume() - .1)
				_ShowSoundTray()
			End If

			If (KeyHit(KEY_EQUALS)) Then
				FlxG.Mute = False
				FlxG.Volume(FlxG.Volume() + .1)
				_ShowSoundTray()
			End If
		End If

		_UpdateSoundTray(_step)
	#End

		Return 0
	End Method

	Method OnRender:Int()
	#If FLX_DEBUG_ENABLED = "1"
		FlxBasic._VisibleCount = 0
	#End

	#If TARGET = "html5" And FLX_WEBGL_ENABLED = "0"

		If ( Not _stateIsReady) Then
			Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
			_state.Create()
			_stateIsReady = True
			Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)

			Return 0
		End If

	#End
		_Draw()
		Return 0
	End Method

	Method OnSuspend:Int()
		ShowMouse()
		FlxG.PauseSounds()
		Return 0
	End Method

	Method OnResume:Int()
	#If FLX_DEBUG_ENABLED = "1"
		If (Not _debuggerUp And Not useSystemCursor) Then
			HideMouse()
		End If
	#Else
		If ( Not useSystemCursor) Then
			HideMouse()
		End If
	#End

		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnBack:Int()
		If (_state = Null Or _state.DoBack()) Then
			Return Super.OnBack()
		End If

		Return 0
	End Method

	Method OnClose:Int()
		If (_state = Null Or _state.DoClose()) Then
			Return Super.OnClose()
		End If

		Return 0
	End Method

	Method SetSwitchStateListener:Void(listener:FlxSwitchStateListener)
		_switchStateListener = listener
	End Method

	Method OnContentInit:Void()
	End Method

Private
	Method _ShowSoundTray:Void(silent:Bool = False)
		If (Not silent) Then
			FlxG.Play("beep" + FlxG.DATA_SUFFIX)
		End If

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()
		FlxG.ResetInput()
		FlxG.DestroySounds()

	#If FLX_DEBUG_ENABLED = "1"
		If (_debugger <> Null) Then
			'note: TODO:!
		End If
	#End

		Local timeManager:TimerManager = FlxTimer.Manager()
		If (timeManager <> Null) timeManager.Clear()

		If (_state <> Null) _state.Destroy()
		If (_switchStateListener <> Null) _switchStateListener.OnSwitchState(_state, _requestedState)

		_state = _requestedState

	#If TARGET = "html5" And FLX_WEBGL_ENABLED = "0"

		_stateIsReady = False

	#Else

		BeginRender()
			Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
			_state.Create()
			Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
		EndRender()

	#End

		If (FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If
	End Method

	Method _Step:Void()
		If (_requestedReset) Then
			_Reset()
		End If

		If (_recordingRequested) Then
			_recordingRequested = False
			_replay.Create(FlxG.GlobalSeed)
			_recording = True

		#If FLX_DEBUG_ENABLED = "1"
			If (_debugger <> Null) Then
				'note: TODO:
				FlxG.Log("FLIXEL: starting new flixel gameplay record.")
			End If
		#End

		ElseIf (_replayRequested)
			_replayRequested = False
			_replay.Rewind()
			FlxG.GlobalSeed = _replay.seed

		#If FLX_DEBUG_ENABLED = "1"
			If (_debugger <> Null) Then
				'note: TODO:
			End If
		#End

			_replaying = True
		End If

	#If TARGET = "html5" And FLX_WEBGL_ENABLED = "0"

		If (_state <> _requestedState) Then
			_SwitchState()
			Return
		End If

		If ( Not _stateIsReady) Return

	#Else

		If (_state <> _requestedState) _SwitchState()

	#end

	#If FLX_DEBUG_ENABLED = "1"
		FlxBasic._ActiveCount = 0
	#End

		If (_replaying) Then
			If (_replayCancelKeys.Length() > 0 And Not KeyDown(192) And Not KeyDown(220)) Then
				Local i:Int = 0
				Local l:Int = _replayCancelKeys.Length()

				While (i < l)
					If (KeyDown(_replayCancelKeys[i])) Then
						If (_replayCallback <> Null) Then
							_replayCallback.OnReplayComplete()
							_replayCallback = Null
						Else
							FlxG.StopReplay()
						End If

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

				If (_replayTimer <= 0) Then
					If (_replayCallback <> Null) Then
						_replayCallback.OnReplayComplete()
						_replayCallback = Null
					Else
						FlxG.StopReplay()
					End If
				End If
			End If

			If (_replaying And _replay.finished) Then
				FlxG.StopReplay()

				If (_replayCallback <> Null) Then
					_replayCallback.OnReplayComplete()
					_replayCallback = Null
				End If
			End If

		#If FLX_DEBUG_ENABLED = "1"
			If (_debugger <> Null) Then
				'note: TODO:
			End If
		#End

		Else
			FlxG.UpdateInput()
		End If

		If (_recording) Then
			_replay.RecordFrame()

		#If FLX_DEBUG_ENABLED = "1"
			If (_debugger <> Null) Then
				'note: TODO:
			End If
		#End

		End If

		_Update()

	#If FLX_DEBUG_ENABLED = "1"
		If (_debugger <> Null) Then
			'note: TODO:
		End If
	#End
	End Method

	Method _Update:Void()
		FlxG.Elapsed = FlxG.TimeScale * (_step / 1000.0)

		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.DoUpdate()

		If (FlxG.Tweener.active And FlxG.Tweener.HasTween) Then
			FlxG.Tweener.UpdateTweens()
		End If

		FlxG.UpdateCameras()

	#If FLX_DEBUG_ENABLED = "1"
		If (_debuggerUp) Then
			'note: TODO:!
		End If
	#End
	End Method

	Method _UpdateSoundTray:Void(ms:Int)
		If (Not _soundTrayVisible) Return

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= ms / 1000.0

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (ms / 1000.0 * FlxG.Height * 2)

			If (_soundTrayY <= -_soundTrayHeight) Then
				_soundTrayVisible = False

				'note: TODO: Save sound settings
			End If
		End If
	End Method

	Method _Draw:Void()
		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)

	#If TARGET <> "ios" And TARGET <> "android" And TARGET <> "psm" And TARGET <> "win8"
		If( Not FlxG.Mobile) Then
			PushMatrix()
		End If
	#End

		Translate(FlxG._DeviceOffsetX, FlxG._DeviceOffsetY)
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

		FlxG._LastDrawingColor = FlxG.WHITE
		FlxG._LastDrawingBlend = GetBlend()
		FlxG._LastDrawingAlpha = GetAlpha()
		FlxG._CurrentCamera = Null

		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG._CurrentCamera = FlxG.Cameras.Get(i)

			If (FlxG._CurrentCamera <> Null And FlxG._CurrentCamera.active And FlxG._CurrentCamera.exists And FlxG._CurrentCamera.visible) Then
				FlxG._CurrentCamera.DrawFX() 'not really draw. Only calculation
				FlxG._CurrentCamera.Lock()
				_state.DoDraw()
				FlxG.DrawPlugins()
				FlxG._CurrentCamera.Unlock()
			End If

			i+=1
		Wend

	#If TARGET <> "ios" And TARGET <> "android" And TARGET <> "psm" And TARGET <> "win8"
		If( Not FlxG.Mobile) Then
			PopMatrix()
			_DrawSoundTray()
			FlxG.Mouse.Draw()
		End If
	#End
	End Method

	Method _DrawSoundTray:Void()
		If (_soundTrayVisible) Then
			Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
			If (FlxG.Mute) globalVolume = 0

			PushMatrix()

			Transform(FlxG._DeviceScaleFactorX, 0, 0, FlxG._DeviceScaleFactorY, ( (FlxG.DeviceWidth - _soundTrayWidth * FlxG._DeviceScaleFactorX) * 0.5), _soundTrayY)

			If (FlxG._LastDrawingAlpha <> .5) Then
				SetAlpha(.5)
				FlxG._LastDrawingAlpha = .5
			End If

			If (FlxG._LastDrawingColor <> FlxG.BLACK) Then
				SetColor(0, 0, 0)
			End If

			DrawRect(0, 0, _soundTrayWidth, _soundTrayHeight)

			SetColor(255, 255, 255)
			FlxG._LastDrawingColor = FlxG.WHITE

			Local bx:Int = 20
			Local by:Int = 28

			Local i:Int = 0
			While (i < 10)
				If (i < globalVolume) Then
					If (FlxG._LastDrawingAlpha <> 1) Then
						SetAlpha(1)
						FlxG._LastDrawingAlpha = 1
					End If

				Else
					If (FlxG._LastDrawingAlpha <> .5) Then
						SetAlpha(.5)
						FlxG._LastDrawingAlpha = .5
					End If
				End If

				DrawRect(bx, by, 8, i * 2)

				bx += 12
				by -= 2
				i += 1
			Wend

			'_soundTrayLabel.Draw()

			PopMatrix()
		End If
	End Method

	Method _Reset:Void()
		_requestedReset = False
		_requestedState = FlxState(_iState.NewInstance())
		_replayTimer = 0
		_replayCancelKeys =[]

		If (FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Local date:Int[] = GetDate()

		Seed = (date[3] * 3600 + date[4] * 60 + date[5]) * 1000 + date[6]
		FlxG.UpdateDevice()

		FlxG.Reset()
	End Method

	Method _ResetFramerate:Void()
		SetUpdateRate(FlxG.Updaterate)
		_step = 1000 / FlxG.Updaterate
		_updaterate = FlxG.Updaterate
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

		Local minSystemFontSize:Int = 8
		Local maxSystemFontSize:Int = 24
		Local fontPathPrefix:String = FlxText.SYSTEM_FONT + "_font_"

		Local system:FlxFont = 	FlxAssetsManager.AddFont(FlxText.SYSTEM_FONT)

		For Local size:Int = minSystemFontSize To maxSystemFontSize
			system.SetPath(size, fontPathPrefix + size + FlxG.DATA_SUFFIX)
		Next

		FlxAssetsManager.AddImage("default" + FlxG.DATA_SUFFIX, "default" +  FlxG.DATA_SUFFIX + ".png")
		FlxAssetsManager.AddImage("button" + FlxG.DATA_SUFFIX, "button" + FlxG.DATA_SUFFIX + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES, FlxTilemap.AUTOTILES + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES_ALT, FlxTilemap.AUTOTILES_ALT + ".png")
		FlxAssetsManager.AddCursor("cursor" + FlxG.DATA_SUFFIX, "cursor" + FlxG.DATA_SUFFIX + ".png")

		FlxAssetsManager.AddSound("beep" + FlxG.DATA_SUFFIX, "beep" + FlxG.DATA_SUFFIX + "." + FlxSound.GetValidExt())

		Local contentInitTrigger:FunctionInfo

		For Local classInfo:ClassInfo = EachIn GetClasses()
			contentInitTrigger = classInfo.GetFunction("OnContentInit",[], False)
			If (contentInitTrigger <> Null) contentInitTrigger.Invoke([])
		Next

		Self.OnContentInit()
	End Method
End Class

Strict

Import mojo
Import reflection

Import flxextern
Import flxbasic
Import flxstate
Import flxcamera
Import flxtimer
Import flxtext
Import flxg
Import flxu
Import flxtilemap
Import system.flxassetsmanager
Import system.flxfont
Import system.flxdebugger
Import system.flxreplay
Import plugin.timermanager

#If  FLX_SOUND_EXTENSION = "unknown"

	Import "data/beep_flx.wav"
	Import "data/beep_flx.ogg"
	Import "data/beep_flx.mp3"

#Else

	Import "data/beep_flx.${FLX_SOUND_EXTENSION}"

#End

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Float

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:ClassInfo

	Field _step:Int

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _updaterate:Int

	Field _switchStateListener:FlxSwitchStateListener

	'note: BUG: It seems we have bug in HTML5 vesion fo mojo
#If TARGET = "html5" And FLX_WEBGL_ENABLED = "0"

	Field _stateIsReady:Bool

#End

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:ClassInfo, zoom:Float = 1, updaterate:Int = 60, useSystemCursor:Bool = False)
		Local classObject:GlobalInfo

		For Local classInfo:ClassInfo = EachIn GetClasses()
			classObject = classInfo.GetGlobal("__CLASS__", False)

			If (classObject <> Null) Then
				classObject.SetValue(classInfo)
			End If
		Next

		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 45
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Updaterate = updaterate

		_state = Null

		useSoundHotKeys = Not FlxG.Mobile
		Self.useSystemCursor = useSystemCursor

		If (Not useSystemCursor) HideMouse()

		forceDebugger = False
		_debuggerUp = False

		_replay = New FlxReplay()
		_replayRequested = False
		_recordingRequested = False
		_replaying = False
		_recording = False

		_iState = initialState
		_requestedState = Null
		_requestedReset = True
	End Method

	Method OnCreate:Int()
		_InitData()
		_Reset()

		#Rem
		_soundTrayLabel = New FlxText(10, 32, _soundTrayWidth, "VOLUME")
		_soundTrayLabel.SetFormat(FlxText.SYSTEM_FONT, 16, FlxG.WHITE, FlxText.ALIGN_CENTER)
		#End
		Return 0
	End Method

	Method OnUpdate:Int()
		If (FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

	#If FLX_ASYNC_EVENTS_ENABLED = "1"
		UpdateAsyncEvents()
	#End

		FlxG.UpdateDevice()
		_Step()

	#If TARGET <> "ios" And TARGET <> "android" And TARGET <> "psm"
		If (useSoundHotKeys) Then
			If (KeyHit(KEY_0)) Then
				FlxG.Mute = Not FlxG.Mute

				If (FlxG.VolumeHandler <> Null) Then
					If (FlxG.Mute) Then
						FlxG.VolumeHandler.OnVolumeChange(0)
					Else
						FlxG.VolumeHandler.OnVolumeChange(FlxG.Volume())
					End If
				End If

				_ShowSoundTray()
			End If

			If (KeyHit(KEY_MINUS)) Then
				FlxG.Mute = False
				FlxG.Volume(FlxG.Volume() - .1)
				_ShowSoundTray()
			End If

			If (KeyHit(KEY_EQUALS)) Then
				FlxG.Mute = False
				FlxG.Volume(FlxG.Volume() + .1)
				_ShowSoundTray()
			End If
		End If

		_UpdateSoundTray(_step)
	#End

		Return 0
	End Method

	Method OnRender:Int()
	#If FLX_DEBUG_ENABLED = "1"
		FlxBasic._VisibleCount = 0
	#End

	#If TARGET = "html5" And FLX_WEBGL_ENABLED = "0"

		If ( Not _stateIsReady) Then
			Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
			_state.Create()
			_stateIsReady = True
			Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)

			Return 0
		End If

	#End
		_Draw()
		Return 0
	End Method

	Method OnSuspend:Int()
		ShowMouse()
		FlxG.PauseSounds()
		Return 0
	End Method

	Method OnResume:Int()
	#If FLX_DEBUG_ENABLED = "1"
		If (Not _debuggerUp And Not useSystemCursor) Then
			HideMouse()
		End If
	#Else
		If ( Not useSystemCursor) Then
			HideMouse()
		End If
	#End

		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnBack:Int()
		If (_state = Null Or _state.DoBack()) Then
			Return Super.OnBack()
		End If

		Return 0
	End Method

	Method OnClose:Int()
		If (_state = Null Or _state.DoClose()) Then
			Return Super.OnClose()
		End If

		Return 0
	End Method

	Method SetSwitchStateListener:Void(listener:FlxSwitchStateListener)
		_switchStateListener = listener
	End Method

	Method OnContentInit:Void()
	End Method

Private
	Method _ShowSoundTray:Void(silent:Bool = False)
		If (Not silent) Then
			FlxG.Play("beep" + FlxG.DATA_SUFFIX)
		End If

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()
		FlxG.ResetInput()
		FlxG.DestroySounds()

	#If FLX_DEBUG_ENABLED = "1"
		If (_debugger <> Null) Then
			'note: TODO:!
		End If
	#End

		Local timeManager:TimerManager = FlxTimer.Manager()
		If (timeManager <> Null) timeManager.Clear()

		If (_state <> Null) _state.Destroy()
		If (_switchStateListener <> Null) _switchStateListener.OnSwitchState(_state, _requestedState)

		_state = _requestedState

	#If TARGET = "html5" And FLX_WEBGL_ENABLED = "0"

		_stateIsReady = False

	#Else

		BeginRender()
			Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
			_state.Create()
			Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
		EndRender()

	#End

		If (FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If
	End Method

	Method _Step:Void()
		If (_requestedReset) Then
			_Reset()
		End If

		If (_recordingRequested) Then
			_recordingRequested = False
			_replay.Create(FlxG.GlobalSeed)
			_recording = True

		#If FLX_DEBUG_ENABLED = "1"
			If (_debugger <> Null) Then
				'note: TODO:
				FlxG.Log("FLIXEL: starting new flixel gameplay record.")
			End If
		#End

		ElseIf (_replayRequested)
			_replayRequested = False
			_replay.Rewind()
			FlxG.GlobalSeed = _replay.seed

		#If FLX_DEBUG_ENABLED = "1"
			If (_debugger <> Null) Then
				'note: TODO:
			End If
		#End

			_replaying = True
		End If

	#If TARGET = "html5" And FLX_WEBGL_ENABLED = "0"

		If (_state <> _requestedState) Then
			_SwitchState()
			Return
		End If

		If ( Not _stateIsReady) Return

	#Else

		If (_state <> _requestedState) _SwitchState()

	#end

	#If FLX_DEBUG_ENABLED = "1"
		FlxBasic._ActiveCount = 0
	#End

		If (_replaying) Then
			If (_replayCancelKeys.Length() > 0 And Not KeyDown(192) And Not KeyDown(220)) Then
				Local i:Int = 0
				Local l:Int = _replayCancelKeys.Length()

				While (i < l)
					If (KeyDown(_replayCancelKeys[i])) Then
						If (_replayCallback <> Null) Then
							_replayCallback.OnReplayComplete()
							_replayCallback = Null
						Else
							FlxG.StopReplay()
						End If

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

				If (_replayTimer <= 0) Then
					If (_replayCallback <> Null) Then
						_replayCallback.OnReplayComplete()
						_replayCallback = Null
					Else
						FlxG.StopReplay()
					End If
				End If
			End If

			If (_replaying And _replay.finished) Then
				FlxG.StopReplay()

				If (_replayCallback <> Null) Then
					_replayCallback.OnReplayComplete()
					_replayCallback = Null
				End If
			End If

		#If FLX_DEBUG_ENABLED = "1"
			If (_debugger <> Null) Then
				'note: TODO:
			End If
		#End

		Else
			FlxG.UpdateInput()
		End If

		If (_recording) Then
			_replay.RecordFrame()

		#If FLX_DEBUG_ENABLED = "1"
			If (_debugger <> Null) Then
				'note: TODO:
			End If
		#End

		End If

		_Update()

	#If FLX_DEBUG_ENABLED = "1"
		If (_debugger <> Null) Then
			'note: TODO:
		End If
	#End
	End Method

	Method _Update:Void()
		FlxG.Elapsed = FlxG.TimeScale * (_step / 1000.0)

		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.DoUpdate()

		If (FlxG.Tweener.active And FlxG.Tweener.HasTween) Then
			FlxG.Tweener.UpdateTweens()
		End If

		FlxG.UpdateCameras()

	#If FLX_DEBUG_ENABLED = "1"
		If (_debuggerUp) Then
			'note: TODO:!
		End If
	#End
	End Method

	Method _UpdateSoundTray:Void(ms:Int)
		If (Not _soundTrayVisible) Return

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= ms / 1000.0

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (ms / 1000.0 * FlxG.Height * 2)

			If (_soundTrayY <= -_soundTrayHeight) Then
				_soundTrayVisible = False

				'note: TODO: Save sound settings
			End If
		End If
	End Method

	Method _Draw:Void()
		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)

	#If TARGET <> "ios" And TARGET <> "android" And TARGET <> "psm" And TARGET <> "win8"
		If( Not FlxG.Mobile) Then
			PushMatrix()
		End If
	#End

		Translate(FlxG._DeviceOffsetX, FlxG._DeviceOffsetY)
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

		FlxG._LastDrawingColor = FlxG.WHITE
		FlxG._LastDrawingBlend = GetBlend()
		FlxG._LastDrawingAlpha = GetAlpha()
		FlxG._CurrentCamera = Null

		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG._CurrentCamera = FlxG.Cameras.Get(i)

			If (FlxG._CurrentCamera <> Null And FlxG._CurrentCamera.active And FlxG._CurrentCamera.exists And FlxG._CurrentCamera.visible) Then
				FlxG._CurrentCamera.DrawFX() 'not really draw. Only calculation
				FlxG._CurrentCamera.Lock()
				_state.DoDraw()
				FlxG.DrawPlugins()
				FlxG._CurrentCamera.Unlock()
			End If

			i+=1
		Wend

	#If TARGET <> "ios" And TARGET <> "android" And TARGET <> "psm" And TARGET <> "win8"
		If( Not FlxG.Mobile) Then
			PopMatrix()
			_DrawSoundTray()
			FlxG.Mouse.Draw()
		End If
	#End
	End Method

	Method _DrawSoundTray:Void()
		If (_soundTrayVisible) Then
			Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
			If (FlxG.Mute) globalVolume = 0

			PushMatrix()

			Transform(FlxG._DeviceScaleFactorX, 0, 0, FlxG._DeviceScaleFactorY, ( (FlxG.DeviceWidth - _soundTrayWidth * FlxG._DeviceScaleFactorX) * 0.5), _soundTrayY)

			If (FlxG._LastDrawingAlpha <> .5) Then
				SetAlpha(.5)
				FlxG._LastDrawingAlpha = .5
			End If

			If (FlxG._LastDrawingColor <> FlxG.BLACK) Then
				SetColor(0, 0, 0)
			End If

			DrawRect(0, 0, _soundTrayWidth, _soundTrayHeight)

			SetColor(255, 255, 255)
			FlxG._LastDrawingColor = FlxG.WHITE

			Local bx:Int = 20
			Local by:Int = 28

			Local i:Int = 0
			While (i < 10)
				If (i < globalVolume) Then
					If (FlxG._LastDrawingAlpha <> 1) Then
						SetAlpha(1)
						FlxG._LastDrawingAlpha = 1
					End If

				Else
					If (FlxG._LastDrawingAlpha <> .5) Then
						SetAlpha(.5)
						FlxG._LastDrawingAlpha = .5
					End If
				End If

				DrawRect(bx, by, 8, i * 2)

				bx += 12
				by -= 2
				i += 1
			Wend

			'_soundTrayLabel.Draw()

			PopMatrix()
		End If
	End Method

	Method _Reset:Void()
		_requestedReset = False
		_requestedState = FlxState(_iState.NewInstance())
		_replayTimer = 0
		_replayCancelKeys =[]

		If (FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Local date:Int[] = GetDate()

		Seed = (date[3] * 3600 + date[4] * 60 + date[5]) * 1000 + date[6]
		FlxG.UpdateDevice()

		FlxG.Reset()
	End Method

	Method _ResetFramerate:Void()
		SetUpdateRate(FlxG.Updaterate)
		_step = 1000 / FlxG.Updaterate
		_updaterate = FlxG.Updaterate
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

		Local minSystemFontSize:Int = 8
		Local maxSystemFontSize:Int = 24
		Local fontPathPrefix:String = FlxText.SYSTEM_FONT + "_font_"

		Local system:FlxFont = 	FlxAssetsManager.AddFont(FlxText.SYSTEM_FONT)

		For Local size:Int = minSystemFontSize To maxSystemFontSize
			system.SetPath(size, fontPathPrefix + size + FlxG.DATA_SUFFIX)
		Next

		FlxAssetsManager.AddImage("default" + FlxG.DATA_SUFFIX, "default" +  FlxG.DATA_SUFFIX + ".png")
		FlxAssetsManager.AddImage("button" + FlxG.DATA_SUFFIX, "button" + FlxG.DATA_SUFFIX + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES, FlxTilemap.AUTOTILES + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES_ALT, FlxTilemap.AUTOTILES_ALT + ".png")
		FlxAssetsManager.AddCursor("cursor" + FlxG.DATA_SUFFIX, "cursor" + FlxG.DATA_SUFFIX + ".png")

		FlxAssetsManager.AddSound("beep" + FlxG.DATA_SUFFIX, "beep" + FlxG.DATA_SUFFIX + "." + FlxSound.GetValidExt())

		Local contentInitTrigger:FunctionInfo

		For Local classInfo:ClassInfo = EachIn GetClasses()
			contentInitTrigger = classInfo.GetFunction("OnContentInit",[], False)
			If (contentInitTrigger <> Null) contentInitTrigger.Invoke([])
		Next

		Self.OnContentInit()
	End Method
End Class


respect the used finger in OnTouchMove and -Up

Strict

Private

Import bono

Public

Class GuiButton Extends GuiBase Implements Touchable, Updateable
    Private

    Global someButtonPressed:Bool
    Field isPressed:Bool
    Field finger:Int
    Field sprite:Sprite

    Public

    Field trackLeavingMoves:Bool

    Method GetSprite:Sprite()
        Return sprite
    End

    Method SetSprite:Void(sprite:Sprite)
        SetColor(sprite.GetColor())
        SetPosition(sprite.GetPosition())
        SetSize(sprite.GetSize())
        Self.sprite = sprite
    End

    Method RemoveSprite:Void()
        If Not sprite Then Return

        Local oldSprite:Sprite = sprite
        sprite = Null

        SetColor(oldSprite.GetColor().Copy())
        SetPosition(oldSprite.GetPosition().Copy())
        SetSize(oldSprite.GetSize().Copy())
    End

    Method SetColor:Void(newColor:Color)
        LockedWithSprite("SetColor")
        Super.SetColor(newColor)
    End

    Method SetPosition:Void(newPos:Vector2D)
        LockedWithSprite("SetPosition")
        Super.SetPosition(newPos)
    End

    Method SetSize:Void(newSize:Vector2D)
        LockedWithSprite("SetSize")
        Super.SetSize(newSize)
    End

    Method OnUpdate:Void(timer:DeltaTimer)
        If sprite Then sprite.OnUpdate(timer)
    End

    Method OnRender:Void()
        If sprite Then sprite.OnRender()
    End

    Method Collide:Bool(pos:Vector2D)
        Local realPos:Vector2D = Director.TranslateSpace(pos)

        If sprite Then Return sprite.Collide(realPos)
        Return Super.Collide(realPos)
    End

    Method OnTouchDown:Void(event:TouchEvent)
        If someButtonPressed Then Return
        If Not Collide(event.pos) Then Return

        someButtonPressed = True
        isPressed = True
        finger = event.finger
        OnButtonDown(event)
    End

    Method OnTouchMove:Void(event:TouchEvent)
        If Not isPressed Then Return
        If Not event.finger = finger Then Return
        If Not trackLeavingMoves And Not Collide(event.pos) Then Return

        OnButtonMove(event)
    End

    Method OnTouchUp:Void(event:TouchEvent)
        If Not isPressed Then Return
        If Not event.finger = finger Then Return

        someButtonPressed = False
        isPressed = False

        If Not Collide(event.pos) Then Return

        OnButtonUp(event)
    End

    Method OnButtonDown:Void(event:TouchEvent)
    End

    Method OnButtonMove:Void(event:TouchEvent)
    End

    Method OnButtonUp:Void(event:TouchEvent)
    End

    Private

    Method LockedWithSprite:Void(name:String)
        If Not sprite Then Return

        Throw New RuntimeException("Button is bound to a sprite so " +
            "please use GetSprite()." + name)
    End
End

Strict

Private

Import bono

Public

Class GuiButton Extends GuiBase Implements Touchable, Updateable
    Private

    Global someButtonPressed:Bool
    Field isPressed:Bool
    Field sprite:Sprite

    Public

    Field trackLeavingMoves:Bool

    Method GetSprite:Sprite()
        Return sprite
    End

    Method SetSprite:Void(sprite:Sprite)
        SetColor(sprite.GetColor())
        SetPosition(sprite.GetPosition())
        SetSize(sprite.GetSize())
        Self.sprite = sprite
    End

    Method RemoveSprite:Void()
        If Not sprite Then Return

        Local oldSprite:Sprite = sprite
        sprite = Null

        SetColor(oldSprite.GetColor().Copy())
        SetPosition(oldSprite.GetPosition().Copy())
        SetSize(oldSprite.GetSize().Copy())
    End

    Method SetColor:Void(newColor:Color)
        LockedWithSprite("SetColor")
        Super.SetColor(newColor)
    End

    Method SetPosition:Void(newPos:Vector2D)
        LockedWithSprite("SetPosition")
        Super.SetPosition(newPos)
    End

    Method SetSize:Void(newSize:Vector2D)
        LockedWithSprite("SetSize")
        Super.SetSize(newSize)
    End

    Method OnUpdate:Void(timer:DeltaTimer)
        If sprite Then sprite.OnUpdate(timer)
    End

    Method OnRender:Void()
        If sprite Then sprite.OnRender()
    End

    Method Collide:Bool(pos:Vector2D)
        Local realPos:Vector2D = Director.TranslateSpace(pos)

        If sprite Then Return sprite.Collide(realPos)
        Return Super.Collide(realPos)
    End

    Method OnTouchDown:Void(event:TouchEvent)
        If someButtonPressed Then Return
        If Not Collide(event.pos) Then Return

        someButtonPressed = True
        isPressed = True
        OnButtonDown(event)
    End

    Method OnTouchMove:Void(event:TouchEvent)
        If Not isPressed Then Return
        If Not trackLeavingMoves And Not Collide(event.pos) Then Return

        OnButtonMove(event)
    End

    Method OnTouchUp:Void(event:TouchEvent)
        If Not isPressed Then Return

        someButtonPressed = False
        isPressed = False

        If Not Collide(event.pos) Then Return

        OnButtonUp(event)
    End

    Method OnButtonDown:Void(event:TouchEvent)
    End

    Method OnButtonMove:Void(event:TouchEvent)
    End

    Method OnButtonUp:Void(event:TouchEvent)
    End

    Private

    Method LockedWithSprite:Void(name:String)
        If Not sprite Then Return

        Throw New RuntimeException("Button is bound to a sprite so " +
            "please use GetSprite()." + name)
    End
End