chingu 0.7.5 → 0.7.6
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 +60 -14
- data/Rakefile +1 -1
- data/chingu.gemspec +16 -6
- data/examples/example14_bounding_box_circle.rb +8 -1
- data/examples/{example19_game_objects.yml → example19.yml} +1014 -4
- data/examples/example19_edit_viewport.rb +34 -8
- data/examples/example21.yml +2145 -0
- data/examples/example21_sidescroller_with_edit.rb +298 -0
- data/examples/game_of_life.rb +3 -3
- data/examples/media/battery.png +0 -0
- data/examples/media/big_star.png +0 -0
- data/examples/media/big_stone_wall.bmp +0 -0
- data/examples/media/black_block.png +0 -0
- data/examples/media/cog_wheel.png +0 -0
- data/examples/media/saw.png +0 -0
- data/examples/media/tube.png +0 -0
- data/lib/chingu.rb +1 -1
- data/lib/chingu/animation.rb +8 -3
- data/lib/chingu/basic_game_object.rb +3 -1
- data/lib/chingu/game_object.rb +23 -11
- data/lib/chingu/game_state.rb +11 -0
- data/lib/chingu/game_states/edit.rb +405 -137
- data/lib/chingu/helpers/game_object.rb +15 -9
- data/lib/chingu/input.rb +2 -2
- data/lib/chingu/traits/animation.rb +5 -4
- data/lib/chingu/traits/bounding_box.rb +9 -4
- data/lib/chingu/traits/bounding_circle.rb +2 -0
- data/lib/chingu/traits/collision_detection.rb +32 -16
- data/lib/chingu/traits/velocity.rb +37 -19
- data/lib/chingu/traits/viewport.rb +1 -0
- data/lib/chingu/viewport.rb +10 -5
- metadata +18 -8
@@ -0,0 +1,298 @@
|
|
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
|
+
# Press 'E' when demo is running to edit the playfield!
|
9
|
+
#
|
10
|
+
class Game < Chingu::Window
|
11
|
+
def initialize
|
12
|
+
super(1000,700)
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup
|
16
|
+
Gosu::enable_undocumented_retrofication
|
17
|
+
switch_game_state(Example21.new)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# The Game
|
23
|
+
#
|
24
|
+
class Example21 < GameState
|
25
|
+
traits :viewport, :timer
|
26
|
+
|
27
|
+
def setup
|
28
|
+
self.input = { :escape => :exit, :e => :edit }
|
29
|
+
self.viewport.game_area = [0, 0, 3000, 1000]
|
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)
|
34
|
+
|
35
|
+
load_game_objects
|
36
|
+
|
37
|
+
# Reverse the cog wheels in relation to eachother
|
38
|
+
CogWheel.each_collision(CogWheel) do |cog_wheel, cog_wheel_2|
|
39
|
+
cog_wheel_2.angle_velocity = -cog_wheel.angle_velocity
|
40
|
+
end
|
41
|
+
|
42
|
+
@saved_x, @saved_y = [100, 300]
|
43
|
+
every(5000) { save_player_position }
|
44
|
+
end
|
45
|
+
|
46
|
+
def edit
|
47
|
+
push_game_state(GameStates::Edit.new(:grid => [32,32], :classes => [Tube, CogWheel, Block, Saw, Battery]))
|
48
|
+
end
|
49
|
+
|
50
|
+
def restore_player_position
|
51
|
+
@droid.x, @droid.y = @saved_x, @saved_y
|
52
|
+
end
|
53
|
+
|
54
|
+
def save_player_position
|
55
|
+
@saved_x, @saved_y = @droid.x, @droid.y if @droid.velocity_y >= 0 && @droid.collidable
|
56
|
+
end
|
57
|
+
|
58
|
+
def update
|
59
|
+
super
|
60
|
+
|
61
|
+
visible_blocks = Block.inside_viewport
|
62
|
+
|
63
|
+
FireBall.each_collision(visible_blocks) do |fire_ball, block|
|
64
|
+
fire_ball.destroy
|
65
|
+
end
|
66
|
+
|
67
|
+
# Makes all saw pendle up and down between Y-coordinate 1000 - 1500
|
68
|
+
# TODO: Not a very flexible sollution, how about setting out circle,rects,lines in editor..
|
69
|
+
# .. when then can be used for this kind of stuff?
|
70
|
+
Saw.all.select {|saw| saw.y < 1300 || saw.y > 1550 }.each do |saw|
|
71
|
+
saw.velocity_y = -saw.velocity_y
|
72
|
+
saw.y += saw.velocity_y * saw.factor_y
|
73
|
+
end
|
74
|
+
|
75
|
+
@droid.each_collision(FireBall, Saw) do |player, evil_object|
|
76
|
+
player.die
|
77
|
+
end
|
78
|
+
|
79
|
+
@droid.each_collision(Battery) do |player, battery|
|
80
|
+
battery.die
|
81
|
+
#after(3000) { push_game_state(GameFinished) }
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
self.viewport.center_around(@droid)
|
86
|
+
|
87
|
+
$window.caption = "Haunted Factory. TAB toggles Edit. x/y: #{@droid.x.to_i}/#{@droid.y.to_i} - viewport x/y: #{self.viewport.x.to_i}/#{self.viewport.y.to_i} - FPS: #{$window.fps}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
#
|
93
|
+
class GameFinished < GameState
|
94
|
+
def setup
|
95
|
+
self.input
|
96
|
+
Text.create("MMMM... Battery ACID, YUM!")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# DROID
|
102
|
+
#
|
103
|
+
class Droid < Chingu::GameObject
|
104
|
+
trait :bounding_box, :scale => 0.80
|
105
|
+
traits :timer, :collision_detection , :timer, :velocity
|
106
|
+
|
107
|
+
def setup
|
108
|
+
self.input = { [:holding_left, :holding_a] => :holding_left,
|
109
|
+
[:holding_right, :holding_d] => :holding_right,
|
110
|
+
[:up, :w] => :jump,
|
111
|
+
:space => :fire
|
112
|
+
}
|
113
|
+
|
114
|
+
# Load the full animation from tile-file media/droid.bmp
|
115
|
+
@animations = Chingu::Animation.new(:file => "droid_11x15.bmp")
|
116
|
+
@animations.frame_names = { :scan => 0..5, :up => 6..7, :down => 8..9, :left => 10..11, :right => 12..13 }
|
117
|
+
|
118
|
+
@animation = @animations[:scan]
|
119
|
+
@speed = 3
|
120
|
+
|
121
|
+
self.zorder = 300
|
122
|
+
self.factor = 3
|
123
|
+
self.acceleration_y = 0.5
|
124
|
+
self.max_velocity = 10
|
125
|
+
self.rotation_center = :bottom_center
|
126
|
+
|
127
|
+
update
|
128
|
+
end
|
129
|
+
|
130
|
+
def die
|
131
|
+
self.collidable = false
|
132
|
+
@color = Color::RED
|
133
|
+
between(1,600) { self.velocity_y = 0; self.scale += 0.2; self.alpha -= 5; }.then { resurrect }
|
134
|
+
end
|
135
|
+
|
136
|
+
def resurrect
|
137
|
+
self.alpha = 255
|
138
|
+
self.factor = 3
|
139
|
+
self.collidable = true
|
140
|
+
@color = Color::WHITE
|
141
|
+
game_state.restore_player_position
|
142
|
+
end
|
143
|
+
|
144
|
+
def holding_left
|
145
|
+
move(-@speed, 0)
|
146
|
+
@animation = @animations[:left]
|
147
|
+
end
|
148
|
+
|
149
|
+
def holding_right
|
150
|
+
move(@speed, 0)
|
151
|
+
@animation = @animations[:right]
|
152
|
+
end
|
153
|
+
|
154
|
+
def jump
|
155
|
+
return if self.velocity_y < 0
|
156
|
+
self.velocity_y = -10
|
157
|
+
@animation = @animations[:up]
|
158
|
+
end
|
159
|
+
|
160
|
+
def move(x,y)
|
161
|
+
@x += x
|
162
|
+
self.each_collision(Block.inside_viewport) do |me, stone_wall|
|
163
|
+
me.x = previous_x
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def update
|
168
|
+
@image = @animation.next
|
169
|
+
self.each_collision(Block.inside_viewport) do |me, stone_wall|
|
170
|
+
if self.velocity_y < 0
|
171
|
+
me.y = stone_wall.bb.bottom + me.image.height * self.factor_y
|
172
|
+
self.velocity_y = 0
|
173
|
+
else
|
174
|
+
me.y = stone_wall.bb.top-1
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
@animation = @animations[:scan] unless moved?
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
#
|
183
|
+
# TUBE
|
184
|
+
#
|
185
|
+
class Tube < GameObject
|
186
|
+
traits :bounding_box, :timer
|
187
|
+
def setup
|
188
|
+
@image = Image["tube.png"]
|
189
|
+
every(3000) { fire }
|
190
|
+
cache_bounding_box
|
191
|
+
end
|
192
|
+
|
193
|
+
def fire
|
194
|
+
return if game_state.viewport.outside?(self.bb.centerx, self.bb.bottom)
|
195
|
+
FireBall.create(:x => self.bb.centerx - rand(10), :y => self.bb.bottom - rand(10))
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
#
|
200
|
+
# BATTERY
|
201
|
+
#
|
202
|
+
class Battery < GameObject
|
203
|
+
traits :timer, :effect
|
204
|
+
trait :bounding_box, :debug => false
|
205
|
+
|
206
|
+
def setup
|
207
|
+
@image = Image["battery.png"]
|
208
|
+
cache_bounding_box
|
209
|
+
end
|
210
|
+
|
211
|
+
def die
|
212
|
+
self.collidable = false # Stops further collisions in each_collsiion() etc.
|
213
|
+
self.rotation_rate = 5
|
214
|
+
self.scale_rate = 0.005
|
215
|
+
self.fade_rate = -5
|
216
|
+
after(2000) { destroy }
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
#
|
221
|
+
# A FIREBALL
|
222
|
+
#
|
223
|
+
class FireBall < GameObject
|
224
|
+
traits :velocity, :collision_detection
|
225
|
+
trait :bounding_circle, :scale => 0.7
|
226
|
+
|
227
|
+
def setup
|
228
|
+
@animation = Animation.new(:file => "fireball.png", :size => [32,32], :delay => 20)
|
229
|
+
@image = @animation.first
|
230
|
+
self.mode = :additive
|
231
|
+
self.factor = 3
|
232
|
+
self.velocity_y = 1
|
233
|
+
self.zorder = 200
|
234
|
+
self.rotation_center = :center
|
235
|
+
end
|
236
|
+
|
237
|
+
def update
|
238
|
+
@image = @animation.next
|
239
|
+
@angle += 2
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
#
|
244
|
+
# COG WHEEL
|
245
|
+
#
|
246
|
+
class CogWheel < GameObject
|
247
|
+
traits :bounding_circle, :collision_detection, :timer
|
248
|
+
attr_accessor :angle_velocity
|
249
|
+
|
250
|
+
def setup
|
251
|
+
@image = Image["cog_wheel.png"]
|
252
|
+
@angle_velocity = 1 / self.factor_x
|
253
|
+
end
|
254
|
+
|
255
|
+
def update
|
256
|
+
self.angle += @angle_velocity
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
#
|
261
|
+
# SAW
|
262
|
+
#
|
263
|
+
class Saw < GameObject
|
264
|
+
traits :bounding_circle, :collision_detection, :timer, :velocity
|
265
|
+
attr_accessor :angle_velocity
|
266
|
+
|
267
|
+
def setup
|
268
|
+
@image = Image["saw.png"]
|
269
|
+
@angle_velocity = 3.0 / self.factor_x.to_f
|
270
|
+
self.velocity_y = 1.0 / self.factor_x.to_f
|
271
|
+
end
|
272
|
+
|
273
|
+
def update
|
274
|
+
self.angle += @angle_velocity
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
#
|
279
|
+
# BLOCK, our basic level building block
|
280
|
+
#
|
281
|
+
class Block < GameObject
|
282
|
+
trait :bounding_box, :debug => false
|
283
|
+
trait :collision_detection
|
284
|
+
|
285
|
+
def self.solid
|
286
|
+
all.select { |block| block.alpha == 255 }
|
287
|
+
end
|
288
|
+
|
289
|
+
def self.inside_viewport
|
290
|
+
all.select { |block| block.game_state.viewport.inside?(block) }
|
291
|
+
end
|
292
|
+
|
293
|
+
def setup
|
294
|
+
@image = Image["black_block.png"]
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
Game.new.show
|
data/examples/game_of_life.rb
CHANGED
@@ -34,8 +34,8 @@ class GameOfLife < Chingu::GameState
|
|
34
34
|
:z => :reset,
|
35
35
|
:n => :update_grid,
|
36
36
|
:space => :toggle_running,
|
37
|
-
:left_arrow => :prev_pattern,
|
38
|
-
:right_arrow => :next_pattern
|
37
|
+
[:mouse_wheel_up,:left_arrow] => :prev_pattern,
|
38
|
+
[:mouse_wheel_down,:right_arrow] => :next_pattern
|
39
39
|
}
|
40
40
|
|
41
41
|
@pattern = :pixel
|
@@ -49,7 +49,7 @@ class GameOfLife < Chingu::GameState
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def update_pattern_info
|
52
|
-
@pattern_info.text = "Current pattern: #{@pattern}. Change patterns with
|
52
|
+
@pattern_info.text = "Current pattern: #{@pattern}. Change patterns with mousewheel."
|
53
53
|
end
|
54
54
|
|
55
55
|
def prev_pattern
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/chingu.rb
CHANGED
data/lib/chingu/animation.rb
CHANGED
@@ -66,11 +66,16 @@ module Chingu
|
|
66
66
|
|
67
67
|
#
|
68
68
|
# Remove transparent space from each frame so the actual sprite is touching the border of the image.
|
69
|
+
# This requires TexPlay
|
69
70
|
#
|
70
71
|
def trim
|
71
|
-
|
72
|
-
|
73
|
-
|
72
|
+
#@frames.each do |frame|
|
73
|
+
# y = 0
|
74
|
+
# x2, y2, color = frame.line 0,y,frame.width,y, :trace => { :while_color => :alpha }
|
75
|
+
# puts "final y: #{y}"
|
76
|
+
# #frame.image.trace 0,0,image
|
77
|
+
# #frame.splice(frame,0,0, :crop => [10, 10, 20, 20])
|
78
|
+
#end
|
74
79
|
end
|
75
80
|
|
76
81
|
#
|
@@ -60,7 +60,9 @@ module Chingu
|
|
60
60
|
# subclass.initialize_inherited_trait if subclass.method_defined?(:initialize_inherited_trait)
|
61
61
|
#end
|
62
62
|
|
63
|
-
|
63
|
+
alias :game_state :parent
|
64
|
+
alias :game_state= :parent=
|
65
|
+
|
64
66
|
#
|
65
67
|
# BasicGameObject initialize
|
66
68
|
# - call .setup_trait() on all traits that implements it
|
data/lib/chingu/game_object.rb
CHANGED
@@ -32,7 +32,7 @@ module Chingu
|
|
32
32
|
#
|
33
33
|
class GameObject < Chingu::BasicGameObject
|
34
34
|
attr_accessor :image, :x, :y, :angle, :center_x, :center_y, :factor_x, :factor_y, :color, :mode, :zorder
|
35
|
-
attr_reader :factor, :center
|
35
|
+
attr_reader :factor, :center
|
36
36
|
|
37
37
|
include Chingu::Helpers::InputClient # Adds input and input=
|
38
38
|
include Chingu::Helpers::RotationCenter # Adds easy and verbose modification of @center_x and @center_y
|
@@ -42,17 +42,17 @@ module Chingu
|
|
42
42
|
|
43
43
|
#
|
44
44
|
# All encapsulated Gosu::Image.draw_rot arguments can be set with hash-options at creation time
|
45
|
-
|
45
|
+
#
|
46
46
|
if options[:image].is_a?(Gosu::Image)
|
47
47
|
@image = options[:image]
|
48
48
|
elsif options[:image].is_a? String
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
49
|
+
begin
|
50
|
+
# 1) Try loading the image the normal way
|
51
|
+
@image = Gosu::Image.new($window, options[:image])
|
52
|
+
rescue
|
53
|
+
# 2) Try looking up the picture using Chingus Image-cache
|
54
|
+
@image = Gosu::Image[options[:image]]
|
55
|
+
end
|
56
56
|
end
|
57
57
|
|
58
58
|
@x = options[:x] || 0
|
@@ -115,7 +115,19 @@ module Chingu
|
|
115
115
|
value = 255 if value > 255
|
116
116
|
@color.alpha = value
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
|
+
#
|
120
|
+
# Sets angle, normalize it to between 0..360
|
121
|
+
#
|
122
|
+
def angle=(value)
|
123
|
+
if value < 0
|
124
|
+
value = 360+value
|
125
|
+
elsif value > 360
|
126
|
+
value = value-360
|
127
|
+
end
|
128
|
+
@angle = value
|
129
|
+
end
|
130
|
+
|
119
131
|
|
120
132
|
# Returns true if object is inside the game window, false if outside
|
121
133
|
def inside_window?(x = @x, y = @y)
|
@@ -127,7 +139,7 @@ module Chingu
|
|
127
139
|
not inside_window?(x,y)
|
128
140
|
end
|
129
141
|
|
130
|
-
# Calculates the distance from self to a given
|
142
|
+
# Calculates the distance from self to a given object
|
131
143
|
def distance_to(object)
|
132
144
|
distance(self.x, self.y, object.x, object.y)
|
133
145
|
end
|
data/lib/chingu/game_state.rb
CHANGED
@@ -128,6 +128,17 @@ module Chingu
|
|
128
128
|
self.class.to_s
|
129
129
|
end
|
130
130
|
|
131
|
+
#
|
132
|
+
# Returns a filename-friendly string from the current class-name
|
133
|
+
#
|
134
|
+
# "Level19" -> "level19"
|
135
|
+
# "BigBossLevel" -> "big_boss_level"
|
136
|
+
#
|
137
|
+
def filename
|
138
|
+
Chingu::Inflector.underscore(self.class.to_s)
|
139
|
+
end
|
140
|
+
|
141
|
+
|
131
142
|
def setup
|
132
143
|
# Your game state setup logic here.
|
133
144
|
end
|