gosu-examples 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +14 -0
  4. data/bin/gosu-examples +97 -0
  5. data/examples/chipmunk_and_rmagick.rb +152 -0
  6. data/examples/chipmunk_integration.rb +278 -0
  7. data/examples/cptn_ruby.rb +229 -0
  8. data/examples/media/BrokenPNG.png +0 -0
  9. data/examples/media/Cursor.png +0 -0
  10. data/examples/media/JingleBells.mp3 +0 -0
  11. data/examples/media/JingleBells.ogg +0 -0
  12. data/examples/media/Loop.wav +0 -0
  13. data/examples/media/Sample.wav +0 -0
  14. data/examples/media/SquareTexture.png +0 -0
  15. data/examples/media/Wallpaper.png +0 -0
  16. data/examples/media/WallpaperXXL.png +0 -0
  17. data/examples/media/WhiteAlpha.png +0 -0
  18. data/examples/media/audio_formats/aiff_32bit_float.aiff +0 -0
  19. data/examples/media/audio_formats/au_16bit_pcm.au +0 -0
  20. data/examples/media/audio_formats/caf_be_16bit_44khz.caf +0 -0
  21. data/examples/media/audio_formats/caf_le_16bit_44khz.caf +0 -0
  22. data/examples/media/audio_formats/caf_le_8bit_44khz.caf +0 -0
  23. data/examples/media/audio_formats/general_midi.mid +0 -0
  24. data/examples/media/audio_formats/impulse_tracker.it +0 -0
  25. data/examples/media/audio_formats/mp3_128k_stereo.mp3 +0 -0
  26. data/examples/media/audio_formats/mp3_avg_96kbit_jointstereo.mp3 +0 -0
  27. data/examples/media/audio_formats/ogg_vorbis.ogg +0 -0
  28. data/examples/media/audio_formats/wav_16bit_pcm.wav +0 -0
  29. data/examples/media/audio_formats/wav_32bit_pcm.wav +0 -0
  30. data/examples/media/audio_formats/wav_4bit_ms_adpcm.wav +0 -0
  31. data/examples/media/beep.wav +0 -0
  32. data/examples/media/cptn_ruby.png +0 -0
  33. data/examples/media/cptn_ruby_map.txt +25 -0
  34. data/examples/media/earth.png +0 -0
  35. data/examples/media/explosion.wav +0 -0
  36. data/examples/media/gem.png +0 -0
  37. data/examples/media/header.psd +0 -0
  38. data/examples/media/image_formats/test.jpg +0 -0
  39. data/examples/media/image_formats/test.psd +0 -0
  40. data/examples/media/landscape.svg +10 -0
  41. data/examples/media/large_star.png +0 -0
  42. data/examples/media/smoke.png +0 -0
  43. data/examples/media/soldier.png +0 -0
  44. data/examples/media/space.png +0 -0
  45. data/examples/media/star.png +0 -0
  46. data/examples/media/starfighter.bmp +0 -0
  47. data/examples/media/tileset.png +0 -0
  48. data/examples/media/vera.ttf +0 -0
  49. data/examples/opengl_integration.rb +224 -0
  50. data/examples/rmagick_integration.rb +413 -0
  51. data/examples/tutorial.rb +129 -0
  52. data/examples/welcome.rb +59 -0
  53. data/lib/gosu-examples/example.rb +82 -0
  54. data/lib/gosu-examples/sidebar.rb +60 -0
  55. metadata +112 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8eb4367ee4c008b79167bda5845113c7513eedd4
4
+ data.tar.gz: 9b6fe668a5ed7f24da588abdb4f6f9dcbe600f81
5
+ SHA512:
6
+ metadata.gz: cacab6fb2e19440bb1b1b84043f4a3936c5b84c48734809a3e8452252ac5509cd9b743d117afc81fa2d7a300c5593a35e32dfb13a0d030ffeb8bef0efe5367eb
7
+ data.tar.gz: aed9c85c7dc6c65a7bf585867f77344a6617273310bcba784f1a15ca0c932ab8eb9984fe3900c3bbf1d693371e10b8fb58e13a7b7325f23d52c14a5ca363869f
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Julian Raschke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,14 @@
1
+ Gosu Examples
2
+ =============
3
+
4
+ This is a collection of Ruby example games for the [Gosu media library](https://libgosu.org/).
5
+
6
+ To run the examples, simply install the `gosu-examples` Ruby gem and then run `gosu-examples` in the terminal.
7
+
8
+ Some examples require the following libraries to be installed:
9
+
10
+ `gem install chipmunk`
11
+ `gem install rmagick`
12
+ `gem install opengl`
13
+
14
+ (This is a very rough first version of this gem. Feel free to contribute to all parts of this repository via Pull Requests - media files, more examples, cleaning up code... - as long as we can use your contributions under the MIT license.)
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'gosu'
5
+
6
+ Dir.chdir "#{File.dirname __FILE__}/../examples"
7
+
8
+ $LOAD_PATH << "#{File.dirname __FILE__}/../lib/gosu-examples"
9
+
10
+ require 'example'
11
+ require 'sidebar'
12
+
13
+ Example.load_examples "{.,../features}/*.rb" # TODO - should be *.rb
14
+
15
+ class ExampleBox < Gosu::Window
16
+ # TODO - the ExampleWindow should resize to fit once Gosu::Window#resize has been added.
17
+ # See https://github.com/jlnr/gosu/issues/255
18
+ EXAMPLE_WIDTH = 600
19
+ EXAMPLE_HEIGHT = 600
20
+
21
+ def initialize
22
+ super Sidebar::WIDTH + EXAMPLE_WIDTH, EXAMPLE_HEIGHT, :fullscreen => ARGV.include?('--fullscreen')
23
+
24
+ @sidebar = Sidebar.new { |example| change_example(example) }
25
+
26
+ welcome_class = Example.examples.find { |example| example.name =~ /::Welcome$/ }
27
+ @current_example = welcome_class.new
28
+ end
29
+
30
+ def update
31
+ self.caption = "Gosu Example Box - #{@current_example.caption} (#{Gosu::fps} FPS)"
32
+
33
+ @current_example.update
34
+ end
35
+
36
+ def draw
37
+ @current_example.draw
38
+
39
+ flush
40
+
41
+ translate(EXAMPLE_WIDTH, 0) do
42
+ current_filename = @current_example.class.source_file
43
+ @sidebar.draw(current_filename)
44
+ end
45
+ end
46
+
47
+ def button_down(id)
48
+ case id
49
+ when Gosu::KbEscape
50
+ close
51
+ when char_to_button_id('S')
52
+ if filename = @current_example.class.source_file then
53
+ open_file_or_folder filename
54
+ end
55
+ when char_to_button_id('O')
56
+ if filename = @current_example.class.source_file then
57
+ open_file_or_folder File.dirname(filename)
58
+ end
59
+ else
60
+ if id == Gosu::MsLeft and mouse_x >= EXAMPLE_WIDTH then
61
+ @sidebar.click(mouse_x - EXAMPLE_WIDTH, mouse_y)
62
+ else
63
+ @current_example.button_down(id)
64
+ end
65
+ end
66
+ end
67
+
68
+ def button_up(id)
69
+ @current_example.button_up(id)
70
+ end
71
+
72
+ def needs_cursor?
73
+ true
74
+ end
75
+
76
+ private
77
+
78
+ def change_example(example)
79
+ if @current_example.class != example then
80
+ @current_example = nil
81
+ GC.start
82
+ @current_example = example.new
83
+ end
84
+ end
85
+
86
+ def open_file_or_folder(filename)
87
+ if RUBY_PLATFORM =~ /darwin[0-9]*$/ then
88
+ `open '#{filename}'`
89
+ elsif RUBY_PLATFORM =~ /mingw[0-9]*$/ then
90
+ `explorer '#{filename}'`
91
+ else
92
+ `xdg-open '#{filename}'`
93
+ end
94
+ end
95
+ end
96
+
97
+ ExampleBox.new.show
@@ -0,0 +1,152 @@
1
+ # Encoding: UTF-8
2
+
3
+ # Based on the C Demo3 demonstration distributed with Chipmunk.
4
+ # Also with some help from the chipmunk_integration.rb program.
5
+ #
6
+ # License: Same as for Gosu (MIT)
7
+ # Created on 21/10/2007, 00:05:19 by Robert Sheehan
8
+
9
+ require 'rubygems'
10
+ require 'gosu'
11
+ require 'chipmunk'
12
+ require 'rmagick'
13
+
14
+ # Layering of sprites
15
+ module ZOrder
16
+ Background, Box = *0..1
17
+ end
18
+
19
+ WIDTH = 600
20
+ HEIGHT = 600
21
+ TICK = 1.0/60.0
22
+ NUM_POLYGONS = 80
23
+ NUM_SIDES = 4
24
+ EDGE_SIZE = 15
25
+
26
+ class ChipmunkAndRMagick < (Example rescue Gosu::Window)
27
+ def radians_to_vec2(radians)
28
+ CP::Vec2.new(Math::cos(radians), Math::sin(radians))
29
+ end
30
+
31
+ def initialize
32
+ super WIDTH, HEIGHT
33
+
34
+ self.caption = "Chipmunk, RMagick and Gosu"
35
+
36
+ @space = CP::Space.new
37
+ @space.iterations = 5
38
+ @space.gravity = CP::Vec2.new(0, 100)
39
+
40
+ # you can replace the background with any image with this line
41
+ # background = Magick::ImageList.new("media/space.png")
42
+ fill = Magick::TextureFill.new(Magick::ImageList.new("granite:"))
43
+ background = Magick::Image.new(WIDTH, HEIGHT, fill)
44
+ setup_triangles(background)
45
+ @background_image = Gosu::Image.new(background, :tileable => true) # turn the image into a Gosu one
46
+ @boxes = create_boxes(NUM_POLYGONS)
47
+ end
48
+
49
+ # Create all of the static triangles.
50
+ # Adds them to the space and the background image.
51
+ def setup_triangles(background)
52
+ gc = Magick::Draw.new
53
+ gc.stroke_width(2)
54
+ gc.stroke('red')
55
+ gc.fill('blue')
56
+ # all the triangles are part of the same body
57
+ body = CP::Body.new(Float::MAX, Float::MAX)
58
+ base = 15
59
+ height = 10
60
+ shape_vertices = [CP::Vec2.new(-base, base), CP::Vec2.new(base, base), CP::Vec2.new(0, -height)]
61
+ # make shapes and images
62
+ 8.times do |i|
63
+ 8.times do |j|
64
+ stagger = (j % 2) * 40
65
+ x = i * 80 + stagger
66
+ y = j * 70 + 80
67
+ shape = CP::Shape::Poly.new(body, shape_vertices, CP::Vec2.new(x, y))
68
+ shape.e = 1
69
+ shape.u = 1
70
+ @space.add_static_shape(shape)
71
+ gc.polygon(x - base + 1, y + base - 1, x + base - 1, y + base - 1, x, y - height + 1)
72
+ end
73
+ end
74
+ # do the drawing
75
+ gc.draw(background)
76
+ end
77
+
78
+ # Produces the vertices of a regular polygon.
79
+ def polygon_vertices(sides, size)
80
+ vertices = []
81
+ sides.times do |i|
82
+ angle = -2 * Math::PI * i / sides
83
+ vertices << radians_to_vec2(angle) * size
84
+ end
85
+ return vertices
86
+ end
87
+
88
+ # Produces the image of a polygon.
89
+ def polygon_image(vertices)
90
+ box_image = Magick::Image.new(EDGE_SIZE * 2, EDGE_SIZE * 2) { self.background_color = 'transparent' }
91
+ gc = Magick::Draw.new
92
+ gc.stroke('red')
93
+ gc.fill('plum')
94
+ draw_vertices = vertices.map { |v| [v.x + EDGE_SIZE, v.y + EDGE_SIZE] }.flatten
95
+ gc.polygon(*draw_vertices)
96
+ gc.draw(box_image)
97
+ return Gosu::Image.new(box_image)
98
+ end
99
+
100
+ # Produces the polygon objects and adds them to the space.
101
+ def create_boxes(num)
102
+ box_vertices = polygon_vertices(NUM_SIDES, EDGE_SIZE)
103
+ box_image = polygon_image(box_vertices)
104
+ boxes = []
105
+ num.times do
106
+ body = CP::Body.new(1, CP::moment_for_poly(1.0, box_vertices, CP::Vec2.new(0, 0))) # mass, moment of inertia
107
+ body.p = CP::Vec2.new(rand(WIDTH), rand(40) - 50)
108
+ shape = CP::Shape::Poly.new(body, box_vertices, CP::Vec2.new(0, 0))
109
+ shape.e = 0.0
110
+ shape.u = 0.4
111
+ boxes << Box.new(box_image, body)
112
+ @space.add_body(body)
113
+ @space.add_shape(shape)
114
+ end
115
+ return boxes
116
+ end
117
+
118
+ # All the simulation is done here.
119
+ def update
120
+ @space.step(TICK)
121
+ @boxes.each { |box| box.check_off_screen }
122
+ end
123
+
124
+ # All the updating of the screen is done here.
125
+ def draw
126
+ @background_image.draw(0, 0, ZOrder::Background)
127
+ @boxes.each { |box| box.draw }
128
+ end
129
+ end
130
+
131
+ # The falling boxes class.
132
+ # Nothing more than a body and an image.
133
+ class Box
134
+ def initialize(image, body)
135
+ @image = image
136
+ @body = body
137
+ end
138
+
139
+ # If it goes offscreen we put it back to the top.
140
+ def check_off_screen
141
+ pos = @body.p
142
+ if pos.y > HEIGHT + EDGE_SIZE or pos.x > WIDTH + EDGE_SIZE or pos.x < -EDGE_SIZE
143
+ @body.p = CP::Vec2.new(rand * WIDTH, 0)
144
+ end
145
+ end
146
+
147
+ def draw
148
+ @image.draw_rot(@body.p.x, @body.p.y, ZOrder::Box, @body.a.radians_to_gosu)
149
+ end
150
+ end
151
+
152
+ ChipmunkAndRMagick.new.show if __FILE__ == $0
@@ -0,0 +1,278 @@
1
+ # Encoding: UTF-8
2
+
3
+ ## File: ChipmunkIntegration.rb
4
+ ## Author: Dirk Johnson
5
+ ## Version: 1.0.0
6
+ ## Date: 2007-10-05
7
+ ## License: Same as for Gosu (MIT)
8
+ ## Comments: Based on the Gosu Ruby Tutorial, but incorporating the Chipmunk Physics Engine
9
+ ## See https://github.com/jlnr/gosu/wiki/Ruby-Chipmunk-Integration for the accompanying text.
10
+
11
+ require 'rubygems'
12
+ require 'gosu'
13
+ require 'chipmunk'
14
+
15
+ WIDTH = 600
16
+ HEIGHT = 600
17
+
18
+ # The number of steps to process every Gosu update
19
+ # The Player ship can get going so fast as to "move through" a
20
+ # star without triggering a collision; an increased number of
21
+ # Chipmunk step calls per update will effectively avoid this issue
22
+ SUBSTEPS = 6
23
+
24
+ # Layering of objects
25
+ module ZOrder
26
+ Background, Stars, Player, UI = *0..3
27
+ end
28
+
29
+ # This game will have one Player in the form of a ship
30
+ class Player
31
+ attr_reader :shape
32
+
33
+ def initialize(shape)
34
+ @image = Gosu::Image.new("media/starfighter.bmp")
35
+ @shape = shape
36
+ @shape.body.p = CP::Vec2.new(0.0, 0.0) # position
37
+ @shape.body.v = CP::Vec2.new(0.0, 0.0) # velocity
38
+
39
+ # Keep in mind that down the screen is positive y, which means that PI/2 radians,
40
+ # which you might consider the top in the traditional Trig unit circle sense is actually
41
+ # the bottom; thus 3PI/2 is the top
42
+ @shape.body.a = (3*Math::PI/2.0) # angle in radians; faces towards top of screen
43
+ end
44
+
45
+ # Directly set the position of our Player
46
+ def warp(vect)
47
+ @shape.body.p = vect
48
+ end
49
+
50
+ # Apply negative Torque; Chipmunk will do the rest
51
+ # SUBSTEPS is used as a divisor to keep turning rate constant
52
+ # even if the number of steps per update are adjusted
53
+ def turn_left
54
+ @shape.body.t -= 400.0/SUBSTEPS
55
+ end
56
+
57
+ # Apply positive Torque; Chipmunk will do the rest
58
+ # SUBSTEPS is used as a divisor to keep turning rate constant
59
+ # even if the number of steps per update are adjusted
60
+ def turn_right
61
+ @shape.body.t += 400.0/SUBSTEPS
62
+ end
63
+
64
+ # Apply forward force; Chipmunk will do the rest
65
+ # SUBSTEPS is used as a divisor to keep acceleration rate constant
66
+ # even if the number of steps per update are adjusted
67
+ # Here we must convert the angle (facing) of the body into
68
+ # forward momentum by creating a vector in the direction of the facing
69
+ # and with a magnitude representing the force we want to apply
70
+ def accelerate
71
+ @shape.body.apply_force((radians_to_vec2(@shape.body.a) * (3000.0/SUBSTEPS)), CP::Vec2.new(0.0, 0.0))
72
+ end
73
+
74
+ # Apply even more forward force
75
+ # See accelerate for more details
76
+ def boost
77
+ @shape.body.apply_force((radians_to_vec2(@shape.body.a) * (3000.0)), CP::Vec2.new(0.0, 0.0))
78
+ end
79
+
80
+ # Apply reverse force
81
+ # See accelerate for more details
82
+ def reverse
83
+ @shape.body.apply_force(-(radians_to_vec2(@shape.body.a) * (1000.0/SUBSTEPS)), CP::Vec2.new(0.0, 0.0))
84
+ end
85
+
86
+ # Wrap to the other side of the screen when we fly off the edge
87
+ def validate_position
88
+ l_position = CP::Vec2.new(@shape.body.p.x % WIDTH, @shape.body.p.y % HEIGHT)
89
+ @shape.body.p = l_position
90
+ end
91
+
92
+ def draw
93
+ @image.draw_rot(@shape.body.p.x, @shape.body.p.y, ZOrder::Player, @shape.body.a.radians_to_gosu)
94
+ end
95
+
96
+ private
97
+
98
+ # Convenience method for converting from radians to a Vec2 vector.
99
+ def radians_to_vec2(radians)
100
+ CP::Vec2.new(Math::cos(radians), Math::sin(radians))
101
+ end
102
+ end
103
+
104
+ # See how simple our Star is?
105
+ # Of course... it just sits around and looks good...
106
+ class Star
107
+ attr_reader :shape
108
+
109
+ def initialize(animation, shape)
110
+ @animation = animation
111
+ @color = Gosu::Color.new(0xff_000000)
112
+ @color.red = rand(255 - 40) + 40
113
+ @color.green = rand(255 - 40) + 40
114
+ @color.blue = rand(255 - 40) + 40
115
+ @shape = shape
116
+ @shape.body.p = CP::Vec2.new(rand * WIDTH, rand * HEIGHT) # position
117
+ @shape.body.v = CP::Vec2.new(0.0, 0.0) # velocity
118
+ @shape.body.a = (3*Math::PI/2.0) # angle in radians; faces towards top of screen
119
+ end
120
+
121
+ def draw
122
+ img = @animation[Gosu::milliseconds / 100 % @animation.size];
123
+ img.draw(@shape.body.p.x - img.width / 2.0, @shape.body.p.y - img.height / 2.0, ZOrder::Stars, 1, 1, @color, :add)
124
+ end
125
+ end
126
+
127
+ # The Gosu::Window is always the "environment" of our game
128
+ # It also provides the pulse of our game
129
+ class ChipmunkIntegration < (Example rescue Gosu::Window)
130
+ def initialize
131
+ super WIDTH, HEIGHT
132
+
133
+ self.caption = "Gosu & Chipmunk Integration Demo"
134
+
135
+ @background_image = Gosu::Image.new("media/space.png", :tileable => true)
136
+
137
+ # Put the beep here, as it is the environment now that determines collision
138
+ @beep = Gosu::Sample.new("media/beep.wav")
139
+
140
+ # Put the score here, as it is the environment that tracks this now
141
+ @score = 0
142
+ @font = Gosu::Font.new(20)
143
+
144
+ # Time increment over which to apply a physics "step" ("delta t")
145
+ @dt = (1.0/60.0)
146
+
147
+ # Create our Space and set its damping
148
+ # A damping of 0.8 causes the ship bleed off its force and torque over time
149
+ # This is not realistic behavior in a vacuum of space, but it gives the game
150
+ # the feel I'd like in this situation
151
+ @space = CP::Space.new
152
+ @space.damping = 0.8
153
+
154
+ # Create the Body for the Player
155
+ body = CP::Body.new(10.0, 150.0)
156
+
157
+ # In order to create a shape, we must first define it
158
+ # Chipmunk defines 3 types of Shapes: Segments, Circles and Polys
159
+ # We'll use s simple, 4 sided Poly for our Player (ship)
160
+ # You need to define the vectors so that the "top" of the Shape is towards 0 radians (the right)
161
+ shape_array = [CP::Vec2.new(-25.0, -25.0), CP::Vec2.new(-25.0, 25.0), CP::Vec2.new(25.0, 1.0), CP::Vec2.new(25.0, -1.0)]
162
+ shape = CP::Shape::Poly.new(body, shape_array, CP::Vec2.new(0,0))
163
+
164
+ # The collision_type of a shape allows us to set up special collision behavior
165
+ # based on these types. The actual value for the collision_type is arbitrary
166
+ # and, as long as it is consistent, will work for us; of course, it helps to have it make sense
167
+ shape.collision_type = :ship
168
+
169
+ @space.add_body(body)
170
+ @space.add_shape(shape)
171
+
172
+ @player = Player.new(shape)
173
+ @player.warp(CP::Vec2.new(320, 240)) # move to the center of the window
174
+
175
+ @star_anim = Gosu::Image.load_tiles("media/star.png", 25, 25)
176
+ @stars = Array.new
177
+
178
+ # Here we define what is supposed to happen when a Player (ship) collides with a Star
179
+ # I create a @remove_shapes array because we cannot remove either Shapes or Bodies
180
+ # from Space within a collision closure, rather, we have to wait till the closure
181
+ # is through executing, then we can remove the Shapes and Bodies
182
+ # In this case, the Shapes and the Bodies they own are removed in the Gosu::Window.update phase
183
+ # by iterating over the @remove_shapes array
184
+ # Also note that both Shapes involved in the collision are passed into the closure
185
+ # in the same order that their collision_types are defined in the add_collision_func call
186
+ @remove_shapes = []
187
+ @space.add_collision_func(:ship, :star) do |ship_shape, star_shape|
188
+ @score += 10
189
+ @beep.play
190
+ @remove_shapes << star_shape
191
+ end
192
+
193
+ # Here we tell Space that we don't want one star bumping into another
194
+ # The reason we need to do this is because when the Player hits a Star,
195
+ # the Star will travel until it is removed in the update cycle below
196
+ # which means it may collide and therefore push other Stars
197
+ # To see the effect, remove this line and play the game, every once in a while
198
+ # you'll see a Star moving
199
+ @space.add_collision_func(:star, :star, &nil)
200
+ end
201
+
202
+ def update
203
+ # Step the physics environment SUBSTEPS times each update
204
+ SUBSTEPS.times do
205
+ # This iterator makes an assumption of one Shape per Star making it safe to remove
206
+ # each Shape's Body as it comes up
207
+ # If our Stars had multiple Shapes, as would be required if we were to meticulously
208
+ # define their true boundaries, we couldn't do this as we would remove the Body
209
+ # multiple times
210
+ # We would probably solve this by creating a separate @remove_bodies array to remove the Bodies
211
+ # of the Stars that were gathered by the Player
212
+ @remove_shapes.each do |shape|
213
+ @stars.delete_if { |star| star.shape == shape }
214
+ @space.remove_body(shape.body)
215
+ @space.remove_shape(shape)
216
+ end
217
+ @remove_shapes.clear # clear out the shapes for next pass
218
+
219
+ # When a force or torque is set on a Body, it is cumulative
220
+ # This means that the force you applied last SUBSTEP will compound with the
221
+ # force applied this SUBSTEP; which is probably not the behavior you want
222
+ # We reset the forces on the Player each SUBSTEP for this reason
223
+ @player.shape.body.reset_forces
224
+
225
+ # Wrap around the screen to the other side
226
+ @player.validate_position
227
+
228
+ # Check keyboard
229
+ if Gosu::button_down? Gosu::KbLeft
230
+ @player.turn_left
231
+ end
232
+ if Gosu::button_down? Gosu::KbRight
233
+ @player.turn_right
234
+ end
235
+
236
+ if Gosu::button_down? Gosu::KbUp
237
+ if Gosu::button_down?(Gosu::KbRightShift) or Gosu::button_down?(Gosu::KbLeftShift)
238
+ @player.boost
239
+ else
240
+ @player.accelerate
241
+ end
242
+ elsif Gosu::button_down? Gosu::KbDown
243
+ @player.reverse
244
+ end
245
+
246
+ # Perform the step over @dt period of time
247
+ # For best performance @dt should remain consistent for the game
248
+ @space.step(@dt)
249
+ end
250
+
251
+ # Each update (not SUBSTEP) we see if we need to add more Stars
252
+ if rand(100) < 4 and @stars.size < 25 then
253
+ body = CP::Body.new(0.0001, 0.0001)
254
+ shape = CP::Shape::Circle.new(body, 25/2, CP::Vec2.new(0.0, 0.0))
255
+ shape.collision_type = :star
256
+
257
+ @space.add_body(body)
258
+ @space.add_shape(shape)
259
+
260
+ @stars.push(Star.new(@star_anim, shape))
261
+ end
262
+ end
263
+
264
+ def draw
265
+ @background_image.draw(0, 0, ZOrder::Background)
266
+ @player.draw
267
+ @stars.each { |star| star.draw }
268
+ @font.draw("Score: #{@score}", 10, 10, ZOrder::UI, 1.0, 1.0, 0xff_ffff00)
269
+ end
270
+
271
+ def button_down(id)
272
+ if id == Gosu::KbEscape
273
+ close
274
+ end
275
+ end
276
+ end
277
+
278
+ ChipmunkIntegration.new.show if __FILE__ == $0