gosu-examples 1.0.3

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.
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