gamebox 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.
- data/History.txt +18 -0
- data/Manifest.txt +85 -0
- data/README.txt +33 -0
- data/Rakefile +42 -0
- data/TODO.txt +29 -0
- data/bin/gamebox +49 -0
- data/docs/gamebox04_big.png +0 -0
- data/docs/getting_started.rdoc +99 -0
- data/docs/logo.png +0 -0
- data/lib/gamebox.rb +6 -0
- data/lib/gamebox/actor.rb +143 -0
- data/lib/gamebox/actor_factory.rb +64 -0
- data/lib/gamebox/actor_view.rb +35 -0
- data/lib/gamebox/ai/line_of_site.rb +61 -0
- data/lib/gamebox/ai/polaris.rb +107 -0
- data/lib/gamebox/ai/two_d_grid_location.rb +21 -0
- data/lib/gamebox/ai/two_d_grid_map.rb +77 -0
- data/lib/gamebox/aliasing.rb +16 -0
- data/lib/gamebox/animated.rb +84 -0
- data/lib/gamebox/behavior.rb +16 -0
- data/lib/gamebox/config_manager.rb +22 -0
- data/lib/gamebox/console_app.rb +39 -0
- data/lib/gamebox/data/fonts/Asimov.ttf +0 -0
- data/lib/gamebox/data/fonts/GAMEBOX_FONTS_GO_HERE +0 -0
- data/lib/gamebox/data/graphics/GAMEBOX_GRAPHICS_GO_HERE +0 -0
- data/lib/gamebox/data/graphics/logo.png +0 -0
- data/lib/gamebox/data/music/GAMEBOX_MUSIC_GOES_HERE +0 -0
- data/lib/gamebox/data/sounds/GAMEBOX_SOUND_FX_GO_HERE +0 -0
- data/lib/gamebox/director.rb +47 -0
- data/lib/gamebox/gamebox_application.rb +77 -0
- data/lib/gamebox/graphical.rb +24 -0
- data/lib/gamebox/graphical_actor_view.rb +31 -0
- data/lib/gamebox/inflections.rb +52 -0
- data/lib/gamebox/inflector.rb +278 -0
- data/lib/gamebox/input_manager.rb +104 -0
- data/lib/gamebox/layered.rb +34 -0
- data/lib/gamebox/level.rb +64 -0
- data/lib/gamebox/linked_list.rb +137 -0
- data/lib/gamebox/logo.rb +11 -0
- data/lib/gamebox/metaclass.rb +6 -0
- data/lib/gamebox/mode.rb +123 -0
- data/lib/gamebox/mode_manager.rb +80 -0
- data/lib/gamebox/numbers_ext.rb +3 -0
- data/lib/gamebox/physical.rb +139 -0
- data/lib/gamebox/physical_director.rb +17 -0
- data/lib/gamebox/physical_level.rb +89 -0
- data/lib/gamebox/physics.rb +27 -0
- data/lib/gamebox/publisher_ext.rb +13 -0
- data/lib/gamebox/resource_manager.rb +122 -0
- data/lib/gamebox/score.rb +35 -0
- data/lib/gamebox/sorted_list.rb +59 -0
- data/lib/gamebox/sound_manager.rb +84 -0
- data/lib/gamebox/surface_ext.rb +37 -0
- data/lib/gamebox/svg_actor.rb +55 -0
- data/lib/gamebox/svg_document.rb +160 -0
- data/lib/gamebox/template_app/README +30 -0
- data/lib/gamebox/template_app/Rakefile +20 -0
- data/lib/gamebox/template_app/config/boot.rb +5 -0
- data/lib/gamebox/template_app/config/environment.rb +29 -0
- data/lib/gamebox/template_app/config/game.yml +6 -0
- data/lib/gamebox/template_app/config/mode_level_config.yml +3 -0
- data/lib/gamebox/template_app/config/objects.yml +29 -0
- data/lib/gamebox/template_app/data/fonts/FONTS_GO_HERE +0 -0
- data/lib/gamebox/template_app/data/graphics/GRAPHICS_GO_HERE +0 -0
- data/lib/gamebox/template_app/data/music/MUSIC_GOES_HERE +0 -0
- data/lib/gamebox/template_app/data/sounds/SOUND_FX_GO_HERE +0 -0
- data/lib/gamebox/template_app/doc/README_FOR_APP +1 -0
- data/lib/gamebox/template_app/lib/code_statistics.rb +107 -0
- data/lib/gamebox/template_app/lib/diy.rb +371 -0
- data/lib/gamebox/template_app/lib/platform.rb +16 -0
- data/lib/gamebox/template_app/src/app.rb +8 -0
- data/lib/gamebox/template_app/src/demo_level.rb +20 -0
- data/lib/gamebox/template_app/src/game.rb +22 -0
- data/lib/gamebox/template_app/src/my_actor.rb +17 -0
- data/lib/gamebox/version.rb +10 -0
- data/lib/gamebox/viewport.rb +81 -0
- data/lib/gamebox/wrapped_screen.rb +15 -0
- data/script/perf_polaris.rb +36 -0
- data/test/helper.rb +25 -0
- data/test/test_actor.rb +38 -0
- data/test/test_animated.rb +64 -0
- data/test/test_line_of_site.rb +14 -0
- data/test/test_physical.rb +26 -0
- data/test/test_polaris.rb +193 -0
- data/test/test_viewport.rb +116 -0
- metadata +188 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
class ScoreView < ActorView
|
2
|
+
def draw(target,x_off,y_off)
|
3
|
+
text = @actor.score.to_s
|
4
|
+
text = '0'*(6-text.size)+text
|
5
|
+
|
6
|
+
font = @mode.resource_manager.load_font 'Asimov.ttf', 30
|
7
|
+
text_image = font.render text, true, [250,250,250,255]
|
8
|
+
|
9
|
+
x = @actor.x
|
10
|
+
y = @actor.y
|
11
|
+
|
12
|
+
text_image.blit target.screen, [x,y]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
class Score < Actor
|
16
|
+
attr_accessor :score
|
17
|
+
|
18
|
+
def setup
|
19
|
+
clear
|
20
|
+
end
|
21
|
+
|
22
|
+
def clear
|
23
|
+
@score = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def +(amount)
|
27
|
+
@score += amount
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def -(amount)
|
32
|
+
@score -= amount
|
33
|
+
self
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'linked_list'
|
2
|
+
|
3
|
+
# Keeps a list of items sorted. Elements must be comparable
|
4
|
+
class SortedList
|
5
|
+
attr_reader :list
|
6
|
+
def initialize(initial_list=nil)
|
7
|
+
@list = LinkedList.new
|
8
|
+
unless initial_list.nil?
|
9
|
+
initial_list.each do |item|
|
10
|
+
add item
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(item)
|
16
|
+
added = false
|
17
|
+
@list.each_element do |node|
|
18
|
+
if node.obj > item
|
19
|
+
added = true
|
20
|
+
@list.place item, :before, node
|
21
|
+
break
|
22
|
+
end
|
23
|
+
end
|
24
|
+
@list << item unless added
|
25
|
+
item
|
26
|
+
end
|
27
|
+
alias :<< :add
|
28
|
+
|
29
|
+
def shift
|
30
|
+
@list.shift
|
31
|
+
end
|
32
|
+
|
33
|
+
def empty?
|
34
|
+
@list.empty?
|
35
|
+
end
|
36
|
+
|
37
|
+
def contains?(item)
|
38
|
+
@list.each do |obj|
|
39
|
+
if obj == item
|
40
|
+
return true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def find(item)
|
47
|
+
@list.each do |obj|
|
48
|
+
if obj == item
|
49
|
+
return obj
|
50
|
+
end
|
51
|
+
end
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def size
|
56
|
+
@list.size
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
class SoundManager
|
2
|
+
|
3
|
+
constructor :resource_manager, :config_manager
|
4
|
+
def setup
|
5
|
+
# Not in the pygame version - for Rubygame, we need to
|
6
|
+
# explicitly open the audio device.
|
7
|
+
# Args are:
|
8
|
+
# Frequency - Sampling frequency in samples per second (Hz).
|
9
|
+
# 22050 is recommended for most games; 44100 is
|
10
|
+
# CD audio rate. The larger the value, the more
|
11
|
+
# processing required.
|
12
|
+
# Format - Output sample format. This is one of the
|
13
|
+
# AUDIO_* constants in Rubygame::Mixer
|
14
|
+
# Channels -output sound channels. Use 2 for stereo,
|
15
|
+
# 1 for mono. (this option does not affect number
|
16
|
+
# of mixing channels)
|
17
|
+
# Samplesize - Bytes per output sample. Specifically, this
|
18
|
+
# determines the size of the buffer that the
|
19
|
+
# sounds will be mixed in.
|
20
|
+
# Rubygame::Mixer::open_audio( 22050, Rubygame::Mixer::AUDIO_U8, 2, 1024 )
|
21
|
+
Rubygame::Mixer::open_audio( 22050, nil, 2, 1024 )
|
22
|
+
|
23
|
+
puts 'Warning, sound disabled' unless
|
24
|
+
(@enabled = (Rubygame::VERSIONS[:sdl_mixer] != nil))
|
25
|
+
@enabled = (@enabled and (@config_manager.settings[:sound].nil? or @config_manager.settings[:sound] == true))
|
26
|
+
|
27
|
+
if @enabled
|
28
|
+
@music = {}
|
29
|
+
files = Dir.glob "#{MUSIC_PATH}**"
|
30
|
+
for f in files
|
31
|
+
name = File.basename(f)
|
32
|
+
begin
|
33
|
+
sym = name.gsub(" ","_").split(".")[0..-2].join(".").to_sym
|
34
|
+
@music[sym] = @resource_manager.load_music(f)
|
35
|
+
rescue;end
|
36
|
+
end if files
|
37
|
+
|
38
|
+
@sounds = {}
|
39
|
+
files = Dir.glob "#{SOUND_PATH}**"
|
40
|
+
for f in files
|
41
|
+
name = File.basename(f)
|
42
|
+
begin
|
43
|
+
sym = name.gsub(" ","_").split(".")[0..-2].join(".").to_sym
|
44
|
+
@sounds[sym] = @resource_manager.load_sound(f)
|
45
|
+
rescue;end
|
46
|
+
end if files
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def enabled?
|
51
|
+
@enabled
|
52
|
+
end
|
53
|
+
|
54
|
+
def play_sound(what, volume=nil)
|
55
|
+
if @enabled && @sounds[what]
|
56
|
+
@sound_thread = Thread.new do
|
57
|
+
@sounds[what].volume = volume if volume
|
58
|
+
@sounds[what].play
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def play_music(what, volume=nil)
|
64
|
+
if @enabled && @music[what]
|
65
|
+
@music_thread = Thread.new do
|
66
|
+
@music[what].volume = volume if volume
|
67
|
+
@music[what].play :repeats => -1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def stop_music(what)
|
73
|
+
if @enabled
|
74
|
+
@music[what].stop if @music[what]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def stop_sound(what)
|
79
|
+
if @enabled
|
80
|
+
@sounds[what].stop if @sounds[what]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'ftor'
|
2
|
+
module Rubygame
|
3
|
+
|
4
|
+
class Surface
|
5
|
+
def draw_line_s(point1, point2, color, thickness)
|
6
|
+
half_thickness = thickness/2.0
|
7
|
+
x1 = point1[0]
|
8
|
+
y1 = point1[1]
|
9
|
+
x2 = point2[0]
|
10
|
+
y2 = point2[1]
|
11
|
+
|
12
|
+
point1_vector = Ftor.new x1, y1
|
13
|
+
point2_vector = Ftor.new x2, y2
|
14
|
+
|
15
|
+
line_vector = point2_vector-point1_vector
|
16
|
+
perp_vector = line_vector.normal.unit
|
17
|
+
|
18
|
+
points = []
|
19
|
+
pvt = perp_vector*half_thickness
|
20
|
+
poly_point1 = Ftor.new(x1,y1)+pvt
|
21
|
+
poly_point2 = Ftor.new(x2,y2)+pvt
|
22
|
+
poly_point3 = Ftor.new(x2,y2)-pvt
|
23
|
+
poly_point4 = Ftor.new(x1,y1)-pvt
|
24
|
+
|
25
|
+
points << [poly_point1.x,poly_point1.y]
|
26
|
+
points << [poly_point2.x,poly_point2.y]
|
27
|
+
points << [poly_point3.x,poly_point3.y]
|
28
|
+
points << [poly_point4.x,poly_point4.y]
|
29
|
+
points << [poly_point1.x,poly_point1.y]
|
30
|
+
|
31
|
+
draw_polygon_s points, color
|
32
|
+
draw_circle_s [x1,y1], half_thickness, color
|
33
|
+
draw_circle_s [x2,y2], half_thickness, color
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end # module Rubygame
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'actor'
|
2
|
+
require 'actor_view'
|
3
|
+
|
4
|
+
require "enumerator"
|
5
|
+
|
6
|
+
|
7
|
+
# SvgActor knows how to build himself based on an svg document based on the :name
|
8
|
+
# passed in being the group name in the doc (layer).
|
9
|
+
class SvgActor < Actor
|
10
|
+
|
11
|
+
attr_accessor :segments, :type
|
12
|
+
def setup
|
13
|
+
@name = @opts[:name]
|
14
|
+
@svg_doc = @opts[:svg_doc]
|
15
|
+
|
16
|
+
my_layer = @svg_doc.find_group_by_label(@name.to_s)
|
17
|
+
build_from_vertices my_layer.path.vertices
|
18
|
+
@visible = my_layer.path.visible?
|
19
|
+
end
|
20
|
+
|
21
|
+
def build_from_vertices(vertices)
|
22
|
+
|
23
|
+
moment_of_inertia,mass = Float::Infinity,Float::Infinity
|
24
|
+
terrain_body = CP::Body.new(mass,moment_of_inertia)
|
25
|
+
elasticity = 0
|
26
|
+
friction = 0.7
|
27
|
+
thickness = 6
|
28
|
+
@segments = []
|
29
|
+
vertices.each_cons(2) do |a,b|
|
30
|
+
seg = CP::Shape::Segment.new(terrain_body, a,b, thickness)
|
31
|
+
seg.collision_type = @name
|
32
|
+
seg.e = elasticity
|
33
|
+
seg.u = friction
|
34
|
+
seg.group = :terrain
|
35
|
+
@segments << [a,b]
|
36
|
+
@level.space.add_static_shape(seg)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def visible?
|
41
|
+
@visible
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class SvgActorView < ActorView
|
47
|
+
def draw(target,x_off,y_off)
|
48
|
+
return unless @actor.visible?
|
49
|
+
@actor.segments.each do |seg|
|
50
|
+
p1 = seg[0]
|
51
|
+
p2 = seg[1]
|
52
|
+
target.draw_line_s [p1.x+x_off,p1.y+y_off], [p2.x+x_off,p2.y+y_off], [25,255,25,255], 6
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'strscan'
|
3
|
+
|
4
|
+
class SvgDocument
|
5
|
+
|
6
|
+
def initialize(xml_string)
|
7
|
+
@document = REXML::Document.new(xml_string)
|
8
|
+
@root = @document.root
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_group_by_label(label)
|
12
|
+
g = REXML::XPath.first(@root, "//g[@inkscape:label='#{label}']")
|
13
|
+
return nil unless g
|
14
|
+
Group.new(g)
|
15
|
+
end
|
16
|
+
|
17
|
+
module HasBounds
|
18
|
+
attr_accessor :bounds
|
19
|
+
|
20
|
+
def translate(vec)
|
21
|
+
@bounds.translate(vec) if @bounds
|
22
|
+
end
|
23
|
+
|
24
|
+
def center
|
25
|
+
@bounds.center if @bounds
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def set_bounds_from_attributes
|
31
|
+
x = @node.attributes["x"].to_f
|
32
|
+
y = @node.attributes["y"].to_f
|
33
|
+
width = @node.attributes["width"].to_f
|
34
|
+
height = @node.attributes["height"].to_f
|
35
|
+
@bounds = Rect.new [x,y,width,height]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module HasTranslation
|
40
|
+
def translation
|
41
|
+
transform = @node.attributes["transform"]
|
42
|
+
if transform and transform =~ /translate\(\s*(.+?)\s*,\s*(.+?\)\s*)/
|
43
|
+
vec2($1.to_f, ty = $2.to_f)
|
44
|
+
else
|
45
|
+
ZeroVec2
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Base
|
51
|
+
include HasTranslation
|
52
|
+
attr_reader :node
|
53
|
+
|
54
|
+
def initialize(node)
|
55
|
+
raise "Can't make #{self.class.name} from nil" if node.nil?
|
56
|
+
@node = node
|
57
|
+
end
|
58
|
+
|
59
|
+
def game_class
|
60
|
+
@node.attributes['game:class']
|
61
|
+
end
|
62
|
+
|
63
|
+
def game_handle
|
64
|
+
@node.attributes['game:handle']
|
65
|
+
end
|
66
|
+
|
67
|
+
def visible?
|
68
|
+
@node.attributes['visible'] != 'false'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Group < Base
|
73
|
+
def paths(opts={})
|
74
|
+
inst_from_xpath "path", Path, opts
|
75
|
+
end
|
76
|
+
|
77
|
+
def path(opts={})
|
78
|
+
paths(opts).first
|
79
|
+
end
|
80
|
+
|
81
|
+
def rects(opts={})
|
82
|
+
inst_from_xpath "rect", Rectangle, opts
|
83
|
+
end
|
84
|
+
|
85
|
+
def rect(opts={})
|
86
|
+
rects(opts).first
|
87
|
+
end
|
88
|
+
|
89
|
+
def images(opts={})
|
90
|
+
inst_from_xpath "image", Image, opts
|
91
|
+
end
|
92
|
+
|
93
|
+
def image(opts={})
|
94
|
+
images(opts).first
|
95
|
+
end
|
96
|
+
|
97
|
+
def groups(opts={})
|
98
|
+
inst_from_xpath "g", Group, opts
|
99
|
+
end
|
100
|
+
|
101
|
+
def group(opts={})
|
102
|
+
groups(opts).first
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def map_from_xpath(xpr, opts={})
|
108
|
+
opts.each do |key,val|
|
109
|
+
xpr << "[@#{key}='#{val}']"
|
110
|
+
end
|
111
|
+
REXML::XPath.match(@node, xpr).map do |n|
|
112
|
+
yield n
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def inst_from_xpath(xpr, clazz, opts={})
|
117
|
+
map_from_xpath(xpr,opts) do |n|
|
118
|
+
clazz.new(n)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class Path < Base
|
124
|
+
# The bezier path object must have all its nodes turned "sharp",
|
125
|
+
# or non-curve-handle-ish, or this parser will not work properly
|
126
|
+
def vertices
|
127
|
+
unless @verts
|
128
|
+
@verts = []
|
129
|
+
data = @node.attributes['d']
|
130
|
+
scanner = StringScanner.new(data)
|
131
|
+
pat = /[ML]\s+([-0-9.,]+)\s*/
|
132
|
+
hit = scanner.scan(pat)
|
133
|
+
while hit
|
134
|
+
x,y = scanner[1].split(/,/).map { |s| s.to_f }
|
135
|
+
@verts << vec2(x,y)
|
136
|
+
hit = scanner.scan(pat)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
@verts
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class Rectangle < Base
|
144
|
+
include HasBounds
|
145
|
+
|
146
|
+
def initialize(node)
|
147
|
+
super node
|
148
|
+
set_bounds_from_attributes
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class Image < Rectangle
|
153
|
+
attr_reader :image_name
|
154
|
+
|
155
|
+
def initialize(node)
|
156
|
+
super(node)
|
157
|
+
@image_name = @node.attributes["xlink:href"]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
== Welcome to Gamebox
|
2
|
+
Blurb here
|
3
|
+
|
4
|
+
== Description of Contents
|
5
|
+
|
6
|
+
src
|
7
|
+
Holds all the code that's specific to this particular application.
|
8
|
+
|
9
|
+
config
|
10
|
+
Configuration files for the Gamebox environment and other dependencies.
|
11
|
+
|
12
|
+
doc
|
13
|
+
This directory is where your application documentation will be stored when generated
|
14
|
+
using <tt>rake doc:app</tt>
|
15
|
+
|
16
|
+
lib
|
17
|
+
Application specific libraries. Basically, any kind of custom code that doesn't
|
18
|
+
belong under controllers, models, or helpers. This directory is in the load path.
|
19
|
+
|
20
|
+
script
|
21
|
+
Helper scripts for automation and generation.
|
22
|
+
|
23
|
+
test
|
24
|
+
Unit and functional tests along with fixtures. When using the script/generate scripts, template
|
25
|
+
test files will be generated for you and placed in this directory.
|
26
|
+
|
27
|
+
vendor
|
28
|
+
External libraries that the application depends on. Also includes the plugins subdirectory.
|
29
|
+
If the app has frozen rails, those gems also go here, under vendor/rails/.
|
30
|
+
This directory is in the load path.
|