chingu 0.7.6.6 → 0.7.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/chingu.gemspec +9 -2
  2. data/examples/example11_animation.rb +2 -5
  3. data/examples/example17_gosu_tutorial.rb +2 -2
  4. data/examples/example18_animation_trait.rb +2 -2
  5. data/examples/example19_edit_viewport.rb +6 -3
  6. data/examples/example21.yml +283 -291
  7. data/examples/example21_sidescroller_with_edit.rb +22 -16
  8. data/examples/example22_text.rb +5 -1
  9. data/examples/example23_chipmunk.rb +25 -0
  10. data/examples/example3_parallax.rb +1 -0
  11. data/examples/example4_gamestates.rb +20 -5
  12. data/examples/game1.rb +13 -40
  13. data/lib/chingu.rb +2 -1
  14. data/lib/chingu/assets.rb +2 -2
  15. data/lib/chingu/basic_game_object.rb +1 -23
  16. data/lib/chingu/game_object.rb +21 -0
  17. data/lib/chingu/game_object_map.rb +96 -0
  18. data/lib/chingu/game_states/debug.rb +60 -14
  19. data/lib/chingu/game_states/edit.rb +5 -1
  20. data/lib/chingu/game_states/fade_to.rb +1 -1
  21. data/lib/chingu/helpers/input_client.rb +13 -5
  22. data/lib/chingu/helpers/input_dispatcher.rb +13 -8
  23. data/lib/chingu/helpers/options_setter.rb +33 -0
  24. data/lib/chingu/input.rb +5 -5
  25. data/lib/chingu/rect.rb +2 -0
  26. data/lib/chingu/text.rb +7 -9
  27. data/lib/chingu/traits/animation.rb +1 -0
  28. data/lib/chingu/traits/bounding_box.rb +1 -5
  29. data/lib/chingu/traits/bounding_circle.rb +1 -6
  30. data/lib/chingu/traits/effect.rb +4 -4
  31. data/lib/chingu/traits/retrofy.rb +1 -1
  32. data/lib/chingu/traits/sprite.rb +234 -0
  33. data/lib/chingu/traits/velocity.rb +22 -11
  34. data/lib/chingu/traits/viewport.rb +2 -2
  35. data/lib/chingu/viewport.rb +32 -21
  36. data/lib/chingu/window.rb +6 -5
  37. data/spec/chingu/helpers/options_setter_spec.rb +39 -0
  38. data/spec/spec_helper.rb +3 -0
  39. metadata +12 -5
@@ -26,11 +26,10 @@ class Example21 < GameState
26
26
 
27
27
  def setup
28
28
  self.input = { :escape => :exit, :e => :edit }
29
- self.viewport.game_area = [0, 0, 3000, 1000]
29
+ self.viewport.game_area = [0, 0, 3500, 2000]
30
30
 
31
- @droid = Droid.create(:x => 100, :y => 300)
32
- #@droid = Droid.create(:x => 2500, :y => 1200)
33
- #@droid = Droid.create(:x => 500, :y => 1500)
31
+ @droid = Droid.create(:x => 100, :y => 400)
32
+ #@droid = Droid.create(:x => 400, :y => 1300)
34
33
 
35
34
  load_game_objects
36
35
 
@@ -58,11 +57,14 @@ class Example21 < GameState
58
57
  def update
59
58
  super
60
59
 
61
- visible_blocks = Block.inside_viewport
60
+ visible_blocks = Block
62
61
 
63
- FireBall.each_collision(visible_blocks) do |fire_ball, block|
64
- fire_ball.destroy
65
- end
62
+ #
63
+ # Eating a lot of CPU cause our crude collision detection, just kill fireballs after 3 secs instead.
64
+ #
65
+ # FireBall.each_collision(visible_blocks) do |fire_ball, block|
66
+ # fire_ball.destroy
67
+ # end
66
68
 
67
69
  # Makes all saw pendle up and down between Y-coordinate 1000 - 1500
68
70
  # TODO: Not a very flexible sollution, how about setting out circle,rects,lines in editor..
@@ -78,9 +80,7 @@ class Example21 < GameState
78
80
 
79
81
  @droid.each_collision(Battery) do |player, battery|
80
82
  battery.die
81
- #after(3000) { push_game_state(GameFinished) }
82
83
  end
83
-
84
84
 
85
85
  self.viewport.center_around(@droid)
86
86
 
@@ -153,15 +153,19 @@ class Droid < Chingu::GameObject
153
153
  end
154
154
 
155
155
  def move(x,y)
156
- @x += x
157
- self.each_collision(Block.inside_viewport) do |me, stone_wall|
158
- me.x = previous_x
156
+ self.x += x
157
+ self.each_collision(Block) do |me, stone_wall|
158
+ self.x = previous_x
159
+ break
159
160
  end
161
+
162
+ self.y += y
160
163
  end
161
164
 
162
- def update
165
+ def update
163
166
  @image = @animation.next
164
- self.each_collision(Block.inside_viewport) do |me, stone_wall|
167
+
168
+ self.each_collision(Block) do |me, stone_wall|
165
169
  if self.velocity_y < 0 # Hitting the ceiling
166
170
  me.y = stone_wall.bb.bottom + me.image.height * self.factor_y
167
171
  self.velocity_y = 0
@@ -217,7 +221,7 @@ end
217
221
  # A FIREBALL
218
222
  #
219
223
  class FireBall < GameObject
220
- traits :velocity, :collision_detection
224
+ traits :velocity, :collision_detection, :timer
221
225
  trait :bounding_circle, :scale => 0.7
222
226
 
223
227
  def setup
@@ -228,6 +232,7 @@ class FireBall < GameObject
228
232
  self.velocity_y = 1
229
233
  self.zorder = 200
230
234
  self.rotation_center = :center
235
+ after(3000) { self.destroy }
231
236
  end
232
237
 
233
238
  def update
@@ -288,6 +293,7 @@ class Block < GameObject
288
293
 
289
294
  def setup
290
295
  @image = Image["black_block.png"]
296
+ @color = Color.new(0xff808080)
291
297
  end
292
298
  end
293
299
 
@@ -29,7 +29,11 @@ class Woff < GameState
29
29
 
30
30
  #
31
31
  # TODO: More text examples!
32
- #
32
+ #
33
+
34
+ t = Text.create("Scaletest", :x => 10, :y => 100)
35
+ t.factor_x = 2
36
+ t.factor_y = 1
33
37
  end
34
38
 
35
39
  def draw
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require File.join(File.dirname($0), "..", "lib", "chingu")
4
+ include Gosu
5
+ include Chingu
6
+
7
+
8
+ class Game < Chingu::Window
9
+ def initialize
10
+ super(640,480,false) # leave it blank and it will be 800,600,non fullscreen
11
+ self.input = { :escape => :exit } # exits example on Escape
12
+
13
+ Player.create(:x => 0, :y => 0, :rotation_center => :top_left)
14
+ end
15
+ end
16
+
17
+ class Player < BasicGameObject
18
+ trait :sprite, :image => "spaceship.png"
19
+
20
+ def setup
21
+ end
22
+ end
23
+
24
+
25
+ Game.new.show
@@ -16,6 +16,7 @@ class Game < Chingu::Window
16
16
  end
17
17
 
18
18
  class Scroller < Chingu::GameState
19
+
19
20
  def initialize(options)
20
21
  super
21
22
  @text_color = Color.new(0xFF000000)
@@ -114,12 +114,17 @@ class Level < Chingu::GameState
114
114
  super
115
115
  @title = Chingu::Text.create(:text=>"Level #{options[:level].to_s}. P: pause R:restart", :x=>20, :y=>10, :size=>30)
116
116
  @player = Player.create
117
- @player.input = { :holding_left => :move_left,
118
- :holding_right => :move_right,
119
- :holding_up => :move_up,
120
- :holding_down => :move_down,
121
- :space => :fire}
122
117
 
118
+ #
119
+ # The below code can mostly be replaced with the use of method "holding?" in Level#update
120
+ # Using holding? in update could be good if you need fine grained controll over when input is dispatched.
121
+ #
122
+ @player.input = { :holding_left => :move_left,
123
+ :holding_right => :move_right,
124
+ :holding_up => :move_up,
125
+ :holding_down => :move_down,
126
+ :space => :fire }
127
+
123
128
  #
124
129
  # The input-handler understands gamestates. P is pressed --> push_gamegate(Pause)
125
130
  # You can also give it Procs/Lambdas which it will execute when key is pressed.
@@ -129,6 +134,16 @@ class Level < Chingu::GameState
129
134
 
130
135
  def update
131
136
  super
137
+
138
+ #
139
+ # Another way of checking input
140
+ #
141
+ # @player.move_left if holding?(:left, :a)
142
+ # @player.move_right if holding?(:right, :d)
143
+ # @player.move_up if holding?(:up, :w)
144
+ # @player.move_down if holding?(:down, :s)
145
+ # @player.fire if holding?(:space)
146
+
132
147
  Bullet.destroy_if {|bullet| bullet.outside_window? }
133
148
  $window.caption = "FPS: #{$window.fps} - GameObjects: #{game_objects.size} - Bullets: #{Bullet.size}"
134
149
  end
@@ -1,27 +1,21 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
3
  #
4
- # A "full" simple game in Chingu, using GameState, GameObject, Paralaxx, has_traits etc
4
+ # A simple game in Chingu, using GameState, GameObject, Paralaxx, has_traits etc
5
5
  #
6
- # TODO: clean up code as Chingu moves along :). Comments. Get it working ;).
7
- #
8
6
  #
9
7
  require 'rubygems'
10
8
  require File.join(File.dirname($0), "..", "lib", "chingu")
11
9
  require 'texplay' # adds Image#get_pixel
12
- #require 'opengl' # adds raw gl stuff so Image#retrofy works (in some setups this seems to be 'gl')
13
10
 
14
11
  include Gosu
15
12
  include Chingu
16
13
 
17
- class Game < Chingu::Window
18
- #attr_reader :factor
19
-
14
+ class Game < Chingu::Window
20
15
  def initialize
21
16
  super(1000,400,false)
22
17
  self.input = { :escape => :exit }
23
- self.factor = 1
24
- Gosu::enable_undocumented_retrofication
18
+ retrofy
25
19
  switch_game_state(Level)
26
20
  end
27
21
  end
@@ -37,12 +31,8 @@ class Level < Chingu::GameState
37
31
  super
38
32
 
39
33
  @parallax = Parallax.create(:rotation_center => :top_left)
40
- #@parallax = Parallax.create(:rotation_center => :center)
41
- @parallax << { :image => "city2.png", :damping => 2}#, :factor => $window.factor }
42
- @parallax << { :image => "city1.png", :damping => 1}#, :factor => $window.factor }
43
- #@parallax.x = $window.width / 2
44
- #@parallax.y = $window.height / 2
45
-
34
+ @parallax << { :image => "city2.png", :damping => 2}
35
+ @parallax << { :image => "city1.png", :damping => 1}
46
36
  @player = Player.create(:x => 30, :y => 10)
47
37
 
48
38
  @bg1 = Color.new(0xFFCE28FF)
@@ -71,13 +61,8 @@ class Level < Chingu::GameState
71
61
  # The foremost layer in our parallax scroller is the collidable terrain
72
62
  #
73
63
  def solid_pixel_at?(x, y)
74
- begin
75
- #pixel = @parallax.layers.last.get_pixel(x/$window.factor, y/$window.factor)
76
- #return false if pixel.nil?
77
- #return
78
-
79
- @parallax.layers.last.get_pixel(x * $window.factor, y * $window.factor)[3] != 0
80
- #@parallax.layers.last.get_pixel(x, y)[3] != 0
64
+ begin
65
+ @parallax.layers.last.get_pixel(x, y)[3] != 0
81
66
  rescue
82
67
  puts "Error in get_pixel(#{x}, #{y})"
83
68
  end
@@ -96,7 +81,7 @@ class Level < Chingu::GameState
96
81
  Bullet.all.select { |o| solid_pixel_at?(o.x, o.y)}.each { |o| o.die }
97
82
 
98
83
  # Collide player with terrain
99
- #push_game_state(GameOver) if solid_pixel_at?(@player.x, @player.y)
84
+ push_game_state(GameOver) if solid_pixel_at?(@player.x, @player.y)
100
85
 
101
86
  # Collide player with enemies and enemy bullets
102
87
  @player.each_bounding_circle_collision(Enemy) do |player, enemy|
@@ -117,9 +102,7 @@ class Level < Chingu::GameState
117
102
  Enemy.create(:x => $window.width, :y => rand(300))
118
103
  @total_ticks = 0
119
104
  end
120
-
121
- #push_game_state(Done.new(:score => @player.score)) if @game_steps == 1
122
-
105
+
123
106
  $window.caption = "City Battle! Player x/y: #{@player.x}/#{@player.y} - Score: #{@player.score} - FPS: #{$window.fps} - game objects: #{game_objects.size}"
124
107
  end
125
108
 
@@ -134,14 +117,13 @@ end
134
117
  #
135
118
  class Player < GameObject
136
119
  has_traits :velocity, :collision_detection, :timer
137
- has_trait :bounding_circle, :scale => 0.50, :debug => true
120
+ has_trait :bounding_circle, :scale => 0.50, :debug => false
138
121
  attr_accessor :score
139
122
 
140
123
  def setup
141
124
  @image = Image["plane.png"]
142
- #self.factor = $window.factor
143
125
 
144
- self.input = {
126
+ self.input = {
145
127
  :holding_left => :left,
146
128
  :holding_right => :right,
147
129
  :holding_up => :up,
@@ -179,8 +161,8 @@ class Player < GameObject
179
161
  self.velocity_y *= 0.6
180
162
  self.velocity_x *= 0.6
181
163
 
182
- @x = @last_x if @x < 0 || @x > $window.width#/$window.factor
183
- @y = @last_y if @y < 0 || @y > $window.height#/$window.factor
164
+ @x = @last_x if @x < 0 || @x > $window.width
165
+ @y = @last_y if @y < 0 || @y > $window.height
184
166
  @last_x, @last_y = @x, @y
185
167
  end
186
168
 
@@ -195,7 +177,6 @@ class Bullet < GameObject
195
177
 
196
178
  def setup
197
179
  @image = Image["bullet.png"]
198
- #self.factor = $window.factor
199
180
  self.velocity_x = 10
200
181
  @status = :default
201
182
  @radius = 3
@@ -208,10 +189,6 @@ class Bullet < GameObject
208
189
  during(50) { @factor_x += 1; @factor_y += 1; @x -= 1; }.then { self.destroy }
209
190
  end
210
191
 
211
- #def update
212
- #return if @status == :dying
213
- #@x += self.velocity_x
214
- #end
215
192
  end
216
193
 
217
194
  #
@@ -238,7 +215,6 @@ class Explosion < GameObject
238
215
  @image = @@image.dup if @image.nil?
239
216
 
240
217
  self.rotation_center = :center
241
- #self.factor = options[:factor] ? options[:factor] : $window.factor
242
218
  during(100) { self.alpha -= 30}.then { destroy }
243
219
  end
244
220
 
@@ -262,7 +238,6 @@ class Shrapnel < GameObject
262
238
  self.velocity_y = 4 - rand(10)
263
239
  self.acceleration_y = 0.2 # gravity = downards acceleration
264
240
  self.rotation_center = :center
265
- #self.factor = $window.factor
266
241
  @status = :default
267
242
  end
268
243
 
@@ -297,10 +272,8 @@ class Enemy < GameObject
297
272
  @health = options[:health] || 100
298
273
 
299
274
  @anim = Animation.new(:file => "media/saucer.png", :size => [32,13], :delay => 100)
300
- # @anim.retrofy
301
275
  @image = @anim.first
302
276
 
303
- #self.factor = $window.factor
304
277
  @radius = 5
305
278
  @black = Color.new(0xFF000000)
306
279
  @status == :default
@@ -33,8 +33,9 @@ require_all "#{CHINGU_ROOT}/chingu/traits"
33
33
  require_all "#{CHINGU_ROOT}/chingu"
34
34
 
35
35
  module Chingu
36
- VERSION = "0.7.6.6"
36
+ VERSION = "0.7.6.7"
37
37
 
38
38
  DEBUG_COLOR = Gosu::Color.new(0xFFFF0000)
39
39
  DEBUG_ZORDER = 9999
40
+ INFINITY = 1.0 / 0
40
41
  end
@@ -33,7 +33,7 @@ module Gosu
33
33
  include Chingu::NamedResource
34
34
 
35
35
  def self.autoload(name)
36
- ret = (path = find_file(name)) ? Gosu::Image.new($window, path, true) : nil
36
+ ret = (path = find_file(name)) ? Gosu::Image.new($window, path, false) : nil
37
37
  raise "Can't load image \"#{name}\"" if ret.nil?
38
38
  return ret
39
39
  end
@@ -55,4 +55,4 @@ module Gosu
55
55
  end
56
56
  end
57
57
  Sound = Sample # Gosu uses Sample, but Sound makes sense too.
58
- end
58
+ end
@@ -133,34 +133,13 @@ module Chingu
133
133
  @paused = false
134
134
  end
135
135
 
136
- #
137
- # Disable automatic calling of draw and draw_trait each game loop
138
- #
139
- def hide!
140
- @visible = false
141
- end
142
-
143
- #
144
- # Enable automatic calling of draw and draw_trait each game loop
145
- #
146
- def show!
147
- @visible = true
148
- end
149
-
150
136
  #
151
137
  # Returns true if paused
152
138
  #
153
139
  def paused?
154
140
  @paused == true
155
141
  end
156
-
157
- #
158
- # Returns true if visible (not hidden)
159
- #
160
- def visible?
161
- @visible == true
162
- end
163
-
142
+
164
143
  #
165
144
  # Empty placeholders to be overridden
166
145
  #
@@ -171,7 +150,6 @@ module Chingu
171
150
  def draw_trait; end
172
151
  def update; end
173
152
  def draw; end
174
-
175
153
 
176
154
  #
177
155
  # Returns an array with all objects of current class.
@@ -189,6 +189,27 @@ module Chingu
189
189
  @angle = value
190
190
  end
191
191
 
192
+ #
193
+ # Disable automatic calling of draw and draw_trait each game loop
194
+ #
195
+ def hide!
196
+ @visible = false
197
+ end
198
+
199
+ #
200
+ # Enable automatic calling of draw and draw_trait each game loop
201
+ #
202
+ def show!
203
+ @visible = true
204
+ end
205
+
206
+ #
207
+ # Returns true if visible (not hidden)
208
+ #
209
+ def visible?
210
+ @visible == true
211
+ end
212
+
192
213
 
193
214
  # Returns true if object is inside the game window, false if outside
194
215
  def inside_window?(x = @x, y = @y)
@@ -0,0 +1,96 @@
1
+ #--
2
+ #
3
+ # Chingu -- OpenGL accelerated 2D game framework for Ruby
4
+ # Copyright (C) 2009 ippa / ippa@rubylicio.us
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ #++
21
+
22
+ module Chingu
23
+ #
24
+ # ** This class is under heavy development, API will most likely change! **
25
+ #
26
+ # GameObjectMap can convert any set of game objects into a 2D-array for fast lookup
27
+ # You can set any gridsize with :grid, defaults to [32,32]. The smaller the grid the more memory it will eat.
28
+ #
29
+ # Basic usage:
30
+ # @map = GameObjectMap.new(:game_objects => TerrainObject.all, :grid => [32, 32])
31
+ # @map.at(100, 100) # returns one TerrainObject at x/y: 100/100
32
+ # @map.game_object(player) # returns one TerrainObject which collides with player.bounding_box
33
+ #
34
+ # ** This class is under heavy development, API will most likely change! **
35
+ #
36
+ class GameObjectMap
37
+ attr_reader :map
38
+
39
+ def initialize(options = {})
40
+ @game_objects = options[:game_objects]
41
+ @grid = options[:grid] || [32,32]
42
+ @debug = options[:debug]
43
+ create_map
44
+ end
45
+
46
+ #
47
+ # Creates a "tilemap" of game objects using @grid and @game_objects
48
+ # Useful for faster collision detection on a grid-based freeform map created with the Edit game state.
49
+ #
50
+ def create_map
51
+ @map = []
52
+ @game_objects.each do |game_object|
53
+ puts "#{game_object.class} @ #{game_object.x} / #{game_object.y}" if @debug
54
+
55
+ start_x = (game_object.bb.left / @grid[0]).to_i
56
+ stop_x = (game_object.bb.right / @grid[0]).to_i
57
+
58
+ (start_x .. stop_x).each do |x|
59
+ start_y = (game_object.bb.top / @grid[1]).to_i
60
+ stop_y = (game_object.bb.bottom / @grid[1]).to_i
61
+
62
+ @map[x] ||= []
63
+ (start_y .. stop_y).each do |y|
64
+ @map[x][y] = game_object
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ #
71
+ # Gets a game object from the array-map on a certain X/Y
72
+ #
73
+ def at(x, y)
74
+ lookup_x = (x / @grid[0]).to_i
75
+ lookup_y = (y / @grid[1]).to_i
76
+ @map[lookup_x][lookup_y] rescue nil
77
+ end
78
+
79
+ def from_game_object(game_object)
80
+ start_x = (game_object.bb.left / @grid[0]).to_i
81
+ stop_x = (game_object.bb.right / @grid[0]).to_i
82
+
83
+ (start_x .. stop_x).each do |x|
84
+ start_y = (game_object.bb.top / @grid[1]).to_i
85
+ stop_y = (game_object.bb.bottom / @grid[1]).to_i
86
+
87
+ (start_y .. stop_y).each do |y|
88
+ return @map[x][y] if @map[x] && @map[x][y]
89
+ end
90
+
91
+ end
92
+ return nil
93
+ end
94
+
95
+ end
96
+ end