chingu 0.8rc2 → 0.8rc3
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/README.rdoc +66 -19
- data/benchmarks/arrays_bench.rb +22 -0
- data/benchmarks/game_objects_benchmark.rb +29 -35
- data/chingu.gemspec +16 -2
- data/examples/example18_animation_trait.rb +14 -9
- data/examples/example19.yml +305 -561
- data/examples/example19_edit_viewport.rb +3 -1
- data/examples/example1_basics.rb +4 -4
- data/examples/example21.yml +62 -54
- data/examples/example21_sidescroller_with_edit.rb +13 -21
- data/examples/example4_gamestates.rb +0 -2
- data/examples/example7_gfx_helpers.rb +1 -1
- data/examples/example8_traits.rb +1 -2
- data/examples/example9_collision_detection.rb +1 -1
- data/examples/game1.rb +1 -1
- data/lib/chingu.rb +1 -2
- data/lib/chingu/animation.rb +13 -5
- data/lib/chingu/assets.rb +2 -2
- data/lib/chingu/basic_game_object.rb +33 -30
- data/lib/chingu/game_object.rb +0 -5
- data/lib/chingu/game_object_list.rb +34 -21
- data/lib/chingu/game_states/edit.rb +2 -5
- data/lib/chingu/game_states/fade_to.rb +0 -1
- data/lib/chingu/game_states/pause.rb +1 -1
- data/lib/chingu/helpers/game_object.rb +0 -1
- data/lib/chingu/parallax.rb +3 -9
- data/lib/chingu/simple_menu.rb +7 -8
- data/lib/chingu/traits/animation.rb +2 -4
- data/lib/chingu/traits/sprite.rb +16 -13
- data/lib/chingu/window.rb +1 -1
- data/spec/chingu/animation_spec.rb +88 -0
- data/spec/chingu/assets_spec.rb +58 -0
- data/spec/chingu/basic_game_object_spec.rb +111 -0
- data/spec/chingu/game_object_list_spec.rb +78 -0
- data/spec/chingu/game_object_spec.rb +50 -14
- data/spec/chingu/game_state_manager_spec.rb +105 -0
- data/spec/chingu/helpers/input_client_spec.rb +4 -0
- data/spec/chingu/helpers/input_dispatcher_spec.rb +4 -0
- data/spec/chingu/images/droid_11x15.bmp +0 -0
- data/spec/chingu/parallax_spec.rb +25 -16
- data/spec/chingu/window_spec.rb +55 -0
- data/spec/spec_helper.rb +1 -5
- metadata +17 -3
data/examples/game1.rb
CHANGED
@@ -79,7 +79,7 @@ class Level < Chingu::GameState
|
|
79
79
|
game_objects.destroy_if { |game_object| game_object.respond_to?("outside_window?") && game_object.outside_window? }
|
80
80
|
|
81
81
|
# Collide bullets with terrain
|
82
|
-
Bullet.
|
82
|
+
Bullet.select { |o| solid_pixel_at?(o.x, o.y)}.each { |o| o.die }
|
83
83
|
|
84
84
|
# Collide player with terrain
|
85
85
|
push_game_state(GameOver) if solid_pixel_at?(@player.x, @player.y)
|
data/lib/chingu.rb
CHANGED
data/lib/chingu/animation.rb
CHANGED
@@ -10,7 +10,7 @@ module Chingu
|
|
10
10
|
# Is autodetection of width / height possible?
|
11
11
|
#
|
12
12
|
class Animation
|
13
|
-
attr_accessor :frames, :delay, :step, :loop, :bounce, :step
|
13
|
+
attr_accessor :frames, :delay, :step, :loop, :bounce, :step, :index
|
14
14
|
|
15
15
|
#
|
16
16
|
# Create a new Animation.
|
@@ -107,18 +107,25 @@ module Chingu
|
|
107
107
|
end
|
108
108
|
|
109
109
|
#
|
110
|
-
# Returns first frame (
|
110
|
+
# Returns the first frame (Gosu::Image) from animation
|
111
111
|
#
|
112
112
|
def first
|
113
113
|
@frames.first
|
114
114
|
end
|
115
115
|
|
116
116
|
#
|
117
|
-
# Returns last frame (
|
117
|
+
# Returns the last frame (Gosu::Image) from animation
|
118
118
|
#
|
119
119
|
def last
|
120
120
|
@frames.last
|
121
121
|
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# [width, height] for each frame in the animation
|
125
|
+
#
|
126
|
+
def size
|
127
|
+
[@width, @height]
|
128
|
+
end
|
122
129
|
|
123
130
|
#
|
124
131
|
# Returns true if the current frame is the last
|
@@ -151,7 +158,7 @@ module Chingu
|
|
151
158
|
end
|
152
159
|
|
153
160
|
#
|
154
|
-
# Get the current frame (a Gosu
|
161
|
+
# Get the current frame (a Gosu::Image)
|
155
162
|
#
|
156
163
|
def image
|
157
164
|
@frames[@index]
|
@@ -186,7 +193,7 @@ module Chingu
|
|
186
193
|
#
|
187
194
|
def next(recursion = true)
|
188
195
|
|
189
|
-
if (@dt += $window.milliseconds_since_last_tick)
|
196
|
+
if (@dt += $window.milliseconds_since_last_tick) >= @delay
|
190
197
|
@dt = 0
|
191
198
|
@previous_index = @index
|
192
199
|
@index += @step
|
@@ -196,6 +203,7 @@ module Chingu
|
|
196
203
|
if @bounce
|
197
204
|
@step *= -1 # invert number
|
198
205
|
@index += @step
|
206
|
+
@index += @step
|
199
207
|
elsif @loop
|
200
208
|
@index = 0
|
201
209
|
else
|
data/lib/chingu/assets.rb
CHANGED
@@ -101,7 +101,7 @@ module Gosu
|
|
101
101
|
include Chingu::NamedResource
|
102
102
|
|
103
103
|
def self.autoload(name)
|
104
|
-
(path = find_file(name)) ? Gosu::Song.new(
|
104
|
+
(path = find_file(name)) ? Gosu::Song.new(path) : nil
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
@@ -109,7 +109,7 @@ module Gosu
|
|
109
109
|
include Chingu::NamedResource
|
110
110
|
|
111
111
|
def self.autoload(name)
|
112
|
-
(path = find_file(name)) ? Gosu::Sample.new(
|
112
|
+
(path = find_file(name)) ? Gosu::Sample.new(path) : nil
|
113
113
|
end
|
114
114
|
end
|
115
115
|
Sound = Sample # Gosu uses Sample, but Sound makes sense too.
|
@@ -10,7 +10,7 @@ module Chingu
|
|
10
10
|
class BasicGameObject
|
11
11
|
include Chingu::Helpers::ClassInheritableAccessor # adds classmethod class_inheritable_accessor
|
12
12
|
|
13
|
-
attr_reader :options, :paused
|
13
|
+
attr_reader :options, :paused
|
14
14
|
attr_accessor :parent
|
15
15
|
|
16
16
|
class_inheritable_accessor :trait_options
|
@@ -24,7 +24,6 @@ module Chingu
|
|
24
24
|
def self.trait(trait, options = {})
|
25
25
|
|
26
26
|
if trait.is_a?(::Symbol) || trait.is_a?(::String)
|
27
|
-
## puts "trait #{trait}, #{options}"
|
28
27
|
begin
|
29
28
|
# Convert user-given symbol (eg. :timer) to a Module (eg. Chingu::Traits::Timer)
|
30
29
|
mod = Chingu::Traits.const_get(Chingu::Inflector.camelize(trait))
|
@@ -56,11 +55,7 @@ module Chingu
|
|
56
55
|
Array(traits).each { |trait_name| trait trait_name }
|
57
56
|
end
|
58
57
|
class << self; alias :has_traits :traits; end
|
59
|
-
|
60
|
-
#def self.inherited(subclass)
|
61
|
-
# subclass.initialize_inherited_trait if subclass.method_defined?(:initialize_inherited_trait)
|
62
|
-
#end
|
63
|
-
|
58
|
+
|
64
59
|
alias :game_state :parent
|
65
60
|
alias :game_state= :parent=
|
66
61
|
|
@@ -75,17 +70,11 @@ module Chingu
|
|
75
70
|
#
|
76
71
|
# A GameObject either belong to a GameState or our mainwindow ($window)
|
77
72
|
#
|
78
|
-
#if !@parent && $window && $window.respond_to?(:game_state_manager)
|
79
|
-
# @parent = $window.game_state_manager.inside_state || $window
|
80
|
-
#end
|
81
73
|
@parent = $window.current_scope if !@parent && $window
|
82
74
|
|
83
75
|
# if true, BasicGameObject#update will be called
|
84
|
-
@paused = options[:paused] || false
|
76
|
+
@paused = options[:paused] || options[:pause] || false
|
85
77
|
|
86
|
-
# if true, BasicGameObject#draw will be called
|
87
|
-
@visible = options[:visible] || true
|
88
|
-
|
89
78
|
# This will call #setup_trait on the latest trait mixed in
|
90
79
|
# which then will pass it on to the next setup_trait() with a super-call.
|
91
80
|
setup_trait(options)
|
@@ -94,14 +83,14 @@ module Chingu
|
|
94
83
|
end
|
95
84
|
|
96
85
|
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
86
|
+
# Works just as BasicGameObject#new with the addition that Chingu will keep track of the new object.
|
87
|
+
# The object will be assigned to a game_objects list. If created within a game state it will be added to that_game_state.game_objects.
|
88
|
+
# Otherwise it will be added to $window.game_objects list.
|
89
|
+
# The naming is inspired from ActiveRecord#create which will persist the object in the database right away.
|
100
90
|
#
|
101
|
-
#
|
102
|
-
#
|
91
|
+
# Chingu will automatically call update() and draw() on stored game objects.
|
92
|
+
# Often in a smaller game this is exaclty what you want. If not, use the normal new().
|
103
93
|
#
|
104
|
-
#def self.create(options = {})
|
105
94
|
def self.create(*options, &block)
|
106
95
|
instance = self.new(*options, &block)
|
107
96
|
|
@@ -113,15 +102,7 @@ module Chingu
|
|
113
102
|
|
114
103
|
return instance
|
115
104
|
end
|
116
|
-
|
117
|
-
#
|
118
|
-
# This ruby callback is called each time someone subclasses BasicGameObject or GameObject
|
119
|
-
# We hook into it to keep track of all game object classes (just as we keep track of game objects instances)
|
120
|
-
#
|
121
|
-
## def self.inherited(klass)
|
122
|
-
## instance.parent.add_game_object_class(klass) if instance.parent
|
123
|
-
## end
|
124
|
-
|
105
|
+
|
125
106
|
#
|
126
107
|
# Disable automatic calling of update() and update_trait() each game loop
|
127
108
|
#
|
@@ -176,7 +157,29 @@ module Chingu
|
|
176
157
|
end
|
177
158
|
|
178
159
|
#
|
179
|
-
#
|
160
|
+
# As Array.each on the instances of the current class
|
161
|
+
#
|
162
|
+
def self.each
|
163
|
+
all.each { |object| yield object }
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
# As Array.each_with_index on the instances of the current class
|
168
|
+
#
|
169
|
+
def self.each_with_index
|
170
|
+
all.each_with_index { |object, index| yield object, index }
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
# As Array.select but on the instances of current class
|
175
|
+
#
|
176
|
+
def self.select
|
177
|
+
all.select { |object| yield object }
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
#
|
182
|
+
# Returns the total amount of game objects based on this class
|
180
183
|
#
|
181
184
|
def self.size
|
182
185
|
$window.current_scope.game_objects.of_class(self).size
|
data/lib/chingu/game_object.rb
CHANGED
@@ -29,8 +29,8 @@ module Chingu
|
|
29
29
|
|
30
30
|
def initialize(options = {})
|
31
31
|
@game_objects = options[:game_objects] || []
|
32
|
-
|
33
|
-
|
32
|
+
@add_game_objects = []
|
33
|
+
@remove_game_objects = []
|
34
34
|
end
|
35
35
|
|
36
36
|
def to_s
|
@@ -48,13 +48,15 @@ module Chingu
|
|
48
48
|
alias :remove_all :destroy_all
|
49
49
|
|
50
50
|
def add_game_object(object)
|
51
|
-
|
51
|
+
@game_objects.push(object)
|
52
|
+
#@add_game_objects.push(object)
|
52
53
|
end
|
53
54
|
|
54
55
|
def remove_game_object(object)
|
55
|
-
|
56
|
+
@game_objects.delete(object)
|
57
|
+
#@remove_game_objects.push(object)
|
56
58
|
end
|
57
|
-
|
59
|
+
|
58
60
|
def destroy_if
|
59
61
|
@game_objects.reject! { |object| yield(object) }
|
60
62
|
end
|
@@ -68,44 +70,46 @@ module Chingu
|
|
68
70
|
end
|
69
71
|
|
70
72
|
def draw
|
71
|
-
@game_objects.
|
73
|
+
@game_objects.select { |object| object.visible }.each do |object|
|
72
74
|
object.draw_trait
|
73
75
|
object.draw
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
77
79
|
def draw_relative(x=0, y=0, zorder=0, angle=0, center_x=0, center_y=0, factor_x=0, factor_y=0)
|
78
|
-
@game_objects.
|
80
|
+
@game_objects.select { |object| object.visible }.each do |object|
|
79
81
|
object.draw_trait
|
80
82
|
object.draw_relative(x, y, zorder, angle, center_x, center_y, factor_x, factor_y)
|
81
83
|
end
|
82
84
|
end
|
83
|
-
|
84
|
-
def sync
|
85
|
-
@game_objects += @add_game_objects
|
86
|
-
@add_game_objects.clear
|
87
|
-
|
88
|
-
@game_objects -= @remove_game_objects
|
89
|
-
@remove_game_objects.clear
|
90
|
-
end
|
91
|
-
|
85
|
+
|
92
86
|
def update
|
93
|
-
|
94
|
-
|
95
|
-
@game_objects.select{ |object| not object.paused }.each do |object|
|
87
|
+
@game_objects.select { |object| not object.paused }.each do |object|
|
96
88
|
object.update_trait
|
97
89
|
object.update
|
98
90
|
end
|
99
91
|
end
|
100
92
|
|
101
93
|
def each
|
102
|
-
@game_objects.each { |object| yield object }
|
94
|
+
@game_objects.dup.each { |object| yield object }
|
95
|
+
end
|
96
|
+
|
97
|
+
def each_with_index
|
98
|
+
@game_objects.dup.each_with_index { |object, index| yield object, index }
|
103
99
|
end
|
104
100
|
|
105
101
|
def select
|
106
|
-
@game_objects.select { |object| yield object }
|
102
|
+
@game_objects.dup.select { |object| yield object }
|
107
103
|
end
|
108
104
|
|
105
|
+
def first
|
106
|
+
@game_objects.first
|
107
|
+
end
|
108
|
+
|
109
|
+
def last
|
110
|
+
@game_objects.last
|
111
|
+
end
|
112
|
+
|
109
113
|
#
|
110
114
|
# Disable automatic calling of update() and update_trait() each game loop for all game objects
|
111
115
|
#
|
@@ -138,5 +142,14 @@ module Chingu
|
|
138
142
|
end
|
139
143
|
alias :show :show!
|
140
144
|
|
145
|
+
private
|
146
|
+
|
147
|
+
def sync
|
148
|
+
@game_objects += @add_game_objects
|
149
|
+
@add_game_objects.clear
|
150
|
+
|
151
|
+
@game_objects -= @remove_game_objects
|
152
|
+
@remove_game_objects.clear
|
153
|
+
end
|
141
154
|
end
|
142
155
|
end
|
@@ -244,11 +244,7 @@ END_OF_STRING
|
|
244
244
|
#
|
245
245
|
# UPDATE
|
246
246
|
#
|
247
|
-
def update
|
248
|
-
# Sync all changes to previous game states game objects list
|
249
|
-
# This is needed since we don't call update on it.
|
250
|
-
previous_game_state.game_objects.sync
|
251
|
-
|
247
|
+
def update
|
252
248
|
super
|
253
249
|
|
254
250
|
@status_text.text = "#{self.mouse_x.to_i} / #{self.mouse_y.to_i}"
|
@@ -467,6 +463,7 @@ END_OF_STRING
|
|
467
463
|
def game_object_icon_at(x, y)
|
468
464
|
game_objects.select do |game_object|
|
469
465
|
next if game_object.is_a? Text
|
466
|
+
next unless game_object.image
|
470
467
|
bounding_box(game_object).collide_point?(x,y)
|
471
468
|
end.first
|
472
469
|
end
|
data/lib/chingu/parallax.rb
CHANGED
@@ -159,7 +159,6 @@ module Chingu
|
|
159
159
|
# put the last layer added on top of the rest.
|
160
160
|
#
|
161
161
|
class ParallaxLayer < Chingu::GameObject
|
162
|
-
@@zorder_counter = 0
|
163
162
|
attr_reader :damping
|
164
163
|
attr_accessor :repeat_x, :repeat_y
|
165
164
|
|
@@ -178,9 +177,9 @@ module Chingu
|
|
178
177
|
options = {
|
179
178
|
:repeat_x => true,
|
180
179
|
:repeat_y => false,
|
181
|
-
:zorder
|
180
|
+
:zorder => @parallax ? (@parallax.zorder + @parallax.layers.count) : 100
|
182
181
|
}.merge(options)
|
183
|
-
|
182
|
+
|
184
183
|
@repeat_x = options[:repeat_x]
|
185
184
|
@repeat_y = options[:repeat_y]
|
186
185
|
|
@@ -188,12 +187,7 @@ module Chingu
|
|
188
187
|
|
189
188
|
@damping = options[:damping] || 1
|
190
189
|
end
|
191
|
-
|
192
|
-
def draw
|
193
|
-
super
|
194
|
-
#p "draw @ #{x} / #{y}: #{image} - #{zorder} - #{color}"
|
195
|
-
end
|
196
|
-
|
190
|
+
|
197
191
|
#
|
198
192
|
# Gets pixel from layers image
|
199
193
|
# The pixel is from the window point of view, so coordinates are converted:
|
data/lib/chingu/simple_menu.rb
CHANGED
@@ -25,21 +25,20 @@ module Chingu
|
|
25
25
|
#
|
26
26
|
class SimpleMenu < BasicGameObject
|
27
27
|
include Chingu::Helpers::InputClient
|
28
|
-
attr_accessor :menu_items
|
28
|
+
attr_accessor :menu_items, :visible
|
29
29
|
|
30
30
|
def initialize(options = {})
|
31
31
|
super
|
32
32
|
|
33
|
-
@menu_items = options.delete(:menu_items)# || {"Exit" => :exit}
|
34
|
-
|
33
|
+
@menu_items = options.delete(:menu_items) # || {"Exit" => :exit}
|
35
34
|
@x = options.delete(:x) || $window.width/2
|
36
|
-
@y = options.delete(:
|
37
|
-
@spacing = options.delete(:
|
35
|
+
@y = options.delete(:y) || 100
|
36
|
+
@spacing = options.delete(:spacing) || 100
|
38
37
|
@items = []
|
38
|
+
@visible = true
|
39
39
|
|
40
40
|
y = @spacing
|
41
41
|
menu_items.each do |key, value|
|
42
|
-
|
43
42
|
item = if key.is_a? String
|
44
43
|
Text.new(key, options.dup)
|
45
44
|
elsif key.is_a? Image
|
@@ -105,10 +104,10 @@ module Chingu
|
|
105
104
|
when Proc, Method
|
106
105
|
action[]
|
107
106
|
when Chingu::GameState
|
108
|
-
push_game_state(action)
|
107
|
+
game_state.push_game_state(action)
|
109
108
|
when Class
|
110
109
|
if action.ancestors.include?(Chingu::GameState)
|
111
|
-
push_game_state(action)
|
110
|
+
game_state.push_game_state(action)
|
112
111
|
end
|
113
112
|
else
|
114
113
|
# TODO possibly raise an error? This ought to be handled when the input is specified in the first place.
|