chingu 0.8rc2 → 0.8rc3
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|