chingu 0.7.0 → 0.7.5
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 +1 -1
- data/README.rdoc +110 -49
- data/benchmarks/game_objects_benchmark.rb +50 -0
- data/chingu.gemspec +24 -12
- data/examples/example10_traits_retrofy.rb +6 -4
- data/examples/example11_animation.rb +14 -23
- data/examples/example12_trait_timer.rb +1 -1
- data/examples/example13_high_scores.rb +1 -1
- data/examples/example14_bounding_box_circle.rb +6 -10
- data/examples/example15_trait_timer2.rb +1 -1
- data/examples/example16_online_high_scores.rb +1 -1
- data/examples/example17_gosu_tutorial.rb +4 -4
- data/examples/example18_animation_trait.rb +98 -0
- data/examples/example19_edit_viewport.rb +223 -0
- data/examples/example19_game_objects.yml +1591 -0
- data/examples/example20_trait_inheritence_test.rb +58 -0
- data/examples/example3_parallax.rb +1 -1
- data/examples/example4_gamestates.rb +1 -1
- data/examples/example7_gfx_helpers.rb +14 -9
- data/examples/example8_traits.rb +4 -4
- data/examples/example9_collision_detection.rb +1 -1
- data/examples/game1.rb +33 -38
- data/examples/game_of_life.rb +291 -0
- data/examples/media/droid_11x15.bmp +0 -0
- data/examples/media/droid_11x15.gal +0 -0
- data/examples/media/heli.bmp +0 -0
- data/examples/media/heli.gal +0 -0
- data/examples/media/star_25x25_default.png +0 -0
- data/examples/media/star_25x25_explode.gal +0 -0
- data/examples/media/star_25x25_explode.png +0 -0
- data/examples/media/stone_wall.bmp +0 -0
- data/lib/chingu.rb +1 -1
- data/lib/chingu/animation.rb +78 -9
- data/lib/chingu/basic_game_object.rb +16 -8
- data/lib/chingu/game_object.rb +36 -7
- data/lib/chingu/game_object_list.rb +20 -3
- data/lib/chingu/game_state.rb +8 -7
- data/lib/chingu/game_states/edit.rb +177 -90
- data/lib/chingu/helpers/class_inheritable_accessor.rb +12 -5
- data/lib/chingu/helpers/game_object.rb +45 -4
- data/lib/chingu/helpers/gfx.rb +150 -172
- data/lib/chingu/helpers/input_client.rb +7 -0
- data/lib/chingu/inflector.rb +16 -2
- data/lib/chingu/traits/animation.rb +84 -0
- data/lib/chingu/traits/bounding_box.rb +16 -3
- data/lib/chingu/traits/bounding_circle.rb +18 -4
- data/lib/chingu/traits/collision_detection.rb +10 -1
- data/lib/chingu/traits/velocity.rb +26 -3
- data/lib/chingu/traits/viewport.rb +10 -9
- data/lib/chingu/viewport.rb +103 -22
- data/lib/chingu/window.rb +8 -2
- metadata +46 -16
- data/examples/example18_viewport.rb +0 -173
- data/examples/media/city1.csv +0 -2
- data/examples/media/plane.csv +0 -2
- data/examples/media/saucer.csv +0 -4
- data/examples/media/stickfigure.bmp +0 -0
- data/examples/media/stickfigure.png +0 -0
@@ -1,6 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'rubygems'
|
3
|
-
require 'opengl'
|
4
3
|
require File.join(File.dirname($0), "..", "lib", "chingu")
|
5
4
|
include Gosu
|
6
5
|
include Chingu
|
@@ -14,14 +13,15 @@ class Game < Chingu::Window
|
|
14
13
|
def initialize
|
15
14
|
super
|
16
15
|
@factor = 6
|
17
|
-
self.input = { :escape => :exit }
|
16
|
+
self.input = { :escape => :exit }
|
17
|
+
Gosu::enable_undocumented_retrofication
|
18
18
|
self.caption = "Chingu::Animation / retrofy example. Move with arrows!"
|
19
19
|
Droid.create(:x => $window.width/2, :y => $window.height/2)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
class Droid < Chingu::GameObject
|
24
|
-
|
24
|
+
traits :timer
|
25
25
|
|
26
26
|
def initialize(options = {})
|
27
27
|
super
|
@@ -33,18 +33,11 @@ class Droid < Chingu::GameObject
|
|
33
33
|
self.input = [:holding_left, :holding_right, :holding_up, :holding_down]
|
34
34
|
|
35
35
|
# Load the full animation from tile-file media/droid.bmp
|
36
|
-
@
|
36
|
+
@animation = Chingu::Animation.new(:file => "droid_11x15.bmp")
|
37
|
+
@animation.frame_names = { :scan => 0..5, :up => 6..7, :down => 8..9, :left => 10..11, :right => 12..13 }
|
37
38
|
|
38
|
-
#
|
39
|
-
@
|
40
|
-
@animations[:scan] = @full_animation[0..5]
|
41
|
-
@animations[:up] = @full_animation[6..7]
|
42
|
-
@animations[:down] = @full_animation[8..9]
|
43
|
-
@animations[:left] = @full_animation[10..11]
|
44
|
-
@animations[:right] = @full_animation[12..13]
|
45
|
-
|
46
|
-
# Start out by animation frames 0-5 (contained by @animations[:scan])
|
47
|
-
@animation = @animations[:scan]
|
39
|
+
# Start out by animation frames 0-5 (contained by @animation[:scan])
|
40
|
+
@frame_name = :scan
|
48
41
|
|
49
42
|
self.factor = $window.factor
|
50
43
|
@last_x, @last_y = @x, @y
|
@@ -53,22 +46,22 @@ class Droid < Chingu::GameObject
|
|
53
46
|
|
54
47
|
def holding_left
|
55
48
|
@x -= 2
|
56
|
-
@
|
49
|
+
@frame_name = :left
|
57
50
|
end
|
58
51
|
|
59
52
|
def holding_right
|
60
53
|
@x += 2
|
61
|
-
@
|
54
|
+
@frame_name = :right
|
62
55
|
end
|
63
|
-
|
56
|
+
|
64
57
|
def holding_up
|
65
58
|
@y -= 2
|
66
|
-
@
|
59
|
+
@frame_name = :up
|
67
60
|
end
|
68
61
|
|
69
62
|
def holding_down
|
70
63
|
@y += 2
|
71
|
-
@
|
64
|
+
@frame_name = :down
|
72
65
|
end
|
73
66
|
|
74
67
|
# We don't need to call super() in update().
|
@@ -77,14 +70,12 @@ class Droid < Chingu::GameObject
|
|
77
70
|
|
78
71
|
# Move the animation forward by fetching the next frame and putting it into @image
|
79
72
|
# @image is drawn by default by GameObject#draw
|
80
|
-
@image = @animation.next
|
73
|
+
@image = @animation[@frame_name].next
|
81
74
|
|
82
75
|
#
|
83
76
|
# If droid stands still, use the scanning animation
|
84
77
|
#
|
85
|
-
if @x == @last_x && @y == @last_y
|
86
|
-
@animation = @animations[:scan]
|
87
|
-
end
|
78
|
+
@frame_name = :scan if @x == @last_x && @y == @last_y
|
88
79
|
|
89
80
|
@x, @y = @last_x, @last_y if outside_window? # return to previous coordinates if outside window
|
90
81
|
@last_x, @last_y = @x, @y # save current coordinates for possible use next time
|
@@ -64,11 +64,10 @@ class Game < Chingu::Window
|
|
64
64
|
end
|
65
65
|
|
66
66
|
class Circle < GameObject
|
67
|
-
|
68
|
-
|
67
|
+
trait :bounding_circle, :debug => true
|
68
|
+
traits :velocity, :collision_detection
|
69
69
|
|
70
|
-
def
|
71
|
-
super
|
70
|
+
def setup
|
72
71
|
@image = Image["circle.png"]
|
73
72
|
self.velocity_x = 3 - rand * 6
|
74
73
|
self.velocity_y = 3 - rand * 6
|
@@ -89,11 +88,10 @@ class Circle < GameObject
|
|
89
88
|
end
|
90
89
|
|
91
90
|
class Box < GameObject
|
92
|
-
|
93
|
-
|
91
|
+
trait :bounding_box, :debug => true
|
92
|
+
traits :velocity, :collision_detection
|
94
93
|
|
95
|
-
def
|
96
|
-
super
|
94
|
+
def setup
|
97
95
|
@image = Image["rect.png"]
|
98
96
|
self.velocity_x = 3 - rand * 6
|
99
97
|
self.velocity_y = 3 - rand * 6
|
@@ -104,8 +102,6 @@ class Box < GameObject
|
|
104
102
|
def update
|
105
103
|
self.velocity_x = -self.velocity_x if @x < 0 || @x > $window.width
|
106
104
|
self.velocity_y = -self.velocity_y if @y < 0 || @y > $window.height
|
107
|
-
#@x = @x.to_i
|
108
|
-
#@y = @y.to_i
|
109
105
|
end
|
110
106
|
end
|
111
107
|
|
@@ -38,8 +38,8 @@ class Game < Chingu::Window
|
|
38
38
|
end
|
39
39
|
|
40
40
|
class Player < GameObject
|
41
|
-
|
42
|
-
|
41
|
+
trait :bounding_circle, :debug => DEBUG
|
42
|
+
traits :collision_detection, :effect, :velocity
|
43
43
|
|
44
44
|
def initialize(options={})
|
45
45
|
super(options)
|
@@ -73,8 +73,8 @@ class Player < GameObject
|
|
73
73
|
end
|
74
74
|
|
75
75
|
class Star < GameObject
|
76
|
-
|
77
|
-
|
76
|
+
trait :bounding_circle, :debug => DEBUG
|
77
|
+
trait :collision_detection
|
78
78
|
|
79
79
|
def initialize(options={})
|
80
80
|
super(:zorder=>1)
|
@@ -0,0 +1,98 @@
|
|
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
|
+
# animation-trait example
|
9
|
+
#
|
10
|
+
class Game < Chingu::Window
|
11
|
+
def initialize
|
12
|
+
super(400, 400)
|
13
|
+
self.input = { :escape => :exit }
|
14
|
+
switch_game_state(Play)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Play < Chingu::GameState
|
19
|
+
trait :timer
|
20
|
+
|
21
|
+
def setup
|
22
|
+
Droid.create(:x => 200, :y => 300, :factor => 4, :alpha => 100)
|
23
|
+
every(1000) { Spaceship.create(:x => 10, :y => 300, :velocity_x => 1) }
|
24
|
+
every(1000) { Plane.create(:x => 10, :y => 350, :velocity => [1,0] ) }
|
25
|
+
every(500) { FireBullet.create(:x => 10, :y => 370, :velocity_x => 1) }
|
26
|
+
every(500) { Star.create(:x => 400, :y => 400, :velocity => [-2,-rand*2]) }
|
27
|
+
#every(400) { Heli.create(:x => 10, :y => 10, :velocity_x => 1) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
super
|
32
|
+
game_objects.select { |game_object| game_object.outside_window? }.each(&:destroy)
|
33
|
+
$window.caption = "game_objects: #{game_objects.size}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Actor < GameObject
|
38
|
+
trait :velocity
|
39
|
+
|
40
|
+
def setup
|
41
|
+
@image = Image["#{self.filename}.png"]
|
42
|
+
@zorder = 10
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
class Spaceship < Actor; end # spaceship.png will be loaded
|
48
|
+
class Plane < Actor; end # plane.png will be loaded
|
49
|
+
class FireBullet < Actor; end # fire_bullet.png will be loaded
|
50
|
+
|
51
|
+
#
|
52
|
+
# droid_11x16.png will be loaded and animated with :delay parameter, each frame beeing 11 x 16 pixels
|
53
|
+
#
|
54
|
+
class Droid < Actor
|
55
|
+
trait :animation, :delay => 200
|
56
|
+
|
57
|
+
def update
|
58
|
+
@image = self.animation.next if self.animation
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# heli.png will be loaded
|
64
|
+
# since it doesn't contain any framesize information, chingu will assume same width and height
|
65
|
+
#
|
66
|
+
class Heli < Actor
|
67
|
+
trait :animation, :delay => 200
|
68
|
+
|
69
|
+
def update
|
70
|
+
@image = self.animation.next if self.animation
|
71
|
+
p self.animation
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# star_25x25_default.png and star_25x25_explode.png will be loaded.
|
77
|
+
# Access the 2 animation-"states" with self.animations[:default] and self.animations[:explode]
|
78
|
+
# self.animation will point to self.animations[:default]
|
79
|
+
#
|
80
|
+
class Star < Actor
|
81
|
+
trait :animation, :delay => 100
|
82
|
+
|
83
|
+
def setup
|
84
|
+
self.animations[:explode].loop = false
|
85
|
+
end
|
86
|
+
|
87
|
+
def update
|
88
|
+
|
89
|
+
if @x < $window.width/2 || @y < $window.height/2
|
90
|
+
@image = self.animations[:explode].next
|
91
|
+
else
|
92
|
+
@image = self.animations[:default].next
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
Game.new.show
|
@@ -0,0 +1,223 @@
|
|
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
|
+
# viewport-trait / edit-trait example
|
9
|
+
#
|
10
|
+
# Press 'E' when demo is running to edit the playfield!
|
11
|
+
#
|
12
|
+
class Game < Chingu::Window
|
13
|
+
def setup
|
14
|
+
Gosu::enable_undocumented_retrofication
|
15
|
+
self.factor = 3
|
16
|
+
#self.input = { :escape => :exit }
|
17
|
+
switch_game_state(Level.new)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Level < GameState
|
22
|
+
#
|
23
|
+
# This adds accessor 'viewport' to class and overrides draw() to use it.
|
24
|
+
#
|
25
|
+
trait :viewport
|
26
|
+
|
27
|
+
#
|
28
|
+
# We create our 3 different game objects in this order:
|
29
|
+
# 1) map 2) stars 3) player
|
30
|
+
# Since we don't give any zorders Chingu automatically increments zorder between each object created, putting player on top
|
31
|
+
#
|
32
|
+
def setup
|
33
|
+
self.input = { :escape => :exit, :e => :edit }
|
34
|
+
|
35
|
+
Sound["laser.wav"] # cache sound by accessing it once
|
36
|
+
|
37
|
+
self.viewport.lag = 0 # 0 = no lag, 0.99 = a lot of lag.
|
38
|
+
self.viewport.game_area = [0, 0, 1000, 1000] # Viewport restrictions, full "game world/map/area"
|
39
|
+
|
40
|
+
#
|
41
|
+
# Create 40 stars scattered around the map. This is now replaced by load_game_objects()
|
42
|
+
# ## 40.times { |nr| Star.create(:x => rand * self.viewport.x_max, :y => rand * self.viewport.y_max) }
|
43
|
+
#
|
44
|
+
load_game_objects( :file => "example19_game_objects.yml" )
|
45
|
+
|
46
|
+
# Create our mechanic star-hunter
|
47
|
+
@droid = Droid.create(:x => 100, :y => 100)
|
48
|
+
end
|
49
|
+
|
50
|
+
def edit
|
51
|
+
push_game_state(GameStates::Edit.new(:file => "example19_game_objects.yml", :classes => [Star, StoneWall]))
|
52
|
+
end
|
53
|
+
|
54
|
+
def update
|
55
|
+
super
|
56
|
+
|
57
|
+
# Droid can pick up starts
|
58
|
+
@droid.each_collision(Star) do |droid, star|
|
59
|
+
star.destroy
|
60
|
+
Sound["laser.wav"].play(0.5)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Bullets collide with stone_walls
|
64
|
+
Bullet.each_collision(StoneWall) do |bullet, stone_wall|
|
65
|
+
bullet.die
|
66
|
+
stone_wall.destroy
|
67
|
+
end
|
68
|
+
|
69
|
+
# Destroy game objects that travels outside the viewport
|
70
|
+
game_objects.destroy_if { |game_object| self.viewport.outside_game_area?(game_object) }
|
71
|
+
|
72
|
+
#
|
73
|
+
# Align viewport with the droid in the middle.
|
74
|
+
# This will make droid will be in the center of the screen all the time...
|
75
|
+
# ...except when hitting outer borders and viewport x_min/max & y_min/max kicks in.
|
76
|
+
#
|
77
|
+
self.viewport.center_around(@droid)
|
78
|
+
|
79
|
+
$window.caption = "viewport/edit-trait example. Move with arrows! Press 'E' to 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}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class Droid < Chingu::GameObject
|
84
|
+
trait :bounding_box, :debug => false
|
85
|
+
traits :timer, :collision_detection , :timer
|
86
|
+
attr_accessor :last_x, :last_y, :direction
|
87
|
+
|
88
|
+
def setup
|
89
|
+
#
|
90
|
+
# This shows up the shortened version of input-maps, where each key calls a method of the very same name.
|
91
|
+
# Use this by giving an array of symbols to self.input
|
92
|
+
#
|
93
|
+
self.input = { [:holding_left, :holding_a] => :holding_left,
|
94
|
+
[:holding_right, :holding_d] => :holding_right,
|
95
|
+
[:holding_up, :holding_w] => :holding_up,
|
96
|
+
[:holding_down, :holding_s] => :holding_down,
|
97
|
+
:space => :fire
|
98
|
+
}
|
99
|
+
|
100
|
+
# Load the full animation from tile-file media/droid.bmp
|
101
|
+
@animations = Chingu::Animation.new(:file => "droid_11x15.bmp")
|
102
|
+
@animations.frame_names = { :scan => 0..5, :up => 6..7, :down => 8..9, :left => 10..11, :right => 12..13 }
|
103
|
+
|
104
|
+
# Start out by animation frames 0-5 (contained by @animations[:scan])
|
105
|
+
@animation = @animations[:scan]
|
106
|
+
@speed = 3
|
107
|
+
@last_x, @last_y = @x, @y
|
108
|
+
|
109
|
+
update
|
110
|
+
end
|
111
|
+
|
112
|
+
def holding_left
|
113
|
+
move(-@speed, 0)
|
114
|
+
@animation = @animations[:left]
|
115
|
+
end
|
116
|
+
|
117
|
+
def holding_right
|
118
|
+
move(@speed, 0)
|
119
|
+
@animation = @animations[:right]
|
120
|
+
end
|
121
|
+
|
122
|
+
def holding_up
|
123
|
+
move(0, -@speed)
|
124
|
+
@animation = @animations[:up]
|
125
|
+
end
|
126
|
+
|
127
|
+
def holding_down
|
128
|
+
move(0, @speed)
|
129
|
+
@animation = @animations[:down]
|
130
|
+
end
|
131
|
+
|
132
|
+
def fire
|
133
|
+
Bullet.create(:x => self.x, :y => self.y, :velocity => @direction)
|
134
|
+
end
|
135
|
+
|
136
|
+
#
|
137
|
+
# Revert player to last positions when:
|
138
|
+
# - player is outside the viewport
|
139
|
+
# - player is colliding with at least one object of class StoneWall
|
140
|
+
#
|
141
|
+
def move(x,y)
|
142
|
+
@x += x
|
143
|
+
@x = @last_x if self.parent.viewport.outside_game_area?(self) || self.first_collision(StoneWall)
|
144
|
+
|
145
|
+
@y += y
|
146
|
+
@y = @last_y if self.parent.viewport.outside_game_area?(self) || self.first_collision(StoneWall)
|
147
|
+
end
|
148
|
+
|
149
|
+
# We don't need to call super() in update().
|
150
|
+
# By default GameObject#update is empty since it doesn't contain any gamelogic to speak of.
|
151
|
+
def update
|
152
|
+
|
153
|
+
# Move the animation forward by fetching the next frame and putting it into @image
|
154
|
+
# @image is drawn by default by GameObject#draw
|
155
|
+
@image = @animation.next
|
156
|
+
|
157
|
+
if @x == @last_x && @y == @last_y
|
158
|
+
# droid stands still, use the scanning animation
|
159
|
+
@animation = @animations[:scan]
|
160
|
+
else
|
161
|
+
# Save the direction to use with bullets when firing
|
162
|
+
@direction = [@x - @last_x, @y - @last_y]
|
163
|
+
end
|
164
|
+
|
165
|
+
@last_x, @last_y = @x, @y
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class Star < GameObject
|
170
|
+
trait :bounding_circle, :debug => false
|
171
|
+
trait :collision_detection
|
172
|
+
|
173
|
+
def setup
|
174
|
+
@animation = Chingu::Animation.new(:file => "Star.png", :size => 25)
|
175
|
+
@image = @animation.next
|
176
|
+
self.color = Gosu::Color.new(0xff000000)
|
177
|
+
self.color.red = rand(255 - 40) + 40
|
178
|
+
self.color.green = rand(255 - 40) + 40
|
179
|
+
self.color.blue = rand(255 - 40) + 40
|
180
|
+
self.factor = 1
|
181
|
+
#self.rotation_center = :center
|
182
|
+
|
183
|
+
#
|
184
|
+
# A cached bounding circle will not adapt to changes in size, but it will follow objects X / Y
|
185
|
+
# Same is true for "cache_bounding_box"
|
186
|
+
#
|
187
|
+
cache_bounding_circle
|
188
|
+
end
|
189
|
+
|
190
|
+
def update
|
191
|
+
# Move the animation forward by fetching the next frame and putting it into @image
|
192
|
+
# @image is drawn by default by GameObject#draw
|
193
|
+
@image = @animation.next
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class StoneWall < GameObject
|
198
|
+
trait :bounding_box, :debug => false
|
199
|
+
trait :collision_detection
|
200
|
+
|
201
|
+
def setup
|
202
|
+
@image = Image["stone_wall.bmp"]
|
203
|
+
self.factor = 1
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class Bullet < GameObject
|
208
|
+
traits :bounding_circle, :collision_detection, :velocity, :timer
|
209
|
+
|
210
|
+
def setup
|
211
|
+
@image = Image["fire_bullet.png"]
|
212
|
+
self.factor = 1
|
213
|
+
self.velocity_x *= 2
|
214
|
+
self.velocity_y *= 2
|
215
|
+
end
|
216
|
+
|
217
|
+
def die
|
218
|
+
self.velocity = [0,0]
|
219
|
+
between(0,50) { self.factor += 0.3; self.alpha -= 10; }.then { destroy }
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
Game.new.show
|