singpolyma-xgame 0.0.1

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 (6) hide show
  1. data/COPYING +22 -0
  2. data/README +8 -0
  3. data/TODO +1 -0
  4. data/lib/xgame.rb +371 -0
  5. data/xgame.gemspec +19 -0
  6. metadata +67 -0
data/COPYING ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2008 Stephen Paul Weber.
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,8 @@
1
+ This is XGame, a cross-platform game development framework based on RubyGame and SDL.
2
+
3
+ To run this demo you must have ruby and the rubygems system installed, then run:
4
+
5
+ sudo gem install rubygame
6
+
7
+ to install the rubygame dependency. You may need to install build tools, ruby headers, and SDL
8
+ libraries/headers in order to install rubygame. These should be in your software repositories.
data/TODO ADDED
@@ -0,0 +1 @@
1
+ * Scrollable background
data/lib/xgame.rb ADDED
@@ -0,0 +1,371 @@
1
+ begin
2
+ require 'rubygame'
3
+
4
+ # If we are operating without rubygems (preferred) some features are still nice
5
+ # define the Gem class to keep a standard API
6
+ class Gem
7
+ @@user_home = '/'
8
+ def self.user_home
9
+ @@user_home ||= find_home
10
+ end
11
+
12
+ def self.find_home
13
+ ['HOME', 'USERPROFILE'].each do |homekey|
14
+ return ENV[homekey] if ENV[homekey]
15
+ end
16
+
17
+ if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
18
+ return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
19
+ end
20
+
21
+ begin
22
+ File.expand_path("~")
23
+ rescue
24
+ if File::ALT_SEPARATOR then
25
+ 'C:/'
26
+ else
27
+ '/'
28
+ end
29
+ end
30
+ end
31
+ end
32
+ rescue LoadError
33
+ require 'rubygems'
34
+ require 'rubygame'
35
+ end
36
+
37
+ # Extend the Rubygame namespace
38
+ module Rubygame
39
+
40
+ # This class defines an easy way to manage callbacks
41
+ class ListenerList < Hash
42
+ def addEventListener(event, callback=nil, &block)
43
+ callback = block unless callback
44
+ self[event] = [] unless self.key?event
45
+ self[event] << callback
46
+ end
47
+ end
48
+
49
+ class LoopEvent < Event
50
+ end
51
+
52
+ # Extend the Sprites namespace
53
+ module Sprites
54
+
55
+ # This is a mixin module for sprites that move
56
+ module MovingSprite
57
+
58
+ def initialize(*args)
59
+ super
60
+ @velocity = {:left => 0, :right => 0, :up => 0, :down => 0} # These are the initial components of velocity
61
+ @going = {:left => false, :right => false, :up => false, :down => false} # Are we "going" in these directions or just travelling?
62
+ @reference = [0,0] # Moving frame of reference
63
+ @animating = {:left => [0,0], :right => [0,0], :up => [0,0], :down => [0,0]}
64
+ @speed = 50 # This can be overidden by implementations: it is how fast / massive the sprite is
65
+ end
66
+
67
+ def velocity
68
+ [@velocity[:left]*-1 + @velocity[:right], @velocity[:up]*-1 + @velocity[:down]]
69
+ end
70
+
71
+ def going
72
+ @going
73
+ end
74
+
75
+ def reference=(v)
76
+ @reference = v
77
+ end
78
+
79
+ # Go in some direction [vx, vy]. If either is nil, motion on that axis will not be affected.
80
+ def go(v, duration=0)
81
+ if v[0]
82
+ if v[0] <= 0
83
+ @animating[:left] = [duration, @velocity[:left]]
84
+ @velocity[:left] = v[0]*-1
85
+ @going[:left] = true
86
+ end
87
+ if v[0] >= 0
88
+ @animating[:right] = [duration, @velocity[:right]]
89
+ @velocity[:right] = v[0]
90
+ @going[:right] = true
91
+ end
92
+ end
93
+ if v[1]
94
+ if v[1] <= 0
95
+ @animating[:up] = [duration, @velocity[:up]]
96
+ @velocity[:up] = v[1]*-1
97
+ @going[:up] = true
98
+ end
99
+ if v[1] >= 0
100
+ @animating[:down] = [duration, @velocity[:down]]
101
+ @velocity[:down] = v[1]
102
+ @going[:down] = true
103
+ end
104
+ end
105
+ end
106
+
107
+ # Stop some component of motion
108
+ def stop(direction, duration=0)
109
+ @animating[direction] = [duration, @animating[direction][0] >= 1 ? @animating[direction][1] : @velocity[direction]]
110
+ @velocity[direction] = 0
111
+ @going[direction] = false
112
+ end
113
+
114
+ # Strike the sprite in a certain direction
115
+ def hit(v, by=nil)
116
+ self.go(v,[2,(1/(XGame.framerate/1000.0))/(@speed/4)].max)
117
+ end
118
+
119
+ # Apply a force to this sprite [vx, vy, max_applied (optional)]
120
+ def apply_force(value)
121
+ @velocity[:left] += value[0]*-1 if value[0] < 0 and (!value[2][:left] or @velocity[:left] < value[2][:left])
122
+ @velocity[:right] += value[0] if value[0] > 0 and (!value[2][:right] or @velocity[:right] < value[2][:right])
123
+ @velocity[:up] += value[1]*-1 if value[1] < 0 and (!value[2][:up] or @velocity[:up] < value[2][:up])
124
+ @velocity[:down] += value[1] if value[1] > 0 and (!value[2][:down] or @velocity[:down] < value[2][:down])
125
+ end
126
+
127
+ def self.included(base)
128
+ base.class_eval {alias_method :update_no_moving, :update; alias_method :update, :update_moving}
129
+ end
130
+
131
+ def update_moving(time)
132
+ update_no_moving(time)
133
+
134
+ if @animating[:left][0] > 0
135
+ @animating[:left][0] -= 1
136
+ @velocity[:left] = @animating[:left][1] if @animating[:left][0] < 1
137
+ end
138
+ if @animating[:right][0] > 0
139
+ @animating[:right][0] -= 1
140
+ @velocity[:right] = @animating[:right][1] if @animating[:right][0] < 1
141
+ end
142
+ if @animating[:up][0] > 0
143
+ @animating[:up][0] -= 1
144
+ @velocity[:up] = @animating[:up][1] if @animating[:up][0] < 1
145
+ end
146
+ if @animating[:down][0] > 0
147
+ @animating[:down][0] -= 1
148
+ @velocity[:down] = @animating[:down][1] if @animating[:down][0] < 1
149
+ end
150
+ x,y = @rect.center
151
+ base = @speed * time/1000.0
152
+
153
+ @rect.centerx = x + (@reference[0] + velocity[0]) * base
154
+ @rect.centery = y + (@reference[1] + velocity[1]) * base
155
+ @reference = [0,0] # Frame of reference must be reset every frame
156
+ end
157
+
158
+ end # module MovingSprite
159
+
160
+ # This is a mixin module to allow a sprite to let things pass through some edges
161
+ module EdgeSprite
162
+ attr_accessor :edges
163
+ end
164
+
165
+ # This is a mixin module for groups that keep their sprites in a particular region of the screen
166
+ module BoundedGroup
167
+
168
+ # Bounding box (of type Rubygame::Rect)
169
+ attr_accessor :bounds
170
+ def bounds
171
+ @bounds ||= Rubygame::Screen.get_surface().make_rect()
172
+ end
173
+
174
+ def update(*args)
175
+ super(*args)
176
+ self.each { |sprite|
177
+ if sprite.rect.top < bounds.top
178
+ sprite.rect.top = bounds.top
179
+ sprite.stop(:up) if sprite.respond_to?(:stop)
180
+ end
181
+ if sprite.rect.bottom > bounds.bottom
182
+ sprite.rect.bottom = bounds.bottom
183
+ sprite.stop(:down) if sprite.respond_to?(:stop)
184
+ end
185
+ if sprite.rect.left < bounds.left
186
+ sprite.rect.left = bounds.left
187
+ sprite.stop(:left) if sprite.respond_to?(:stop)
188
+ end
189
+ if sprite.rect.right > bounds.right
190
+ sprite.rect.right = bounds.right
191
+ sprite.stop(:right) if sprite.respond_to?(:stop)
192
+ end
193
+ }
194
+ end
195
+
196
+ end
197
+
198
+ # This is a mixin module for groups of sprites with a constant force acting on them
199
+ module ForceGroup
200
+ # Force vector [vx, vy, max_applied (optional)]
201
+ def force=(value)
202
+ value[2] = {} unless value
203
+ @force = value
204
+ end
205
+
206
+ def update(*args)
207
+ super(*args)
208
+ force = [@force[0] * args[0]/1000.0, @force[1] * args[0]/1000.0, @force[2]] # Make sure force is applied the same no matter how fast we're rendering
209
+ self.each { |sprite|
210
+ sprite.apply_force(force) if sprite.respond_to?(:apply_force)
211
+ }
212
+ end
213
+ end # module ForceGroup
214
+
215
+ # This is a mixin module for collisions between sprites
216
+ module CollideGroup
217
+
218
+ def update(*args)
219
+ super(*args)
220
+ self.each { |sprite|
221
+ self.each { |sprite2|
222
+ if sprite != sprite2 and sprite.respond_to?(:stop) and sprite.collide_sprite?sprite2
223
+ @sprite2_edges = {:top => true, :bottom => true, :left => true, :right => true}
224
+ @sprite2_edges = sprite2.edges if sprite2.respond_to?(:edges)
225
+ d = sprite2.rect.top - sprite.rect.bottom
226
+ if d < 0 and d > -5 and @sprite2_edges[:top] # Sprite is on top
227
+ if !sprite.respond_to?(:velocity) or sprite.velocity[1] > 0
228
+ sprite2.hit([nil,sprite.velocity[1]], sprite) if sprite2.respond_to?(:hit)
229
+ sprite.rect.bottom += d if (!sprite.respond_to?(:edges) or sprite.edges[:bottom])
230
+ end
231
+ sprite.stop(:down, (!sprite.respond_to?(:going) or sprite.going[:down]) ? 1/(args[0]/1000.0) * 0.1 : 0)
232
+ end
233
+ d = sprite.rect.top - sprite2.rect.bottom
234
+ if d < 0 and d > -5 and @sprite2_edges[:bottom] # Sprite is on bottom
235
+ if !sprite.respond_to?(:velocity) or sprite.velocity[1] < 0
236
+ sprite2.hit([nil,sprite.velocity[1]], sprite) if sprite2.respond_to?(:hit)
237
+ sprite.rect.top += d if !sprite.respond_to?(:edges) or sprite.edges[:top]
238
+ end
239
+ sprite.stop(:up, (!sprite.respond_to?(:going) or sprite.going[:up]) ? 1/(args[0]/1000.0) * 0.1 : 0)
240
+ end
241
+ d = sprite2.rect.left - sprite.rect.right
242
+ if d < 0 and d > -5 and @sprite2_edges[:left] # Sprite is on left
243
+ if !sprite.respond_to?(:velocity) or sprite.velocity[0] > 0
244
+ sprite2.hit([sprite.velocity[0],nil], sprite) if sprite2.respond_to?(:hit)
245
+ sprite.rect.right += d if !sprite.respond_to?(:edges) or sprite.edges[:right]
246
+ end
247
+ sprite.stop(:right, (!sprite.respond_to?(:going) or sprite.going[:right]) ? 1/(args[0]/1000.0) * 0.1 : 0)
248
+ end
249
+ d = sprite.rect.left - sprite2.rect.right
250
+ if d < 0 and d > -5 and @sprite2_edges[:right] # Sprite is on right
251
+ if !sprite.respond_to?(:velocity) or sprite.velocity[0] < 0
252
+ sprite2.hit([sprite.velocity[0],nil], sprite) if sprite2.respond_to?(:hit)
253
+ sprite.rect.left += d if (!sprite.respond_to?(:edges) or sprite.edges[:left])
254
+ end
255
+ sprite.stop(:left, (!sprite.respond_to?(:going) or sprite.going[:left]) ? 1/(args[0]/1000.0) * 0.1 : 0)
256
+ end
257
+ end
258
+ }
259
+ }
260
+ end
261
+ end
262
+
263
+ # This is a basic class for updatable, image-based, sprites with a rectangular box matching their image
264
+ class BasicSprite
265
+ include Rubygame::Sprites::Sprite
266
+
267
+ # Override this in subclasses to have a default image
268
+ def self.default_image; end;
269
+
270
+ # Create a new BasicSprite. Pass x, y coordinates for location to spawn.
271
+ # Pass path to image if you have not ovrriden default_image
272
+ def initialize(x,y,image=nil)
273
+ super()
274
+ if image
275
+ @image = Rubygame::Surface[image]
276
+ throw "Image #{image} failed to load. Looking in: #{Rubygame::Surface.autoload_dirs.join(":")}" unless @image
277
+ else
278
+ @image = default_image
279
+ end
280
+ @rect = Rubygame::Rect.new(x,y,*@image.size)
281
+ end
282
+
283
+ def update(time); end
284
+
285
+ end # class BasicMovingBoundedSprit
286
+
287
+ end # module Sprites
288
+
289
+ end # module Rubygame
290
+
291
+ class XGame
292
+
293
+ @@framerate = 60
294
+ def self.framerate
295
+ @@framerate
296
+ end
297
+
298
+ # This method is the heart of XGame. Call it with a block that sets up your program.
299
+ def self.run(title = 'XGame', size = [], framerate = @@framerate, ignore_events = [], &block)
300
+
301
+ Rubygame.init() # Set stuff up
302
+
303
+ if Rubygame::Screen.respond_to?(:get_resolution)
304
+ size[0] = Rubygame::Screen.get_resolution[0] unless size[0]
305
+ size[1] = Rubygame::Screen.get_resolution[1] unless size[1]
306
+ else
307
+ size[0] = 640 unless size[0]
308
+ size[1] = 480 unless size[1]
309
+ end
310
+
311
+ # The events queue gets filled up with all user input into our window
312
+ events = Rubygame::EventQueue.new()
313
+ events.ignore = ignore_events # Let's save cycles by ignoring events of some types
314
+
315
+ # The clock keeps us from eating the CPU
316
+ clock = Rubygame::Clock.new()
317
+ clock.target_framerate = framerate # Let's aim to render at some framerate
318
+
319
+ # Set up autoloading for Surfaces. Surfaces will be loaded automatically the first time you use Surface["filename"].
320
+ Rubygame::Surface.autoload_dirs = [ File.dirname($0) ] # XXX: this should include other paths depending on the platform
321
+
322
+ # Create a world for sprites to live in
323
+ world = Rubygame::Sprites::Group.new
324
+ world.extend(Rubygame::Sprites::DepthSortGroup) # Let them get in front of each other
325
+
326
+ # Grab the screen and create a background
327
+ screen = Rubygame::Screen.new(size, 0, [Rubygame::HWSURFACE, Rubygame::NOFRAME])
328
+ background = Rubygame::Surface.new(screen.size)
329
+
330
+ # This is where event handlers will get stored
331
+ listeners = Rubygame::ListenerList.new
332
+
333
+ # Include the user code
334
+ yield screen, background, world, listeners
335
+
336
+ # Refresh the screen once. During the loop, we'll use 'dirty rect' updating
337
+ # to refresh only the parts of the screen that have changed.
338
+ screen.update()
339
+
340
+ catch(:quit) do
341
+ loop do
342
+ events.push Rubygame::LoopEvent.new
343
+ events.each do |event|
344
+ case event
345
+ when Rubygame::ActiveEvent
346
+ # ActiveEvent appears when the window gains or loses focus.
347
+ # This helps to ensure everything is refreshed after the Rubygame window has been covered up by a different window.
348
+ screen.update()
349
+ when Rubygame::QuitEvent
350
+ # QuitEvent appears when the user closes the window, or otherwise signals they wish to quit
351
+ throw :quit
352
+ else
353
+ listeners[event.class].each { |callback| callback.call(event) } if listeners.key?(event.class)
354
+ end
355
+ end
356
+
357
+ world.undraw(screen, background)
358
+ @@framerate = clock.tick
359
+ world.update(@@framerate)
360
+ screen.update_rects(world.draw(screen))
361
+
362
+ screen.title = "#{title} [#{clock.framerate.to_i} fps]"
363
+ end
364
+ end
365
+
366
+ puts "#{title} is Quitting!"
367
+ Rubygame.quit()
368
+
369
+ end #run
370
+
371
+ end #XGame
data/xgame.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "xgame"
3
+ s.version = "0.0.1"
4
+ s.date = "2008-10-18"
5
+ s.summary = "High-level game framework based on rubygame"
6
+ s.email = "singpolyma@singpolyma.net"
7
+ s.homepage = "http://github.com/singpolyma/xgame"
8
+ s.description = "High-level game framework based on rubygame"
9
+ s.has_rdoc = true
10
+ s.authors = ['Stephen Paul Weber']
11
+ s.files = ["README",
12
+ "TODO",
13
+ "COPYING",
14
+ "xgame.gemspec",
15
+ "lib/xgame.rb"]
16
+ s.extra_rdoc_files = ["README", "COPYING", "TODO"]
17
+ s.add_dependency("rubygame", ["> 0.0.0"])
18
+ end
19
+
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: singpolyma-xgame
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Paul Weber
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-10-18 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rubygame
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">"
21
+ - !ruby/object:Gem::Version
22
+ version: 0.0.0
23
+ version:
24
+ description: High-level game framework based on rubygame
25
+ email: singpolyma@singpolyma.net
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README
32
+ - COPYING
33
+ - TODO
34
+ files:
35
+ - README
36
+ - TODO
37
+ - COPYING
38
+ - xgame.gemspec
39
+ - lib/xgame.rb
40
+ has_rdoc: true
41
+ homepage: http://github.com/singpolyma/xgame
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.2.0
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: High-level game framework based on rubygame
66
+ test_files: []
67
+