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