Bläddra i källkod

Added gridshooter banana.

Mark Sibly 9 år sedan
förälder
incheckning
3307ecca3b
25 ändrade filer med 1246 tillägg och 0 borttagningar
  1. BIN
      modules/mojo/bananas/gridshooter/fonts/classic_sans.ttf
  2. 144 0
      modules/mojo/bananas/gridshooter/fonts/gridshooter.monkey2
  3. 9 0
      modules/mojo/bananas/gridshooter/gamegraphics/README.txt
  4. BIN
      modules/mojo/bananas/gridshooter/gamegraphics/classic_sans.ttf
  5. 106 0
      modules/mojo/bananas/gridshooter/gamegraphics/gamegraphics.monkey2
  6. 9 0
      modules/mojo/bananas/gridshooter/gamegraphics/src/README.txt
  7. 47 0
      modules/mojo/bananas/gridshooter/gamegraphics/src/background.monkey2
  8. 106 0
      modules/mojo/bananas/gridshooter/gamegraphics/src/gamegraphics.monkey2
  9. 116 0
      modules/mojo/bananas/gridshooter/gamegraphics/src/sprite.monkey2
  10. 40 0
      modules/mojo/bananas/gridshooter/gamegraphics/src/tilegraphics.monkey2
  11. 144 0
      modules/mojo/bananas/gridshooter/gridshooter.monkey2
  12. BIN
      modules/mojo/bananas/gridshooter/images/bombExplosion.png
  13. BIN
      modules/mojo/bananas/gridshooter/images/bullet.png
  14. BIN
      modules/mojo/bananas/gridshooter/images/dualbeam.png
  15. BIN
      modules/mojo/bananas/gridshooter/images/enemyBulletBig.png
  16. BIN
      modules/mojo/bananas/gridshooter/images/enemyBulletSmall.png
  17. BIN
      modules/mojo/bananas/gridshooter/images/explosion.png
  18. BIN
      modules/mojo/bananas/gridshooter/images/grid.png
  19. BIN
      modules/mojo/bananas/gridshooter/images/hero.png
  20. BIN
      modules/mojo/bananas/gridshooter/images/jet.png
  21. BIN
      modules/mojo/bananas/gridshooter/images/laser.png
  22. BIN
      modules/mojo/bananas/gridshooter/images/starfield.png
  23. 12 0
      modules/mojo/bananas/gridshooter/renderwindow/README.txt
  24. 197 0
      modules/mojo/bananas/gridshooter/renderwindow/area.monkey2
  25. 316 0
      modules/mojo/bananas/gridshooter/renderwindow/renderwindow.monkey2

BIN
modules/mojo/bananas/gridshooter/fonts/classic_sans.ttf


+ 144 - 0
modules/mojo/bananas/gridshooter/fonts/gridshooter.monkey2

@@ -0,0 +1,144 @@
+
+#Import "renderwindow/renderwindow"
+#Import "gamegraphics/gamegraphics"
+
+#Import "fonts/classic_sans.ttf"
+#Import "images/grid.png"
+#Import "images/starfield.png"
+#Import "images/hero.png"
+#Import "images/jet.png"
+#Import "images/bullet.png"
+
+Using mojo..
+Using std..
+
+Class Game Extends RenderWindow
+
+	Field bg:Background
+	Field bgGrid:Background
+	Field smallFont:Font
+	Field heroSprite:Sprite
+	Field jetSprite:Sprite
+	Field bulletSprite:Sprite
+	
+	Field x:Double, y:Double, speed:= 2.0
+	Field oldX:Float, oldY:Float
+	Field anim:= "idle"
+	
+	Field cameraSpeed := 5.0
+	Field colorTint:= New Color( 0.25, 1.0, 0.5 )
+	
+	Field allBullets := New Stack<Bullet>
+	Field lastFired := 0
+	
+	Method New()					
+		Super.New( "Test", 480, 270, False, True )		'name, width, height, filterTextures, renderToTexture
+	End
+	
+	Method OnStart() Override
+		canvas.Font = Font.Load( "asset::classic_sans.ttf", 10 )
+		bg = New Background( "asset::starfield.png", False )
+		bgGrid = New Background( "asset::grid.png", False )
+		
+		heroSprite = New Sprite( "asset::hero.png", 3, 32, 32, False )
+		heroSprite.AddAnimationClip( "idle", New Int[]( 0 ) )
+		heroSprite.AddAnimationClip( "up", New Int[]( 1 ) )
+		heroSprite.AddAnimationClip( "down", New Int[]( 2 ) )
+		
+		jetSprite = New Sprite( "asset::jet.png", 2, 16, 16, False )
+		jetSprite.AddAnimationClip( "idle", New Int[]( 0,1 ) )
+		jetSprite.frameRate = 30
+		
+		bulletSprite = New Sprite( "asset::bullet.png", 4, 32, 32, False )
+		bulletSprite.AddAnimationClip( "idle", New Int[] ( 0 ) )
+		bulletSprite.AddAnimationClip( "hit", New Int[] ( 1,2,3 ) )
+		
+		For Local n := 0 Until 10
+			allBullets.Push( New Bullet )
+		Next
+	End
+	
+	Method OnUpdate() Override
+		camera.X += cameraSpeed		
+		x += cameraSpeed
+		
+		If Keyboard.KeyHit( Key.D ) Then debug = Not debug
+
+		If Keyboard.KeyDown( Key.Left )
+			x -= speed
+		Else If Keyboard.KeyDown( Key.Right )
+			x += speed
+		End
+		If Keyboard.KeyDown( Key.Up )
+			y -= speed * 2
+			camera.Y -= speed
+		Else If Keyboard.KeyDown( Key.Down )
+			y += speed * 2
+			camera.Y += speed
+		End
+		
+		If Keyboard.KeyHit( Key.Space )
+			Local bullet := allBullets.Get( lastFired )
+			bullet.visible = True
+			bullet.x = x + 16
+			bullet.y = y + 4
+			lastFired += 1
+			If lastFired > 9 Then lastFired = 0
+		End
+		
+		x = Clamp( x, camera.Left, camera.Right )
+		y = Clamp( y, camera.Top, camera.Bottom )
+		
+		If y > oldY
+			anim = "down"
+		Elseif y < oldY
+			anim = "up"
+		Else
+			anim = "idle"
+		End
+		oldY = y
+	End
+	
+	Method OnDraw() Override
+		canvas.Color = colorTint
+		
+		canvas.Alpha = 1.0
+		Parallax = 0.05
+		bg.Draw( canvas, 0, 0, 1.0, CameraRect )
+		
+		canvas.Alpha = 0.25
+		Parallax = 0.2
+		bgGrid.Draw( canvas, 32, 32, 1.0, CameraRect )
+		
+		canvas.Alpha = 0.5
+		Parallax = 1.0
+		bgGrid.Draw( canvas, 0, 0, 1.0, CameraRect )
+		
+		canvas.Alpha = 1.0
+		canvas.Color= Color.White
+		jetSprite.Draw( canvas, "idle", x-16, y+2 )
+		heroSprite.Draw( canvas, anim, x, y )
+		
+		For Local b := Eachin allBullets
+			If b.visible
+				bulletSprite.Draw( canvas, "idle", b.x, b.y )
+				b.x += b.speed
+				If b.x > ( x + Width ) Then b.visible = False
+			End
+		Next
+	End
+
+End
+
+Class Bullet
+	Field visible := False
+	Field x:Float, y:Float, speed:Float = 15.0
+End
+
+Function Main()
+	New AppInstance
+	New Game()
+	App.Run()
+End
+
+

+ 9 - 0
modules/mojo/bananas/gridshooter/gamegraphics/README.txt

@@ -0,0 +1,9 @@
+#GameGraphics
+
+A collection of game related drawing objects.
+
+- Sprite: A basic sprite system featuring spritesheet loading, easy texture filtering, animation clips (series of frames played back sequenctially) and playback framerate.
+
+- Background: An "infinite background" that takes a single texture and tiles it in a way that respects the Canvas translation, as long as you provide a camera Rect containing the camera corners (corrected for parallax, if necessary)
+
+Roadmap: Add Tilemap (will use a similar system as the Background object), "9-patches", Textbox.

BIN
modules/mojo/bananas/gridshooter/gamegraphics/classic_sans.ttf


+ 106 - 0
modules/mojo/bananas/gridshooter/gamegraphics/gamegraphics.monkey2

@@ -0,0 +1,106 @@
+
+#Import "<mojo>"
+#Import "src/sprite"
+#Import "src/background"
+
+Using mojo..
+Using std..
+
+Class GameGraphics Abstract
+
+	Field images		:Image[]	'The array containing all frames
+	Field debug := False
+		
+	Protected
+	Field _handle:= New Vec2f
+
+	
+	'************************************* Instance Properties *************************************
+	
+	Public
+	
+	'Sets the handles in all sub-images
+	Property Handle:Vec2f()
+		Return _handle
+	Setter( handle:Vec2f )
+		_handle = handle
+		For Local i := Eachin images
+			i.Handle = _handle
+		Next
+	End
+
+	
+	'************************************* Instance Methods *************************************
+
+	
+	'Loads an array of Images from a sprite sheet
+	Method LoadFrames:Image[] ( path:String, numFrames:Int, cellWidth:Int, cellHeight:Int, filter:Bool = True, padded:Bool = False )
+	
+		Local flags:TextureFlags=Null
+		If filter Then flags |= TextureFlags.Filter
+		
+		Local atlasTextture := Texture.Load( path, flags )
+		Assert( atlasTextture, " ~n ~nGameGraphics: Image " + path + " not found.~n ~n" )
+		
+		Local atlasImg := New Image( atlasTextture )
+		Local imgs := New Image[ numFrames ]
+
+		If cellHeight = atlasImg.Height
+			Local x := 0
+			Local width := cellWidth
+			If padded
+				x += 1
+				width -= 2
+			End
+			For Local i := 0 Until numFrames
+				Local x0 := i * cellWidth + x
+				Local y0 := 0
+				imgs[i] = New Image( atlasImg, New Recti( x0, y0, x0 + cellWidth, cellHeight ) )
+'   				imgs[i].Handle = New Vec2f( .5,.5 )
+			Next
+		Else
+			Local x:= 0
+			Local width:= cellWidth
+			Local y:= 0
+			Local height:= cellHeight
+			Local columns:= atlasImg.Width / width
+			If padded
+				x += 1
+				y += 1
+				width -= 2
+				height -= 2
+			End If
+			For Local i:= 0 Until numFrames
+				Local fx := i Mod columns * cellWidth
+				Local fy := i / columns * cellHeight
+				imgs[i] = New Image( atlasImg, New Recti( fx + x, fy + y, fx + cellWidth, fy + cellHeight ) )
+'   				imgs[i].Handle = New Vec2f( .5,.5 )
+			Next
+		Endif
+		atlasImg = Null
+		Return imgs
+	End
+	
+	
+	Method DrawOutline( canvas:Canvas, x:Float, y:Float, width:Float, height:Float, rz:Float = 0, sx:Float = 1.0, sy:Float = 1.0 )
+		Local matrix:= canvas.Matrix
+		canvas.Translate( x, y )
+		canvas.Rotate( rz )
+		canvas.Scale( sx,sy )
+		DrawRectOutline( canvas, -( width * Handle.X ), -( height * Handle.Y ), width, height )
+		canvas.Matrix=matrix
+	End
+	
+	
+	
+	'************************************* Class Functions *************************************
+	
+
+	Method DrawRectOutline:Void(canvas:Canvas, left:Int, top:Int, width:Int, height:Int )
+		canvas.DrawLine( left, top, left+width, top )
+		canvas.DrawLine( left, top, left ,top+height )
+		canvas.DrawLine( left, top+height, left+width, top+height )
+		canvas.DrawLine( left+width, top, left+width, top+height )
+	End
+
+End

+ 9 - 0
modules/mojo/bananas/gridshooter/gamegraphics/src/README.txt

@@ -0,0 +1,9 @@
+#GameGraphics
+
+A collection of game related drawing objects.
+
+- Sprite: A basic sprite system featuring spritesheet loading, easy texture filtering, animation clips (series of frames played back sequenctially) and playback framerate.
+
+- Background: An "infinite background" that takes a single texture and tiles it in a way that respects the Canvas translation, as long as you provide a camera Rect containing the camera corners (corrected for parallax, if necessary)
+
+Roadmap: Add Tilemap (will use a similar system as the Background object), "9-patches", Textbox.

+ 47 - 0
modules/mojo/bananas/gridshooter/gamegraphics/src/background.monkey2

@@ -0,0 +1,47 @@
+
+#Import "tilegraphics"
+
+Class Background Extends TileGraphics
+
+	Field total:Int
+
+	Method New( path:String, filter:Bool = True )
+	
+		Local flags:TextureFlags=Null
+		If filter Then flags |= TextureFlags.Filter
+		
+		Local atlasTextture := Texture.Load( path, flags )
+		Assert( atlasTextture, " ~n ~nGameGraphics: Image " + path + " not found.~n ~n" )
+		images = New Image[]( New Image( atlasTextture ) )
+	End
+	
+	Method Draw( canvas:Canvas, x:Double, y:Double, scale:Double, camera:Rect<Double> )
+
+		total = 0
+
+		GetVisibleTiles( x, y, scale, camera )
+		
+		For Local tY := tileStartY Until tileEndY
+			For Local tX := tileStartX Until tileEndX
+				local absX := ( tX * tileWidth ) + x
+				local absY := ( tY * tileHeight ) + y
+				If images[0]
+					total += 1
+					canvas.DrawImage( images[0], absX, absY, 0, scale, scale )
+					If debug
+						DrawRectOutline( canvas, absX, absY, tileWidth, tileHeight )
+						canvas.DrawText( tX + "," + tY, absX + 4, absY + 4 )
+					End
+				End
+			Next
+		Next
+	End
+	
+	Method ToString:String()
+		Local t := ""
+		t += ( "Background: " + tileStartX + "," + tileStartY + "; " + tileEndX + "," + tileEndY + "; " )
+		t += ( "Total tiles: " + total )
+		Return t
+	End
+	
+End

+ 106 - 0
modules/mojo/bananas/gridshooter/gamegraphics/src/gamegraphics.monkey2

@@ -0,0 +1,106 @@
+
+#Import "<mojo>"
+#Import "src/sprite"
+#Import "src/background"
+
+Using mojo..
+Using std..
+
+Class GameGraphics Abstract
+
+	Field images		:Image[]	'The array containing all frames
+	Field debug := False
+		
+	Protected
+	Field _handle:= New Vec2f
+
+	
+	'************************************* Instance Properties *************************************
+	
+	Public
+	
+	'Sets the handles in all sub-images
+	Property Handle:Vec2f()
+		Return _handle
+	Setter( handle:Vec2f )
+		_handle = handle
+		For Local i := Eachin images
+			i.Handle = _handle
+		Next
+	End
+
+	
+	'************************************* Instance Methods *************************************
+
+	
+	'Loads an array of Images from a sprite sheet
+	Method LoadFrames:Image[] ( path:String, numFrames:Int, cellWidth:Int, cellHeight:Int, filter:Bool = True, padded:Bool = False )
+	
+		Local flags:TextureFlags=Null
+		If filter Then flags |= TextureFlags.Filter
+		
+		Local atlasTextture := Texture.Load( path, flags )
+		Assert( atlasTextture, " ~n ~nGameGraphics: Image " + path + " not found.~n ~n" )
+		
+		Local atlasImg := New Image( atlasTextture )
+		Local imgs := New Image[ numFrames ]
+
+		If cellHeight = atlasImg.Height
+			Local x := 0
+			Local width := cellWidth
+			If padded
+				x += 1
+				width -= 2
+			End
+			For Local i := 0 Until numFrames
+				Local x0 := i * cellWidth + x
+				Local y0 := 0
+				imgs[i] = New Image( atlasImg, New Recti( x0, y0, x0 + cellWidth, cellHeight ) )
+'   				imgs[i].Handle = New Vec2f( .5,.5 )
+			Next
+		Else
+			Local x:= 0
+			Local width:= cellWidth
+			Local y:= 0
+			Local height:= cellHeight
+			Local columns:= atlasImg.Width / width
+			If padded
+				x += 1
+				y += 1
+				width -= 2
+				height -= 2
+			End If
+			For Local i:= 0 Until numFrames
+				Local fx := i Mod columns * cellWidth
+				Local fy := i / columns * cellHeight
+				imgs[i] = New Image( atlasImg, New Recti( fx + x, fy + y, fx + cellWidth, fy + cellHeight ) )
+'   				imgs[i].Handle = New Vec2f( .5,.5 )
+			Next
+		Endif
+		atlasImg = Null
+		Return imgs
+	End
+	
+	
+	Method DrawOutline( canvas:Canvas, x:Float, y:Float, width:Float, height:Float, rz:Float = 0, sx:Float = 1.0, sy:Float = 1.0 )
+		Local matrix:= canvas.Matrix
+		canvas.Translate( x, y )
+		canvas.Rotate( rz )
+		canvas.Scale( sx,sy )
+		DrawRectOutline( canvas, -( width * Handle.X ), -( height * Handle.Y ), width, height )
+		canvas.Matrix=matrix
+	End
+	
+	
+	
+	'************************************* Class Functions *************************************
+	
+
+	Method DrawRectOutline:Void(canvas:Canvas, left:Int, top:Int, width:Int, height:Int )
+		canvas.DrawLine( left, top, left+width, top )
+		canvas.DrawLine( left, top, left ,top+height )
+		canvas.DrawLine( left, top+height, left+width, top+height )
+		canvas.DrawLine( left+width, top, left+width, top+height )
+	End
+
+End

+ 116 - 0
modules/mojo/bananas/gridshooter/gamegraphics/src/sprite.monkey2

@@ -0,0 +1,116 @@
+
+'TO DO: different loop behaviors ( loop, stop, bounce, random )
+Class Sprite Extends GameGraphics
+
+	Field timeScale := 1.0			'Adjusts playback speed. Can be used to create slow motion effects without setting the framerate.
+	Field frameRate := 10			'in frames per second
+	
+	Field animations := New StringMap< AnimationClip >		'List of available animation clips
+	
+	Private
+	
+	Field _time:Int					'main time. Can be overriden in the Draw() method.
+	Field _period:Int				'how many millisecs for each frame
+	Field _listFrame:Int			'looped animation clip frame number
+	Field _clampedListFrame:Int		'ensures not out-of-bounds value
+	Field _duration:Int				'how long the current animation clip is
+	Field _frame:Int				'current frame being played
+	Field _startTime:Int			'keeps track of when the last Reset() ocurred
+	Field _anim := ""				'The animation clip last played
+
+	Public
+	
+	'************************************* Instance Properties *************************************
+	
+	'Current frame
+	Property Frame:Int()
+		Return _frame
+	End
+
+
+	'************************************* Instance Methods *************************************
+
+	'Loads images[] and initializes itself
+	Method New( ImagePath:String, Totalframes:Int=1, cellWidth:Int, cellHeight:Int, filter:Bool = True )
+		images = LoadFrames( ImagePath, Totalframes, cellWidth, cellHeight, filter )
+		Handle = New Vec2f( 0.5, 0.5 )
+		Reset()
+	End
+
+	'Use this to restart the playback from frame 0
+	Method Reset()
+		_startTime = Millisecs()
+	End
+
+	'main drawing. You can override the time to offset instances of the same sprite.
+	Method Draw( canvas:Canvas, anim:String, x:Float, y:Float, rotation:Float = 0.0, scaleX:Float = 1.0, scaleY:Float = 1.0, time:Int = -1 )
+
+		Local _anim := animations.Get( anim )
+	
+		If debug Or Not _anim
+			Local w := images[ _frame ].Width
+			Local h := images[ _frame ].Height
+			DrawOutline( canvas, x, y, w, h , rotation, scaleX, scaleY )
+		End
+		If Not _anim
+			canvas.DrawText( "Sprite: AnimationClip '" + anim + "' is undefined", x, y )
+			Return
+		End
+		
+		'Override _time with any time value above 0
+		If time < 0
+			_time = Millisecs() - _startTime
+		Else
+			_time = time 
+		End
+		_period = ( 1000 / frameRate ) / timeScale	
+
+		If _anim.loop
+			_listFrame = _time Mod ( _anim.frame.Length * _period )
+			_clampedListFrame = Clamp( _listFrame/_period, 0, _anim.frame.Length - 1 )			
+		Else
+			_clampedListFrame = Clamp( _time/_period, 0, _anim.frame.Length - 1 )
+		End
+		
+		_frame = _anim.frame[ _clampedListFrame ]
+
+		If images
+			canvas.DrawImage( images[ _frame ], x, y, rotation, scaleX, scaleY )
+		Else
+			canvas.DrawText( "Sprite: No image loaded", x, y )
+		End		
+	End
+
+	'How long this animation clip is in milliseconds
+	Property Duration:Int( anim:String )
+		Local a := animations.Get( anim )
+		If Not a Then Return 0
+		_period = ( 1000 / frameRate ) / timeScale
+		Return _period * a.Count()				
+	End	
+	
+	'Adds new animation clips. Won't draw anything until you create at least one animation clip
+	Method AddAnimationClip( _id:String, _frames:Int[], _loop:Bool = True )
+		local animClip := New AnimationClip()
+		animClip.id = _id
+		animClip.loop = _loop
+		animClip.frame = _frames
+		animations.Add( _id, animClip )
+	End
+
+End
+
+'*******************************************************************'
+
+'AnimationClips contain a sequence of frames to be played
+Class AnimationClip
+
+	field id			:String			'Animation name
+	field frame 		:Int[]			'Frame list array, contains the sequence in which the frames play
+	field loop			:= True			'looping can be controlled per animation
+
+	Method Count:Int()
+		Return frame.Length
+	End
+
+End

+ 40 - 0
modules/mojo/bananas/gridshooter/gamegraphics/src/tilegraphics.monkey2

@@ -0,0 +1,40 @@
+
+'Base class used by Shapes like Tilemap and Background
+Class TileGraphics Extends GameGraphics Abstract
+
+	Field tileWidth:Double
+	Field tileHeight:Double
+
+	Protected
+	Field drawScaleX:Double
+	Field drawScaleY:Double
+	Field viewLeft:Double
+	Field viewTop:Double
+	Field viewRight:Double
+	Field viewBottom:Double
+	
+	Field tileStartX:Int
+	Field tileStartY:Int
+	Field tileEndX:Int
+	Field tileEndY:Int
+
+	Method GetVisibleTiles( x:Double, y:Double, scale:Double, camera:Rect<Double> )
+
+		tileWidth = images[0].Width * scale
+		tileHeight = images[0].Height * scale
+
+		viewLeft = camera.Left - x
+		viewRight = camera.Right - x
+		viewTop = camera.Top - y
+		viewBottom = camera.Bottom - y
+
+'   		Local margin := 0
+		
+		tileStartX = Floor( viewLeft / tileWidth )' - margin
+		tileStartY = Floor( viewTop / tileHeight )' - margin
+
+		tileEndX = Ceil( viewRight / tileWidth )' + margin
+		tileEndY = Ceil( viewBottom / tileHeight )' + margin
+	End
+
+End

+ 144 - 0
modules/mojo/bananas/gridshooter/gridshooter.monkey2

@@ -0,0 +1,144 @@
+
+#Import "renderwindow/renderwindow"
+#Import "gamegraphics/gamegraphics"
+
+#Import "fonts/classic_sans.ttf"
+#Import "images/grid.png"
+#Import "images/starfield.png"
+#Import "images/hero.png"
+#Import "images/jet.png"
+#Import "images/bullet.png"
+
+Using mojo..
+Using std..
+
+Class Game Extends RenderWindow
+
+	Field bg:Background
+	Field bgGrid:Background
+	Field smallFont:Font
+	Field heroSprite:Sprite
+	Field jetSprite:Sprite
+	Field bulletSprite:Sprite
+	
+	Field x:Double, y:Double, speed:= 2.0
+	Field oldX:Float, oldY:Float
+	Field anim:= "idle"
+	
+	Field cameraSpeed := 5.0
+	Field colorTint:= New Color( 0.25, 1.0, 0.5 )
+	
+	Field allBullets := New Stack<Bullet>
+	Field lastFired := 0
+	
+	Method New()					
+		Super.New( "Test", 480, 270, False, True )		'name, width, height, filterTextures, renderToTexture
+	End
+	
+	Method OnStart() Override
+		canvas.Font = Font.Load( "asset::classic_sans.ttf", 10 )
+		bg = New Background( "asset::starfield.png", False )
+		bgGrid = New Background( "asset::grid.png", False )
+		
+		heroSprite = New Sprite( "asset::hero.png", 3, 32, 32, False )
+		heroSprite.AddAnimationClip( "idle", New Int[]( 0 ) )
+		heroSprite.AddAnimationClip( "up", New Int[]( 1 ) )
+		heroSprite.AddAnimationClip( "down", New Int[]( 2 ) )
+		
+		jetSprite = New Sprite( "asset::jet.png", 2, 16, 16, False )
+		jetSprite.AddAnimationClip( "idle", New Int[]( 0,1 ) )
+		jetSprite.frameRate = 30
+		
+		bulletSprite = New Sprite( "asset::bullet.png", 4, 32, 32, False )
+		bulletSprite.AddAnimationClip( "idle", New Int[] ( 0 ) )
+		bulletSprite.AddAnimationClip( "hit", New Int[] ( 1,2,3 ) )
+		
+		For Local n := 0 Until 10
+			allBullets.Push( New Bullet )
+		Next
+	End
+	
+	Method OnUpdate() Override
+		camera.X += cameraSpeed		
+		x += cameraSpeed
+		
+		If Keyboard.KeyHit( Key.D ) Then debug = Not debug
+
+		If Keyboard.KeyDown( Key.Left )
+			x -= speed
+		Else If Keyboard.KeyDown( Key.Right )
+			x += speed
+		End
+		If Keyboard.KeyDown( Key.Up )
+			y -= speed * 2
+			camera.Y -= speed
+		Else If Keyboard.KeyDown( Key.Down )
+			y += speed * 2
+			camera.Y += speed
+		End
+		
+		If Keyboard.KeyHit( Key.Space )
+			Local bullet := allBullets.Get( lastFired )
+			bullet.visible = True
+			bullet.x = x + 16
+			bullet.y = y + 4
+			lastFired += 1
+			If lastFired > 9 Then lastFired = 0
+		End
+		
+		x = Clamp( x, camera.Left, camera.Right )
+		y = Clamp( y, camera.Top, camera.Bottom )
+		
+		If y > oldY
+			anim = "down"
+		Elseif y < oldY
+			anim = "up"
+		Else
+			anim = "idle"
+		End
+		oldY = y
+	End
+	
+	Method OnDraw() Override
+		canvas.Color = colorTint
+		
+		canvas.Alpha = 1.0
+		Parallax = 0.05
+		bg.Draw( canvas, 0, 0, 1.0, CameraRect )
+		
+		canvas.Alpha = 0.25
+		Parallax = 0.2
+		bgGrid.Draw( canvas, 32, 32, 1.0, CameraRect )
+		
+		canvas.Alpha = 0.5
+		Parallax = 1.0
+		bgGrid.Draw( canvas, 0, 0, 1.0, CameraRect )
+		
+		canvas.Alpha = 1.0
+		canvas.Color= Color.White
+		jetSprite.Draw( canvas, "idle", x-16, y+2 )
+		heroSprite.Draw( canvas, anim, x, y )
+		
+		For Local b := Eachin allBullets
+			If b.visible
+				bulletSprite.Draw( canvas, "idle", b.x, b.y )
+				b.x += b.speed
+				If b.x > ( x + Width ) Then b.visible = False
+			End
+		Next
+	End
+
+End
+
+Class Bullet
+	Field visible := False
+	Field x:Float, y:Float, speed:Float = 15.0
+End
+
+Function Main()
+	New AppInstance
+	New Game()
+	App.Run()
+End
+
+

BIN
modules/mojo/bananas/gridshooter/images/bombExplosion.png


BIN
modules/mojo/bananas/gridshooter/images/bullet.png


BIN
modules/mojo/bananas/gridshooter/images/dualbeam.png


BIN
modules/mojo/bananas/gridshooter/images/enemyBulletBig.png


BIN
modules/mojo/bananas/gridshooter/images/enemyBulletSmall.png


BIN
modules/mojo/bananas/gridshooter/images/explosion.png


BIN
modules/mojo/bananas/gridshooter/images/grid.png


BIN
modules/mojo/bananas/gridshooter/images/hero.png


BIN
modules/mojo/bananas/gridshooter/images/jet.png


BIN
modules/mojo/bananas/gridshooter/images/laser.png


BIN
modules/mojo/bananas/gridshooter/images/starfield.png


+ 12 - 0
modules/mojo/bananas/gridshooter/renderwindow/README.txt

@@ -0,0 +1,12 @@
+# RenderWindow
+A Window class for Monkey2 that simplifies some tasks like parallax layers and render to texture.
+
+Features:
+- Simple camera coordinates. Any x and y drawing coordinate becomes a world coordinate.
+- Easy to use Parallax
+- "World space" mouse coordinates
+- Render to texture, allows "pixel perfect" games
+- Display debug info on screen with Echo( "info" )
+
+Check the examples folder for a simple test usage.
+

+ 197 - 0
modules/mojo/bananas/gridshooter/renderwindow/area.monkey2

@@ -0,0 +1,197 @@
+
+Struct Area<T>
+
+	Private
+	
+	Field _vec:Vec2<T>
+	Field _width:T
+	Field _height:T	
+	Field _handle := New Vec2f( 0.5, 0.5 )	'Values are from 0,0 (Left, Top ) to 1,1 (Right, Bottom )
+
+	Field _x0:T, _y0:T, _x1:T, _y1:T		'corners
+	Field _pivotX:T							'width * handle.X
+	Field _pivotY:T							'height * handle.Y
+	
+	Field _rect:Rect<T>
+
+	Public
+
+	'*************************  Properties  ****************************
+	
+	Property X:T()
+		Return _vec.X
+	Setter( x:T )
+		_vec.X = x
+		Self._x0 = x - _pivotX
+		Self._x1 = _x0 + _width
+	End
+	
+	Property Y:T()
+		Return _vec.Y
+	Setter( y:T )
+		_vec.Y = y
+		Self._y0 = y - _pivotY
+		Self._y1 = _y0 + _height
+	End
+
+	Property Width:T()
+		Return _width
+	Setter( w:T )
+		Self._width = w
+		_pivotX = ( _width * _handle.x )
+		Self._x0 = _vec.X - _pivotX
+		Self._x1 = _x0 + _width
+	End
+	
+	Property Height:T()
+		Return _height
+	Setter( h:T )
+		Self._height = h
+		_pivotY = ( _height * _handle.y )
+		Self._y0 = _vec.Y - _pivotY
+		Self._y1 = _y0 + _height
+	End
+
+	Property Left:T()
+		Return _x0
+	End
+	
+	Property Right:T()
+		Return _x1
+	End
+	
+	Property Top:T()
+		Return _y0
+	End
+	
+	Property Bottom:T()
+		Return _y1
+	End
+	
+	Property Handle:Vec2f()
+		Return _handle
+	End
+	
+	Property Rect:Rect<T>()
+		_rect.Left = _x0
+		_rect.Top = _y0
+		_rect.Right = _x1
+		_rect.Bottom = _y1		
+		Return _rect
+	End
+
+	'**************************  Public Methods  ****************************
+
+	Method New( x:T, y:T, _width:T, _height:T )
+		X = x
+		Y = y
+		SetSize( _width, _height )
+		_rect = New Rect<T>
+	End
+	
+	Method Position( x:T, y:T )
+		X = x
+		Y = y
+	End
+
+	Method SetSize(_width:T, _height:T )
+		Self._width = _width
+		Self._height = _height
+		_pivotX = ( _width * _handle.x )
+		_pivotY = ( _height * _handle.y )
+		Self._x0 = _vec.X - _pivotX
+		Self._y0 = _vec.Y - _pivotY
+		Self._x1 = _x0 + _width
+		Self._y1 = _y0 + _height
+	End
+	
+	Method SetHandle( pX:Float, pY:Float )
+		_handle.X = pX
+		_handle.Y = pY
+		_pivotX = pX * _width
+		_pivotY = pY * _height
+		Self._x0 = _vec.X - _pivotX
+		Self._y0 = _vec.Y - _pivotY
+		Self._x1 = _x0 + _width
+		Self._y1 = _y0 + _height
+	End
+	 
+	Method PositionByCorner( _x0:Float, _y0:Float )
+		X = _x0 + _pivotX
+		Y = _y0 + _pivotY
+	End
+
+	Method Move( deltaX:Float, deltaY:Float )
+		Position( _vec.X + deltaX, _vec.Y +deltaY )
+	End
+'   
+	Method Contains:Bool(_x:Float, _y:Float)
+		If _x > _x0
+			If _x < _x1
+				If _y > _y0
+					If _y < _y1
+						Return True
+					End
+				End
+			End
+		End
+		Return False
+	End
+
+	Method Overlaps:Bool( rect:Area )
+		If rect._x1 > _x0
+			If rect._x0 < _x1
+				If rect._y1 > _y0
+					If rect._y0 < _y1
+						Return True
+					End
+				End
+			End
+		End
+		Return False
+	End
+	
+	Method ToString:String()
+'   		Return "Area("+_vec.X+","+_vec.Y+","+_width+","+_height+")"
+		Return "("+Int(_x0)+","+Int(_y0)+","+Int(_x1)+","+Int(_y1)+")"
+	End
+	
+
+'	Old code, unconverted to M2
+
+'   	Method Copy( other:Vec2<f> )
+'   		Self.X = other.X
+'   		Self.Y = other.Y
+'   		local otherRect := Rec2<T>( other )
+'   		If otherRect
+'   			Self._pivotX = otherRect._pivotX
+'   			Self._pivotY = otherRect._pivotY
+'   			Self._width = otherRect.Width
+'   			Self._height = otherRect.Height
+'   			Self._x0 = x - _pivotX
+'   			Self._y0 = y - _pivotY
+'   			Self._x1 = _x0 + _width
+'   			Self._y1 = _y0 + _height
+'   			Self._handle.Copy( otherRect._handle )
+'   		End
+'   	End
+
+'   	Method SnapToPixel:Void()
+'   		x = Round( x )
+'   		y = Round( y )
+'   		_width = Round( _width )
+'   		_height = Round( _height )
+'   		_pivotX = Round( _width * _handle.x )
+'   		_pivotY = Round( _height * _handle.y )
+'   		_x0 = Round( x - _pivotX )
+'   		_y0 = Round( y - _pivotY )
+'   		_x1 = Round( _x0 + _width )
+'   		_y1 = Round( _y0 + _height )
+'   	End
+'   
+'   	Function Round:Float(number:Float)
+'   		If number - Int(number) > 0.5 Then Return Ceil(number)
+'   		Return Floor(number)
+'   	End
+
+End

+ 316 - 0
modules/mojo/bananas/gridshooter/renderwindow/renderwindow.monkey2

@@ -0,0 +1,316 @@
+
+#Rem
+Features:
+- Simple camera coordinates. Any x and y drawing coordinate becomes a world coordinate.
+- Easy to use Parallax
+- "World space" mouse coordinates
+- Render to texture, allows "pixel perfect" games
+- Display debug info on screen with Echo( "info" )
+#End
+
+'To Do: camera is a rect. SHould it be a Vec2f? Of should I take advantage of the rect and change the code?
+'To do: Integer scaling
+
+#Import "<mojo>"
+#Import "area"
+
+Using mojo..
+Using std..
+
+Class RenderWindow Extends Window
+
+	Field canvas :Canvas						'Main canvas currently in use
+	Field camera :Area<Double>					'Camera coordinates
+	
+	Field renderToTexture := False				'Causes all canvas rendering to be directed to a fixed size texture
+	Field filterTextures := True				'Turns on/off texture smoothing. Off for pixel art.
+	Field bgColor := Color.DarkGrey				'Background color
+	Field borderColor := Color.Black 			'Letterboxing border color
+	Field debug := False						'Toggles display of debug info ( Echo() )
+	
+	Protected
+	Field _init := False
+	
+	Field _parallax := 1.0
+	Field _parallaxCam :Area<Double>
+	
+	Field _virtualRes:= New Vec2i				'Virtual rendering size
+	Field _mouse := New Vec2i					'temporarily stores mouse coords
+	Field _adjustedMouse := New Vec2i			'Mouse corrected for layout style and camera position
+	Field _layerInitiated := False
+
+	Field _echoStack:= New Stack<String>		'Contains all the text messages to be displayed
+	Field _flags :TextureFlags					'flags used on the render texture
+	
+	Field _fps	:= 60							'fps counter
+	Field _fpscount	:= 0.0						'temporary fps counter
+	Field _tick := 0							'Only stores the current time once every second
+	
+	Field _renderImage :Image					'Image that uses the render target
+	Field _textureCanvas :Canvas				'Canvas that uses _renderImage
+	Field _windowCanvas: Canvas					'main window canvas
+	
+	Public
+	
+	
+	'**************************************************** Properties ****************************************************
+	
+	'Mouse coordinates in WORLD units, corrected for camera
+	Property Mouse:Vec2i()						
+		Return _adjustedMouse
+	End
+	
+	'You can set the parallax before any drawing operation
+	Property Parallax:Float()					
+		Return _parallax
+	Setter( value:Float )
+		_parallax = value
+		_parallaxCam.Position( camera.X * _parallax, camera.Y * _parallax )
+		If _layerInitiated
+			canvas.PopMatrix()
+			_layerInitiated = False
+		End
+		canvas.PushMatrix()
+'   		canvas.Translate( ( -camera.X * _parallax ) + _cameraOffset.X, ( -camera.Y * _parallax ) + _cameraOffset.Y  )
+		canvas.Translate( ( -camera.X * _parallax ) + camera.Width/2.0, ( -camera.Y * _parallax ) + camera.Height/2.0  )
+
+		_layerInitiated = True
+	End
+	
+	'Returns the camera corrected for current parallax 
+	Property CameraRect:Rect<Double>()
+		Return _parallaxCam.Rect
+	End
+	
+	'Flags used by the Render Texture
+	Property Flags:TextureFlags()
+		Return _flags
+	End
+	
+	'Efective frame rate
+	Property FPS:Int()
+		Return _fps
+	End
+	
+	'corner window coordinates	
+	Property Left:Float()
+		Return -Width/2.0
+	End
+	
+	Property Right:Float()
+		Return Width/2.0
+	End
+	
+	Property Top:Float()
+		Return -Height/2.0
+	End
+	
+	Property Bottom:Float()
+		Return Height/2.0
+	End
+	
+	
+	'**************************************************** Public methods ****************************************************
+	
+	
+	Method New( title:String, width:Int, height:Int, filterTextures:Bool = True, renderToTexture:Bool = False, flags:WindowFlags = WindowFlags.Resizable )
+		Super.New( title, width, height, flags )
+		Layout = "letterbox-int"
+		ClearColor = borderColor
+		Style.BackgroundColor = bgColor
+		
+		_flags = Null
+		If filterTextures Then _flags |= TextureFlags.Filter		
+
+'		_flags=Null
+'		If filterTextures Then _flags|=TextureFlags.Filter
+		
+		Self.renderToTexture = renderToTexture
+		Self.filterTextures = filterTextures
+		
+		camera = New Area<Double>( 0, 0, width, height )
+		_parallaxCam = New Area<Double>( 0, 0, width, height )
+		
+		SetVirtualResolution( width, height )
+'   		SelectCanvas()
+	End
+	
+
+	Method OnRender( windowCanvas:Canvas ) Override
+		App.RequestRender()
+		
+		If Not _init
+			_init = True
+'   			canvas = windowCanvas
+			SelectCanvas()
+			WindowStart()
+			Return
+		End
+		
+		FrameUpdate()
+		
+		Style.BackgroundColor = bgColor
+		Self._windowCanvas = windowCanvas
+		
+		'Picks current drawing canvas based on renderToTexture
+		SelectCanvas()
+
+		'Mouse in world coordinates
+		_mouse = TransformPointFromView( App.MouseLocation, Null )
+		_adjustedMouse.x = _mouse.x + camera.Left
+		_adjustedMouse.y = _mouse.y + camera.Top
+		
+		'the Parallax property will always set the canvas translation before drawing.
+		Parallax = 1.0		
+		FrameDraw()
+		
+		''Closes' the drawing for any parallax layer
+		If _layerInitiated
+			canvas.PopMatrix()
+			_layerInitiated = False
+		End
+		
+		'Draws render to texture image onto _windowCanvas
+		If renderToTexture
+			canvas.Flush()
+			_windowCanvas.DrawImage( _renderImage, 0, 0 )
+		End
+		
+		'Resets canvas colors for each frame
+		_textureCanvas.Color = Color.White
+		_windowCanvas.Color = Color.White
+		
+		'Draw message stack, then clear it every frame
+		If debug Then DebugInfo()
+		Local y := 2
+		For Local t := Eachin _echoStack
+			_windowCanvas.DrawText( t, 5, y )
+			y += _windowCanvas.Font.Height
+		Next
+		_echoStack.Clear()
+		
+		'App quit
+		If ( Keyboard.KeyDown( Key.LeftGui ) And Keyboard.KeyHit( Key.Q ) ) Or ( Keyboard.KeyDown( Key.LeftAlt ) And Keyboard.KeyHit( Key.W ) )
+			App.Terminate()
+		End
+		
+		'Basic fps counter
+		If Millisecs() - _tick > 1008
+			_fps = _fpscount
+			_tick = Millisecs()
+			_fpscount=0
+		Else
+			_fpscount +=1
+		End
+	End
+	
+	
+	Method OnMeasure:Vec2i() Override
+		Return _virtualRes
+	End
+	
+	
+	Method OnWindowEvent(event:WindowEvent) Override
+		Select event.Type
+			Case EventType.WindowMoved
+			Case EventType.WindowResized
+				App.RequestRender()
+			Case EventType.WindowGainedFocus
+			Case EventType.WindowLostFocus
+			Default
+				Super.OnWindowEvent(event)
+		End
+	End
+	
+
+	Method SetVirtualResolution( width:Int, height:Int )
+		_virtualRes = New Vec2i( width, height )
+		MinSize = New Vec2i( width/2, height/2 )
+		
+		camera.Width = width
+		camera.Height = height
+		_parallaxCam.Width = Width
+		_parallaxCam.Height = Height
+		
+		_renderImage = New Image( width,height,TextureFlags.Dynamic )
+		_textureCanvas = New Canvas( _renderImage )
+		_textureCanvas.Font = App.DefaultFont
+	End
+	
+	
+	Method Echo( text:String )
+		_echoStack.Push( text )
+	End
+	
+
+	Method CycleLayout()
+		Select Layout
+		Case "fill"
+			Layout="letterbox-int"
+		Case "letterbox-int"
+			Layout="stretch"
+		Case "stretch"
+			Layout="float"
+		Case "float"
+'   			Layout="fill"
+			Layout = "letterbox-int"
+		End
+	End
+	
+	
+	'**************************************************** Protected Methods ****************************************************
+	'These allow RenderWindow to be extended without the need for OnUpdate and OnDraw to call Super.xxx().
+	'i.e: A MyGameEngine class can extend RenderWindow and override FrameDraw() and add specific features, leaving OnDraw() alone, as long as it is called somewhere.
+	
+	Protected
+	
+	Method WindowStart() Virtual
+		OnStart()
+	End
+	
+	Method FrameUpdate() Virtual
+		OnUpdate()
+	End
+	
+	Method FrameDraw() Virtual
+		OnDraw()
+	End
+	
+	Method DebugInfo() Virtual
+		Echo( "Window resolution: " + Frame.Width + ", " + Frame.Height )
+		Echo( "Virtual resolution: " + Width + ", " + Height )
+		Echo( "Mouse:" + Mouse.x + "," + Mouse.y )
+		Echo( "Camera:" + Int( camera.X ) + "," + Int( camera.Y ) )
+		Echo( "Layout: " + Layout )
+		If renderToTexture
+			Echo( "renderToTexture = True" )
+		Else
+			Echo( "renderToTexture = False" )
+		End
+		Echo( "Camera: " + camera.ToString() )
+		Echo( "FPS: " + FPS )
+	End
+	
+	Method SelectCanvas()
+		If renderToTexture
+			canvas = _textureCanvas
+		Else
+			canvas = _windowCanvas
+		End
+		canvas.Clear( bgColor )
+	End
+	
+	'**************************************************** Virtual Methods ****************************************************
+	Public
+	
+	Method OnStart() Virtual
+	End
+	
+	Method OnUpdate() Virtual
+	End
+	
+	Method OnDraw() Virtual
+	End
+	
+End
+