Permalink
Browse files

Major internal rewrite. New GameState system with 1 example. Docs.

  • Loading branch information...
1 parent d093a87 commit 7619f4fe805935649a867267b6dbeebb7d90073a @ippa committed Aug 9, 2009
Showing with 457 additions and 83 deletions.
  1. +91 −9 README.rdoc
  2. +93 −0 examples/example4.rb
  3. +5 −2 lib/chingu.rb
  4. +17 −27 lib/chingu/game_object.rb
  5. +39 −0 lib/chingu/game_state.rb
  6. +84 −0 lib/chingu/game_state_manager.rb
  7. +41 −0 lib/chingu/helpers.rb
  8. +7 −4 lib/chingu/keymap.rb
  9. +80 −41 lib/chingu/window.rb
View
@@ -125,7 +125,7 @@ This is our basic "gameunit"-class, meaning most ingame objects (players, enemie
* Encapsulate only the very common basics that Most ingame objects need
* Keep naming close to Gosu, but add smart convenientmethods / shortcuts and a more rubyish feeling
-* No gamelogic at all allowed in ScreenObject, since that is most likely usefull for others
+* No gamelogic at all allowed in GameObject, since that is most likely usefull for others
I've chose to base it around Image#draw_rot. So basicly all the arguments that you pass to draw_rot can be passed to GameObject#new when creating a new object, an example using almost all arguments would be:
@@ -149,11 +149,82 @@ I've chose to base it around Image#draw_rot. So basicly all the arguments that y
@player = Player.new
#
- # By default Chingu::Window calls update & draw on all ScreenObjects in it's own update/draw.
+ # By default Chingu::Window calls update & draw on all GameObjects in it's own update/draw.
# If this is not what you want, use :draw and :update
#
@player = Player.new(:draw => false, :update => false)
+=== GameState / GameStateManager
+Chingu incorperates a basic push/pop gamestate system (as discuessed here: http://www.gamedev.net/community/forums/topic.asp?topic_id=477320).
+
+Gamestates is a way of organizing your intros, menus, levels.
+
+Gamestates aren't complicated. In Chingu a GameState is a class that behaves mostly like your default Gosu::Window (or in our case Chingu::Window) gameloop.
+
+
+ class Intro < Chingu::GameState
+ def update
+ # gamelogic here
+ end
+
+ def draw
+ # screen manipulation here
+ end
+
+ def button_down(id)
+ # called when a button is pressed
+ end
+
+ def finalize
+ push_gamestate(Menu.new) # Called when Intro dies for whatever reason.
+ end
+
+ # etc etc
+ end
+
+Looks familiar ye?
+Active that gamestate/gameloop in your mainwindow (which is always the spider in the net).
+
+ class Game < Chingu::Window
+ def initialize
+ push_gamestate(Intro.new)
+ end
+ end
+
+A GameState in Chingu is just a class with the following instancemethods:
+
+* setup() - called when gamestate becomes active (switch_gamestate(gamestate) for example)
+* button_down(id) - Called when a button is down
+* button_up(id) - Called when a button is released
+* update() - just as in your normal gameloop, put your gamelogic here.
+* draw() - just as in your normal gameloop, pur your draws here.
+* finalize() - called when a gamestate is finished
+
+Chingu::Window automaticly creates a @game_state_manager and makes it accessible in our gameloop.
+By default the gameloop calls update() / draw() on the the current gamestate.
+
+Chingu also has a couple of helpers to easy change between gamestates.
+In a mainloop or in a gamestate:
+* push_gamestate(state) - adds a new gamestate, which then becomes the active one
+* pop_gamestate - removes active gamestate and activates the previous one
+* switch_gamestate(state) - pop all gamestates until given state is found
+
+To switch to a certain gamestate with a keypress use Chingus keymapper:
+ class Intro < Chingu::GameState
+ def setup
+ self.keymap = { :space => lambda{push_gamestate(Menu.new)} }
+ end
+ end
+
+Or Chingus pretty shortcut:
+
+ class Intro < Chingu::GameState
+ def setup
+ self.keymap = { :space => Menu } # { :space => Menu.new } works as well.
+ end
+ end
+
+Chingu will detect that Menu is a gamestate-class and call push_gamestate on it when space is pressed inside Intro.
=== Assets / Paths
@@ -176,31 +247,42 @@ You'll get $window.root (equivalent to ROOT_PATH above) for free though which po
== TODO:
* Complete the keymap-definitions with all possible keys
+* Complete keymap-stuff with released-states etc
* More gfx effects, for example: fade in/out to a specific color (black makes sense between levels).
* Summon good proven community gosu snippets into Chingu
-* Generate docs @ ippa.github.com
-* A good scene-manager to manage welcomescreens, levels and gameflow
+* -Generate docs @ ippa.github.com- http://rdoc.info/projects/ippa/chingu !
+* -A good scene-manager to manage welcomescreens, levels and gameflow- GameStateManager / GameState !
* More docs
-* Make a gem
+* -Make a gem- first gem made on github
+* Automate gemgenning rake-task even more
* More examples when effects are more complete
* class ChipmunkObject
-* class Actor/MovingActor (?). Would ppl find is useful?
+* class Actor/MovingActor with maybe abit more logic then the basic GameObject. Would ppl find is useful?
+* Spellcheck all docs, sloppy spelling turns ppl off.
* Tests
+* Streamline fps / tick code
+* Encapsulate Font.new / draw_rot with a "class Text < GameObject"
+* Make it possible for ppl to use the parts of chingu they like
+* A more robust gamestate <-> game_object system to connect them together.
== WHY?
-* Plain gosu is very minimalistic
+* Plain gosu is very minimalistic, perfect to build some higherlevel logic on!
* Deployment and assethandling should be simple
+* Managing gamestates/scenes (intros, menus, levels etc) should be simple
* There are patterns in gamedevelopment
== OPINIONS
* Less code is usually better
* Hasharguments FTW. And it becomes even better in 1.9.
-* Don't separate too much from Gosus core-naming and functionallity
-* Make it possible for ppl to use the parts of chingu they like
+* Don't separate too much from Gosus core-naming
== CREDITS:
Jacius of Rubygame (For doing cool stuff that's well documented as re-usable). So far rect.rb and named_resource.rb is taken from Rubygame.
+jlnr,philymore,shawn24 for contructive feedback
+
+
+
== REQUIREMENTS:
* Gosu latest version
* Ruby 1.8/1.9
View
@@ -0,0 +1,93 @@
+require 'rubygems'
+require '../lib/chingu.rb'
+include Gosu
+
+#
+# GameState example
+#
+class Game < Chingu::Window
+ def initialize
+ super
+ push_gamestate(Intro.new)
+ end
+end
+
+#
+# Our Player
+#
+class Player < Chingu::GameObject
+ def move_left; @x -= 1; end
+ def move_right; @x += 1; end
+ def move_up; @y -= 1; end
+ def move_down; @y += 1; end
+end
+
+#
+# GAMESTATE #1 - INTRO
+#
+class Intro < Chingu::GameState
+ def setup
+ @font = Gosu::Font.new($window, "verdana", 30)
+ self.keymap = { :space => Menu, :escape => :close }
+ end
+
+ def draw
+ @font.draw("Intro... (press space)", 200, 50, 10)
+ end
+end
+
+#
+# GAMESTATE #2 - MENU
+#
+class Menu < Chingu::GameState
+ def setup
+ @font = Gosu::Font.new($window, "verdana", 30)
+ self.keymap = { :m => Level.new(:level => 10) }
+ end
+
+ def draw
+ @font.draw("GameState Menu (press 'm')", 200, 50, 10)
+ end
+end
+
+#
+# GAMESTATE #3 - LEVEL (Gameplay, yay)
+#
+class Level < Chingu::GameState
+ def setup
+ #
+ # FIX: :p => Pause.new would Change the "inside_game_state" to Pause and make @player belong to Pause.
+ #
+ @font = Gosu::Font.new($window, "verdana", 30)
+ @player = Player.new(:x => 200, :y => 200, :image => Image["spaceship.png"])
+ @player.keymap = {:left => :move_left, :right => :move_right, :up => :move_up, :down => :move_down, :left_ctrl => :fire}
+ self.keymap = {:p => Pause, :escape => :close}
+ end
+
+ def draw
+ @font.draw("Level #{options[:level].to_s}. Pause with 'P'", 200, 10, 10)
+ super
+ end
+end
+
+#
+# SPECIAL GAMESTATE - Pause
+#
+class Pause < Chingu::GameState
+ def setup
+ @font = Gosu::Font.new($window, "verdana", 40)
+ self.keymap = { :u => :un_pause }
+ end
+
+ # Return the previous gamestate
+ def un_pause
+ pop_gamestate
+ end
+
+ def draw
+ previous_gamestate.draw # Draw prev gamestate onto screen
+ @font.draw("PAUSED (press 'u' to continue)", 10, 200, 10)
+ end
+end
+
+Game.new.show
View
@@ -5,7 +5,10 @@
require 'rubygems'
require 'gosu'
-%w{ window
+%w{ helpers
+ game_state_manager
+ game_state
+ window
fpscounter
named_resource
assets
@@ -21,5 +24,5 @@
end
module Chingu
- VERSION = "0.0.1"
+ VERSION = "0.0.2"
end
View
@@ -6,6 +6,8 @@ module Chingu
# All objects that inherits from this class will automaticly be updated and drawn.
#
class GameObject
+ #include Chingu::KeymapHelpers
+
attr_accessor :image, :x, :y, :angle, :center_x, :center_y, :factor_x, :factor_y, :mode
attr_accessor :update, :draw, :keymap
attr_reader :options
@@ -71,47 +73,35 @@ def initialize(options = {})
@factor_y = options[:factor_y] || options[:factor] || @@factor_y
@mode = options[:mode] || :additive
- # gameloop logic
+ # gameloop/framework logic
@update = options[:update] || true
@draw = options[:draw] || true
+ @keymap = options[:keymap] || nil
- automatic_update! if @update
- automatic_draw! if @draw
- end
-
- #
- # Add self to the list of objects that Chingu calls #update on each update-loop.
- # This is done by default except if you create a gameobject with {:update => false}
- #
- def automatic_update!
- $window.automatic_update_for(self)
- end
- #
- # Add self to the list of objects that Chingu calls #draw on each update-loop.
- # This is done by default except if you create a gameobject with {:draw => false}
- #
- def automatic_draw!
- $window.automatic_draw_for(self)
+ #
+ # A GameObject can either belong to a GameState or our mainwindow ($window)
+ # .. or live in limbo with manual updates
+ #
+ @parent = $window.game_state_manager.inside_state || $window
+ @parent.add_game_object(self) if @parent
+
+ #puts "-----------"
+ #puts @parent.class
+ #puts self.class
+ #puts "-----------"
end
- def keymap=(keymap)
- @keymap = keymap
- $window.key_recievers << self unless $window.key_recievers.include? self
- end
- #
- # Override this with your own game-logic
- #
def update
-
+ # Objects gamelogic here
end
#
# The core of the gameclass, the draw_rot encapsulation. Draws the sprite on screen.
# Calling #to_i on @x and @y enables thoose to be Float's, for subpixel slow movement in #update
#
def draw
- @image.draw_rot(@x.to_i, @y.to_i, @zorder, @angle, @center_x, @center_y, @factor_x, @factor_y, @mode)
+ @image.draw_rot(@x.to_i, @y.to_i, @zorder, @angle, @center_x, @center_y, @factor_x, @factor_y)
end
end
end
View
@@ -0,0 +1,39 @@
+module Chingu
+ class GameState
+ include Chingu::GameStateHelpers # Easy access to the global game_state-queue
+ include Chingu::DrawHelpers # Adds fill(), fade() etc to each gamestate.
+
+ attr_reader :options # so jac can access his :level-number
+ attr_reader :game_objects
+ attr_accessor :keymap
+
+ def initialize(options = {})
+ @options = options
+ @game_objects = Array.new
+ @keymap = nil
+ $window.game_state_manager.inside_state = self
+ setup
+ end
+
+ def add_game_object(game_object)
+ @game_objects.push(game_object) unless @game_objects.include?(game_object)
+ end
+
+ def setup
+ end
+
+ def button_down(id)
+ end
+
+ def button_up(id)
+ end
+
+ def update
+ @game_objects.each { |object| object.update }
+ end
+
+ def draw
+ @game_objects.each { |object| object.draw }
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit 7619f4f

Please sign in to comment.