ippa-chingu 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,5 +1,8 @@
1
+ === 0.0.3 / 2009-08-14
2
+ Too much to list. remade inputsystem. gamestates are better. window.rb is cleaner. lots of small bugfixes. Bigger readme.
3
+
1
4
  === 0.0.2 / 2009-08-10
2
5
  tons of new stuff and fixes. complete keymap. gamestate system. moreexamples/docs. better game_object.
3
6
 
4
7
  === 0.0.1 / 2009-08-05
5
- first release
8
+ first release
data/README.rdoc CHANGED
@@ -34,17 +34,27 @@ Chingu consists of the following core classes:
34
34
  The main window, use it at you use Gosu::Window.
35
35
 
36
36
  === Chingu::GameObject
37
- Use for your in game objects, got everything to put them on the screen.
37
+ Use for all your in game objects. The player, the enemies, the bullets, the powerups, the loot laying around.
38
+ It's very reusable and doesn't contain any game-logic (that's up to you!). Only stuff to put it on screen a certain way.
39
+ It also gives you a couple of bonuses with chingu, as automatic updates/draws and easier input-mapping.
38
40
  Has either Chingu::Window or a Chingu::GameState as "owner".
39
41
 
40
42
  === Chingu::Text
41
- Makes use of Gosu::Font more rubyish and powerful
43
+ Makes use of Gosu::Font more rubyish and powerful.
44
+ In it's core, another Chingu::GameObject + Gosu::Font.
45
+
46
+ === Chingu::GameStateManager
47
+ Keeps track of the game states. Implements a stack-based system with push_game_state and pop_game_state.
42
48
 
43
49
  === Chingu::GameState
44
- A "standalone game loop" that can be switched on/off to control game flow.
50
+ A "standalone game loop" that can be activated and deactivated to control game flow.
51
+ A game state is very much like a main gosu window. You define update() and draw() in a gamestate.
52
+ It comes with 2 extras that main window doesn't have. #setup (called when activated) and #finalize (called when deactivated)
53
+
54
+ If using game states, the flow of draw/update/button_up/button_down is:
55
+ Chingu::Window --> Chingu::GameStateManager --> Chingu::GameState.
56
+ For example, inside game state Menu you call push_game_state(Level). When Level exists, it will go back to Menu.
45
57
 
46
- === Chingu::GameStateManager
47
- Keeps track of the game states. The flow of draw/update/button_down is Chingu::Window --> Chingu::GameStateManager --> Chingu::GameState.
48
58
 
49
59
  == THE BASICS
50
60
 
@@ -105,10 +115,10 @@ Chingu doesn't change any fundamental concept of Gosu, but it will make the abov
105
115
  #
106
116
  class Game < Chingu:Window
107
117
  def initialize
108
- super # This is always needed
118
+ super # This is always needed if you want to take advantage of what chingu offers
109
119
  #
110
120
  # Player will automaticly be updated and drawn since it's a Chingu::GameObject
111
- # You'll need your own Game#update/#draw after a while, but just put #super there and Chingu can do its thing!
121
+ # You'll need your own Game#update/#draw after a while, but just put #super there and Chingu can do its thing.
112
122
  #
113
123
  @player = Player.new
114
124
  @player.input = {:left => :move_left, :right => :move_right}
@@ -178,6 +188,65 @@ I've chose to base it around Image#draw_rot. So basically all the arguments that
178
188
  #
179
189
  @player = Player.new(:draw => false, :update => false)
180
190
 
191
+ === Input
192
+ One of the core things I wanted a more natural way of inputhandling.
193
+ You can define input -> actions on Chingu::Window, Chingu::GameState and Chingu::GameObject.
194
+ Like this:
195
+
196
+ #
197
+ # When left arrow is pressed, call @player.turn_left ... and so on.
198
+ #
199
+ @player.input = { :left => :turn_left, :right => :turn_right, :left => :halt_left, :right => :halt_right }
200
+
201
+
202
+ #
203
+ # In Gosu the equivalent would be:
204
+ #
205
+ def button_down(id)
206
+ @player.turn_left if id == Button::KbLeft
207
+ @player.turn_right if id == Button::KbRight
208
+ end
209
+
210
+ def button_up(id)
211
+ @player.halt_left if id == Button::KbLeft
212
+ @player.halt_right if id == Button::KbRight
213
+ end
214
+
215
+
216
+ Another more complex example:
217
+
218
+ #
219
+ # So what happens here?
220
+ #
221
+ # Pressing P would create an game state out of class Pause, cache it and activate it.
222
+ # Pressing ESC would call Play#close
223
+ # Holding down LEFT would call Play#move_left on every game iteration
224
+ # Holding down RIGHT would call Play#move_right on every game iteration
225
+ # Relasing SPACE would call Play#fire
226
+ #
227
+
228
+ class Play < Chingu::GameState
229
+ def initialize
230
+ self.input = { :p => Pause, :escape => :close, :holding_left => :move_left, :holding_right => :move_right, :released_space => :fire }
231
+ end
232
+ end
233
+ class Pause < Chingu::GameState
234
+ # pause logic here
235
+ end
236
+
237
+ In Gosu the above code would include code in button_up(), button_down() and a check for button_down?() in update().
238
+
239
+ Every symbol can be prefixed by either "released_" or "holding_" while no prefix at all defaults to pressed once.
240
+ So, why not :up_space or :relase_space instead of :released_space?
241
+ Or :hold_left or :down_left instead of :holding_left?
242
+
243
+ :up_space doesn't sound like english, :release_space sounds more like a command then an event.
244
+
245
+ :holding_left sounds like something that's happening over a period of time, not a single trigger, which corresponds good to what's happening when using it.
246
+
247
+ And with the default :space => :something youd imagine that :something is called once. You press :space once, :something get's executed once.
248
+
249
+
181
250
  === GameState / GameStateManager
182
251
  Chingu incorporates a basic push/pop game state system (as discussed here: http://www.gamedev.net/community/forums/topic.asp?topic_id=477320).
183
252
 
@@ -186,7 +255,9 @@ Game states is a way of organizing your intros, menus, levels.
186
255
  Game states aren't complicated. In Chingu a GameState is a class that behaves mostly like your default Gosu::Window (or in our case Chingu::Window) game loop.
187
256
 
188
257
 
258
+ # A simple GameState-example
189
259
  class Intro < Chingu::GameState
260
+
190
261
  def update
191
262
  # game logic here
192
263
  end
@@ -194,44 +265,62 @@ Game states aren't complicated. In Chingu a GameState is a class that behaves mo
194
265
  def draw
195
266
  # screen manipulation here
196
267
  end
197
-
198
- def button_down(id)
199
- # called when a button is pressed
268
+
269
+ # Called when we enter the game state
270
+ def setup
271
+ @player.angle = 0 # point player upwards
200
272
  end
201
273
 
274
+ # Called when we leave the current game state
202
275
  def finalize
203
- push_gamestate(Menu.new) # Called when Intro dies for whatever reason.
276
+ push_game_state(Menu) # switch to game state "Menu"
204
277
  end
205
-
206
- # etc etc
278
+
207
279
  end
208
280
 
209
281
  Looks familiar ye?
210
- Active that game state/game loop in your main window (which is always the spider in the net).
282
+ You can activate the above game state in 2 ways
211
283
 
212
284
  class Game < Chingu::Window
213
285
  def initialize
214
- push_gamestate(Intro.new)
286
+ #
287
+ # 1) Create a new Intro-object and activate it (pushing to the top).
288
+ # This version makes more sense if you want to pass parameters to the gamestate, for example:
289
+ # push_game_state(Level.new(:level_nr => 10))
290
+ #
291
+ push_game_state(Intro.new)
292
+
293
+ #
294
+ # 2) This leaves the actual object-creation to the game state manager.
295
+ # This results in only 1 object is ever created of class 'Intro'.
296
+ # The second time 'push_game_state(Intro)' is called, it will re-use the last one.
297
+ # This means code in Intro#initialize() is only called once, Intro#setup() is called everytime Intro is activated though.
298
+ #
299
+ push_game_state(Intro)
215
300
  end
216
301
  end
217
302
 
218
303
  A GameState in Chingu is just a class with the following instance methods:
219
304
 
220
- * setup() - called when game state becomes active (switch_gamestate(gamestate) for example)
305
+ * initialize() - called only once with push_game_state(Intro) but everytime with push_game_state(Intro.new)
306
+ * setup() - called each time the game state becomes active.
221
307
  * button_down(id) - Called when a button is down
222
308
  * button_up(id) - Called when a button is released
223
309
  * update() - just as in your normal game loop, put your game logic here.
224
310
  * draw() - just as in your normal game loop, put your screen manipulation here.
225
- * finalize() - called when a game state is finished
311
+ * finalize() - called when a game state de-activated (for example by pushing a new one on top with push_game_state)
226
312
 
227
313
  Chingu::Window automatically creates a @game_state_manager and makes it accessible in our game loop.
228
314
  By default the game loop calls update() / draw() on the the current game state.
229
315
 
230
- Chingu also has a couple of helpers to easy change between game states.
316
+ Chingu also has a couple of helpers-methods for handling the game states:
231
317
  In a main loop or in a game state:
232
- * push_gamestate(state) - adds a new gamestate, which then becomes the active one
233
- * pop_gamestate - removes active gamestate and activates the previous one
234
- * switch_gamestate(state) - pop all gamestates until given state is found
318
+ * push_game_state(state) - adds a new gamestate on top of the stack, which then becomes the active one
319
+ * pop_game_state - removes active gamestate and activates the previous one
320
+ * current_game_state - returns the current game state
321
+ * previous_game_state - returns the previous game state (useful for pausing and dialog boxes, see example4.rb)
322
+ * pop_until_game_state(state) - pop game states until given state is found
323
+ * clear_game_states - removes all game states from stack
235
324
 
236
325
  To switch to a certain gamestate with a keypress use Chingus input handler:
237
326
  class Intro < Chingu::GameState
@@ -240,15 +329,15 @@ To switch to a certain gamestate with a keypress use Chingus input handler:
240
329
  end
241
330
  end
242
331
 
243
- Or Chingus pretty shortcut:
332
+ Or Chingus shortcut:
244
333
 
245
334
  class Intro < Chingu::GameState
246
335
  def setup
247
- self.input = { :space => Menu } # { :space => Menu.new } works as well.
336
+ self.input = { :space => Menu } # or { :space => Menu.new } if you want to create a new object each time.
248
337
  end
249
338
  end
250
339
 
251
- Chingu will detect that Menu is a gamestate-class and call push_gamestate on it when space is pressed inside Intro.
340
+ Chingus inputhandler will detect that Menu is a gamestate-class, create a new instance, cache it and activate it with push_game_state().
252
341
 
253
342
  === Assets / Paths
254
343
 
@@ -285,12 +374,13 @@ It's not only that the second example is readable by ppl now even familiar with
285
374
 
286
375
  == TODO:
287
376
  * (done) Complete the input-definitions with all possible inputs (keyboard, gamepad, mouse)!
288
- * Complete input-stuff with released-states etc
377
+ * (done) Complete input-stuff with released-states etc
289
378
  * More gfx effects, for example: fade in/out to a specific color (black makes sense between levels).
290
- * Summon good proven community gosu snippets into Chingu
379
+ * (posted request on forums) Summon good proven community gosu snippets into Chingu
291
380
  * (done) Generate docs @ ippa.github.com- http://rdoc.info/projects/ippa/chingu !
292
381
  * (done) A good scene-manager to manage welcome screens, levels and game flow- GameStateManager / GameState !
293
382
  * More docs
383
+ * make a playable simple game in examples\ that really depends on game states
294
384
  * (done) Make a gem- first gem made on github
295
385
  * Automate gemgenning rake-task even more
296
386
  * More examples when effects are more complete
@@ -298,14 +388,14 @@ It's not only that the second example is readable by ppl now even familiar with
298
388
  * class Actor/MovingActor with maybe abit more logic then the basic GameObject. Would ppl find is useful?
299
389
  * Spell check all docs, sloppy spelling turns ppl off.
300
390
  * Tests
301
- * Streamline fps / tick code
391
+ * (done) Streamline fps / tick code
302
392
  * (done) Encapsulate Font.new / draw_rot with a "class Text < GameObject"
303
- * Make it possible for ppl to use the parts of Chingu they like
393
+ * (10% done) Make it possible for ppl to use the parts of Chingu they like
304
394
  * A more robust game state <-> game_object system to connect them together.
305
395
  * Get better at styling rdocs
306
- * all �gamestate� ? �game state� ?
307
- * FIX example4: :p => Pause.new would Change the "inside_game_state" to Pause and make @player belong to Pause.
396
+ * (done) all �gamestate� ? �game state� ? it's "game state"
308
397
  * intergrate rubygame_movie_make (maybe after a rename, GameAutomator? GameSequence?
398
+ * FIX example4: :p => Pause.new would Change the "inside_game_state" to Pause and make @player belong to Pause.
309
399
 
310
400
  == WHY?
311
401
  * Plain Gosu is very minimalistic, perfect to build some higher level logic on!
data/chingu.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{chingu}
5
- s.version = "0.2.0"
5
+ s.version = "0.3.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["ippa"]
9
- s.date = %q{2009-08-10}
9
+ s.date = %q{2009-08-14}
10
10
  s.description = %q{Game framework built on top of the OpenGL accelerated game lib Gosu. It adds simple yet powerfull game states, prettier inputhandling, deploymentsafe asset-handling, a basic re-usable game object and automation of common task.}
11
11
  s.email = ["ippa@rubylicio.us"]
12
12
  s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
@@ -24,11 +24,11 @@ Gem::Specification.new do |s|
24
24
  s.specification_version = 2
25
25
 
26
26
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
- s.add_development_dependency(%q<hoe>, [">= 2.3.2"])
27
+ s.add_development_dependency(%q<hoe>, [">= 2.3.3"])
28
28
  else
29
- s.add_dependency(%q<hoe>, [">= 2.3.2"])
29
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
30
30
  end
31
31
  else
32
- s.add_dependency(%q<hoe>, [">= 2.3.2"])
32
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
33
33
  end
34
34
  end
data/examples/example1.rb CHANGED
@@ -15,7 +15,13 @@ class Game < Chingu::Window
15
15
  def initialize
16
16
  super
17
17
  @player = Player.new(:x => 200, :y => 200, :image => Image["spaceship.png"])
18
- @player.input = {:left => :move_left, :right => :move_right, :up => :move_up, :down => :move_down}
18
+ @player.input = { :holding_left => :move_left, :holding_right => :move_right,
19
+ :holding_up => :move_up, :holding_down => :move_down}
20
+ end
21
+
22
+ def update
23
+ super
24
+ self.caption = "FPS: #{self.fps} milliseconds_since_last_tick: #{self.milliseconds_since_last_tick}"
19
25
  end
20
26
  end
21
27
 
data/examples/example2.rb CHANGED
@@ -15,7 +15,11 @@ class Game < Chingu::Window
15
15
  super
16
16
 
17
17
  @player = Player.new(:x => 200, :y => 200, :image => Image["spaceship.png"])
18
- @player.input = {:left => :move_left, :right => :move_right, :up => :move_up, :down => :move_down, :space => :fire}
18
+ @player.input = { :holding_left => :move_left,
19
+ :holding_right => :move_right,
20
+ :holding_up => :move_up,
21
+ :holding_down => :move_down,
22
+ :space => :fire}
19
23
  end
20
24
 
21
25
  #
@@ -43,18 +47,23 @@ class Game < Chingu::Window
43
47
 
44
48
  end
45
49
 
50
+ #
51
+ # Our Player
52
+ #
46
53
  class Player < Chingu::GameObject
54
+ def initialize(options = {})
55
+ super
56
+ @image = Image["spaceship.png"]
57
+ end
58
+
47
59
  def move_left; @x -= 1; end
48
60
  def move_right; @x += 1; end
49
61
  def move_up; @y -= 1; end
50
- def move_down; @y += 1; end
51
-
62
+ def move_down; @y += 1; end
63
+
52
64
  def fire
53
65
  Bullet.new(:x => @x, :y => @y)
54
- end
55
-
56
- def update
57
- end
66
+ end
58
67
  end
59
68
 
60
69
  class Bullet < Chingu::GameObject
@@ -67,7 +76,7 @@ class Bullet < Chingu::GameObject
67
76
  end
68
77
 
69
78
  # Move the bullet forward
70
- def update
79
+ def update(time)
71
80
  @y -= 2
72
81
  end
73
82
 
data/examples/example3.rb CHANGED
@@ -9,7 +9,7 @@ include Gosu
9
9
  class Game < Chingu::Window
10
10
  def initialize
11
11
  super
12
- self.input = {:left => :scroll_left, :right => :scroll_right, :escape => :close}
12
+ self.input = {:holding_left => :scroll_left, :holding_right => :scroll_right, :escape => :close}
13
13
 
14
14
  @parallax = Chingu::Parallax.new(:x => 0, :y => 0, :center_x => 0, :center_y => 0)
15
15
 
data/examples/example4.rb CHANGED
@@ -5,7 +5,7 @@ include Gosu
5
5
  #
6
6
  # Example demonstrating jumping between 4 different game states.
7
7
  #
8
- # push_gamestate, pop_gamestate and previous_gamestate are 3 helpers that Chingu mixes in
8
+ # push_game_state, pop_game_state, current_game_state previous_game_state are 4 helper-methods that Chingu mixes in
9
9
  # into Chingu::Window and Chingu::GameState
10
10
  #
11
11
  # Behind the scenes they work against @game_state_manager that's autocreated within Chingu::Window.
@@ -19,7 +19,7 @@ include Gosu
19
19
  #
20
20
  # 3) @game_state_manager calls draw / update on the current active game state
21
21
  #
22
- # 4) Each gamestate keeps a collection @game_objects which it calls draw / update on.
22
+ # 4) Each game state keeps a collection @game_objects which it calls draw / update on.
23
23
  # Any object based on Chingu::GameObject (In this example Player and Text) automatically
24
24
  # gets added to the correct state or or main window.
25
25
  #
@@ -29,19 +29,18 @@ include Gosu
29
29
  #
30
30
  class Game < Chingu::Window
31
31
  def initialize
32
- super
33
- push_gamestate(Intro)
32
+ super
33
+
34
+ push_game_state(Intro)
34
35
 
35
36
  # Yes you can do crazy things like this :)
36
- self.input = { :left_mouse_button => lambda{Chingu::Text.new(:text => "Woff!")}}
37
+ self.input = { :left_mouse_button => lambda{Chingu::Text.new(:text => "Woff!")}, :esc => :close}
37
38
  end
38
39
  end
39
40
 
40
- #
41
- # Our Player
42
- #
41
+ # Our Player
43
42
  class Player < Chingu::GameObject
44
- def initialize(options)
43
+ def initialize(options = {})
45
44
  super
46
45
  @image = Image["spaceship.png"]
47
46
  end
@@ -49,16 +48,42 @@ class Player < Chingu::GameObject
49
48
  def move_left; @x -= 1; end
50
49
  def move_right; @x += 1; end
51
50
  def move_up; @y -= 1; end
52
- def move_down; @y += 1; end
51
+ def move_down; @y += 1; end
52
+
53
+ def fire
54
+ Bullet.new(:x => @x, :y => @y)
55
+ end
56
+ end
57
+
58
+ # The bullet the Player fires
59
+ class Bullet < Chingu::GameObject
60
+ def initialize(options)
61
+ super
62
+ @image = Image["fire_bullet.png"]
63
+ end
64
+
65
+ def update(time)
66
+ @y -= 2
67
+ end
53
68
  end
54
69
 
70
+
55
71
  #
56
72
  # GAMESTATE #1 - INTRO
57
73
  #
58
74
  class Intro < Chingu::GameState
59
- def setup
60
- @title = Chingu::Text.new(:text=>"Intro (press space)", :x=>200, :y=>50, :size=>30)
61
- self.input = { :space => Menu, :escape => :close }
75
+ def initialize(options)
76
+ super
77
+ @title = Chingu::Text.new(:text=>"Press and release F1", :x=>200, :y=>50, :size=>30)
78
+ self.input = { :f1 => :pressed, :released_f1 => :released, :f2 => Menu}
79
+ end
80
+
81
+ def pressed
82
+ @title.text = "F1 pressed (F2 to continue)"
83
+ end
84
+
85
+ def released
86
+ @title.text = "F1 released (F2 to continue)"
62
87
  end
63
88
  end
64
89
 
@@ -66,9 +91,10 @@ end
66
91
  # GAMESTATE #2 - MENU
67
92
  #
68
93
  class Menu < Chingu::GameState
69
- def setup
70
- @title = Chingu::Text.new(:text => "GameState Menu (press 'm')", :x => 200, :y => 50, :size=>30)
71
- self.input = { :m => Level.new(:level => 10) }
94
+ def initialize(options)
95
+ super
96
+ @title = Chingu::Text.new(:text => "Press 'S' to Start game", :x=>100, :y=>50, :size=>30)
97
+ self.input = { :s => Level.new(:level => 10) }
72
98
  end
73
99
  end
74
100
 
@@ -76,34 +102,56 @@ end
76
102
  # GAMESTATE #3 - LEVEL (Gameplay, yay)
77
103
  #
78
104
  class Level < Chingu::GameState
79
- def setup
80
- @title = Chingu::Text.new(:text=>"Level #{options[:level].to_s}. Pause with 'P'", :x=>200, :y=>10, :size => 30)
81
- @player = Player.new(:x => 200, :y => 200)
82
- @player.input = {:left => :move_left, :right => :move_right, :up => :move_up, :down => :move_down, :left_ctrl => :fire}
105
+ #
106
+ # initialize() is called when you create the game state
107
+ #
108
+ def initialize(options)
109
+ super
110
+ @title = Chingu::Text.new(:text=>"Level #{options[:level].to_s}. P: pause R:restart", :x=>20, :y=>10, :size=>30)
111
+ @player = Player.new
112
+ @player.input = { :holding_left => :move_left,
113
+ :holding_right => :move_right,
114
+ :holding_up => :move_up,
115
+ :holding_down => :move_down,
116
+ :left_ctrl => :fire}
83
117
 
84
118
  #
85
119
  # The input-handler understands gamestates. P is pressed --> push_gamegate(Pause)
120
+ # You can also give it Procs/Lambdas which it will execute when key is pressed.
86
121
  #
87
- self.input = {:p => Pause, :escape => :close}
88
- end
122
+ self.input = {:p => Pause, :r => lambda{ current_game_state.setup } }
123
+ end
124
+
125
+ #
126
+ # setup() is called each time you switch to the game state (and on creation time).
127
+ # You can skip setup by switching with push_game_state(:setup => false) or pop_game_state(:setup => false)
128
+ #
129
+ # This can be useful if you want to display some kind of box above the gameplay (pause/options/info/... box)
130
+ #
131
+ def setup
132
+ # Place player in a good starting position
133
+ @player.x = $window.width/2
134
+ @player.y = $window.height - @player.image.height
135
+ end
89
136
  end
90
137
 
91
138
  #
92
139
  # SPECIAL GAMESTATE - Pause
93
140
  #
94
141
  class Pause < Chingu::GameState
95
- def setup
142
+ def initialize(options)
143
+ super
96
144
  @title = Chingu::Text.new(:text=>"PAUSED (press 'u' to un-pause)", :x=>100, :y=>200, :size=>20, :color => Color.new(0xFF00FF00))
97
145
  self.input = { :u => :un_pause }
98
146
  end
99
147
 
100
148
  def un_pause
101
- pop_gamestate # Return the previous gamestate
149
+ pop_game_state(:setup => false) # Return the previous game state, dont call setup()
102
150
  end
103
151
 
104
152
  def draw
105
- previous_gamestate.draw # Draw prev gamestate onto screen
106
- super # Draw game objects in current game state, this includes Chingu::Texts
153
+ previous_game_state.draw # Draw prev game state onto screen (in this case our level)
154
+ super # Draw game objects in current game state, this includes Chingu::Texts
107
155
  end
108
156
  end
109
157