gamebox 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/History.txt +18 -0
  2. data/Manifest.txt +85 -0
  3. data/README.txt +33 -0
  4. data/Rakefile +42 -0
  5. data/TODO.txt +29 -0
  6. data/bin/gamebox +49 -0
  7. data/docs/gamebox04_big.png +0 -0
  8. data/docs/getting_started.rdoc +99 -0
  9. data/docs/logo.png +0 -0
  10. data/lib/gamebox.rb +6 -0
  11. data/lib/gamebox/actor.rb +143 -0
  12. data/lib/gamebox/actor_factory.rb +64 -0
  13. data/lib/gamebox/actor_view.rb +35 -0
  14. data/lib/gamebox/ai/line_of_site.rb +61 -0
  15. data/lib/gamebox/ai/polaris.rb +107 -0
  16. data/lib/gamebox/ai/two_d_grid_location.rb +21 -0
  17. data/lib/gamebox/ai/two_d_grid_map.rb +77 -0
  18. data/lib/gamebox/aliasing.rb +16 -0
  19. data/lib/gamebox/animated.rb +84 -0
  20. data/lib/gamebox/behavior.rb +16 -0
  21. data/lib/gamebox/config_manager.rb +22 -0
  22. data/lib/gamebox/console_app.rb +39 -0
  23. data/lib/gamebox/data/fonts/Asimov.ttf +0 -0
  24. data/lib/gamebox/data/fonts/GAMEBOX_FONTS_GO_HERE +0 -0
  25. data/lib/gamebox/data/graphics/GAMEBOX_GRAPHICS_GO_HERE +0 -0
  26. data/lib/gamebox/data/graphics/logo.png +0 -0
  27. data/lib/gamebox/data/music/GAMEBOX_MUSIC_GOES_HERE +0 -0
  28. data/lib/gamebox/data/sounds/GAMEBOX_SOUND_FX_GO_HERE +0 -0
  29. data/lib/gamebox/director.rb +47 -0
  30. data/lib/gamebox/gamebox_application.rb +77 -0
  31. data/lib/gamebox/graphical.rb +24 -0
  32. data/lib/gamebox/graphical_actor_view.rb +31 -0
  33. data/lib/gamebox/inflections.rb +52 -0
  34. data/lib/gamebox/inflector.rb +278 -0
  35. data/lib/gamebox/input_manager.rb +104 -0
  36. data/lib/gamebox/layered.rb +34 -0
  37. data/lib/gamebox/level.rb +64 -0
  38. data/lib/gamebox/linked_list.rb +137 -0
  39. data/lib/gamebox/logo.rb +11 -0
  40. data/lib/gamebox/metaclass.rb +6 -0
  41. data/lib/gamebox/mode.rb +123 -0
  42. data/lib/gamebox/mode_manager.rb +80 -0
  43. data/lib/gamebox/numbers_ext.rb +3 -0
  44. data/lib/gamebox/physical.rb +139 -0
  45. data/lib/gamebox/physical_director.rb +17 -0
  46. data/lib/gamebox/physical_level.rb +89 -0
  47. data/lib/gamebox/physics.rb +27 -0
  48. data/lib/gamebox/publisher_ext.rb +13 -0
  49. data/lib/gamebox/resource_manager.rb +122 -0
  50. data/lib/gamebox/score.rb +35 -0
  51. data/lib/gamebox/sorted_list.rb +59 -0
  52. data/lib/gamebox/sound_manager.rb +84 -0
  53. data/lib/gamebox/surface_ext.rb +37 -0
  54. data/lib/gamebox/svg_actor.rb +55 -0
  55. data/lib/gamebox/svg_document.rb +160 -0
  56. data/lib/gamebox/template_app/README +30 -0
  57. data/lib/gamebox/template_app/Rakefile +20 -0
  58. data/lib/gamebox/template_app/config/boot.rb +5 -0
  59. data/lib/gamebox/template_app/config/environment.rb +29 -0
  60. data/lib/gamebox/template_app/config/game.yml +6 -0
  61. data/lib/gamebox/template_app/config/mode_level_config.yml +3 -0
  62. data/lib/gamebox/template_app/config/objects.yml +29 -0
  63. data/lib/gamebox/template_app/data/fonts/FONTS_GO_HERE +0 -0
  64. data/lib/gamebox/template_app/data/graphics/GRAPHICS_GO_HERE +0 -0
  65. data/lib/gamebox/template_app/data/music/MUSIC_GOES_HERE +0 -0
  66. data/lib/gamebox/template_app/data/sounds/SOUND_FX_GO_HERE +0 -0
  67. data/lib/gamebox/template_app/doc/README_FOR_APP +1 -0
  68. data/lib/gamebox/template_app/lib/code_statistics.rb +107 -0
  69. data/lib/gamebox/template_app/lib/diy.rb +371 -0
  70. data/lib/gamebox/template_app/lib/platform.rb +16 -0
  71. data/lib/gamebox/template_app/src/app.rb +8 -0
  72. data/lib/gamebox/template_app/src/demo_level.rb +20 -0
  73. data/lib/gamebox/template_app/src/game.rb +22 -0
  74. data/lib/gamebox/template_app/src/my_actor.rb +17 -0
  75. data/lib/gamebox/version.rb +10 -0
  76. data/lib/gamebox/viewport.rb +81 -0
  77. data/lib/gamebox/wrapped_screen.rb +15 -0
  78. data/script/perf_polaris.rb +36 -0
  79. data/test/helper.rb +25 -0
  80. data/test/test_actor.rb +38 -0
  81. data/test/test_animated.rb +64 -0
  82. data/test/test_line_of_site.rb +14 -0
  83. data/test/test_physical.rb +26 -0
  84. data/test/test_polaris.rb +193 -0
  85. data/test/test_viewport.rb +116 -0
  86. metadata +188 -0
@@ -0,0 +1,80 @@
1
+ require 'inflector'
2
+ require 'mode'
3
+ class ModeManager
4
+
5
+ constructor :resource_manager, :actor_factory, :input_manager,
6
+ :sound_manager, :config_manager
7
+
8
+ def setup
9
+ @modes = {}
10
+ @actor_factory.mode_manager = self
11
+ modes = @resource_manager.load_config('mode_level_config')[:modes]
12
+
13
+ @mode_names = []
14
+ for mode_hash in modes
15
+ for mode, levels in mode_hash
16
+ @mode_names << mode
17
+ mode_klass_name = "Mode"
18
+ unless mode == :default
19
+ mode_klass_name = Inflector.camelize mode.to_s+"Mode"
20
+ end
21
+ begin
22
+ require mode.to_s+"_mode"
23
+ rescue LoadError
24
+ # hope it's defined somewhere else
25
+ end
26
+ mode_klass = ObjectSpace.const_get mode_klass_name
27
+ mode_instance = mode_klass.new(@input_manager, @actor_factory, @resource_manager, @sound_manager, @config_manager, levels)
28
+ mode_instance.when :next_mode do
29
+ next_mode
30
+ end
31
+ mode_instance.when :prev_mode do
32
+ prev_mode
33
+ end
34
+ add_mode mode, mode_instance
35
+ end
36
+ end
37
+ end
38
+
39
+ def next_mode
40
+ index = @mode_names.index @mode
41
+ if index == @mode_names.size-1
42
+ puts "last mode, exiting"
43
+ exit
44
+ end
45
+ change_mode_to @mode_names[index+1]
46
+ end
47
+
48
+ def prev_mode
49
+ index = @mode_names.index @mode
50
+ if index == 0
51
+ puts "first mode, exiting"
52
+ exit
53
+ end
54
+ change_mode_to @mode_names[index-1]
55
+ end
56
+
57
+ def add_mode(mode_sym, mode_instance)
58
+ @modes[mode_sym] = mode_instance
59
+ @mode = mode_sym unless @mode
60
+ mode_instance
61
+ end
62
+
63
+ def change_mode_to(mode, *args)
64
+ @modes[@mode].stop unless @modes[@mode].nil?
65
+ @mode = mode
66
+ @modes[@mode].start *args
67
+ end
68
+
69
+ def current_mode
70
+ @modes[@mode]
71
+ end
72
+
73
+ def update(time)
74
+ @modes[@mode].update time unless @modes[@mode].nil?
75
+ end
76
+
77
+ def draw(target)
78
+ @modes[@mode].draw target unless @modes[@mode].nil?
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ class Float
2
+ Infinity = 1.0/0.0
3
+ end
@@ -0,0 +1,139 @@
1
+ require 'physics'
2
+ require 'behavior'
3
+ require 'inflector'
4
+ require 'publisher'
5
+ class Physical < Behavior
6
+ attr_accessor :shapes, :body, :opts, :parts
7
+
8
+ def shape
9
+ @shapes.first if @shapes
10
+ end
11
+
12
+ def setup
13
+ # TODO add defaults?
14
+ @mass = @opts[:mass]
15
+ @mass ||= Float::Infinity
16
+ @parts = {}
17
+ @shapes = []
18
+
19
+ moment_of_inertia = @opts[:moment]
20
+
21
+ case @opts[:shape]
22
+ when :circle
23
+ @radius = @opts[:radius]
24
+
25
+ moment_of_inertia ||= @opts[:fixed] ? Float::Infinity : moment_for_circle(@mass, @radius, 0, ZeroVec2)
26
+ @body = Body.new(@mass, moment_of_inertia)
27
+ @shape = Shape::Circle.new(@body, @radius, ZeroVec2)
28
+
29
+ when :poly
30
+ shape_array = @opts[:verts].collect{|v| vec2(v[0],v[1])}
31
+
32
+ moment_of_inertia ||= @opts[:fixed] ? Float::Infinity : moment_for_poly(@mass, shape_array, ZeroVec2)
33
+ @body = Body.new(@mass, moment_of_inertia)
34
+ @shape = Shape::Poly.new(@body, shape_array, ZeroVec2)
35
+ end
36
+
37
+ collision_type = @opts[:collision_group]
38
+ collision_type ||=
39
+ Inflector.underscore(@actor.class).to_sym
40
+
41
+ @body.a = @opts[:angle] if @opts[:angle]
42
+
43
+ @shape.collision_type = collision_type
44
+ start_x = @opts[:x]
45
+ start_y = @opts[:y]
46
+ start_x ||= @actor.x
47
+ start_y ||= @actor.y
48
+ @shape.body.p = vec2(start_x,start_y)
49
+ @shape.e = 0
50
+ friction = @opts[:friction]
51
+ friction ||= 0.4
52
+ @shape.u = friction
53
+
54
+ @shapes << @shape
55
+
56
+ if @opts[:parts]
57
+ for obj in @opts[:parts]
58
+ for part_name, part_def in obj
59
+ # add another shape here
60
+ part_shape_array = part_def[:verts].collect{|v| vec2(v[0],v[1])}
61
+ part_shape = Shape::Poly.new(@body, part_shape_array, part_def[:offset])
62
+ part_shape.collision_type = part_name.to_sym
63
+ # TODO pass all physics params to parts (ie u and e)
64
+ part_shape.u = friction
65
+ @shapes << part_shape
66
+ end
67
+ end
68
+ end
69
+
70
+
71
+ physical_obj = self
72
+
73
+ if @actor.level.respond_to? :register_physical_object
74
+ if @opts[:fixed]
75
+ @actor.level.register_physical_object physical_obj, true
76
+ else
77
+ @actor.level.register_physical_object physical_obj
78
+ end
79
+ else
80
+ raise "physical actor in a non-physical level!"
81
+ end
82
+
83
+ # write code here to keep physics and x,y of actor in sync
84
+ @actor.instance_eval do
85
+ (class << self; self; end).class_eval do
86
+ define_method :x do
87
+ physical_obj.body.p.x
88
+ end
89
+ define_method :y do
90
+ physical_obj.body.p.y
91
+ end
92
+ define_method :x= do |new_x|
93
+ raise "I am physical, you should apply forces"
94
+ end
95
+ define_method :y= do |new_y|
96
+ raise "I am physical, you should apply forces"
97
+ end
98
+ define_method :shape do
99
+ physical_obj.shape
100
+ end
101
+ define_method :body do
102
+ physical_obj.body
103
+ end
104
+ define_method :parts do
105
+ physical_obj.parts
106
+ end
107
+ define_method :deg do
108
+ # TODO hack!! why do poly's not work the same?
109
+ if physical_obj.opts[:shape] == :poly
110
+ -((physical_obj.body.a-1.57) * 180.0 / Math::PI + 90)
111
+ else
112
+ -((physical_obj.body.a) * 180.0 / Math::PI + 90)
113
+ end
114
+ end
115
+ define_method :warp do |new_p|
116
+ physical_obj.body.p = new_p
117
+ @level.space.rehash_static if physical_obj.opts[:fixed]
118
+ end
119
+ define_method :physical do
120
+ physical_obj
121
+ end
122
+ define_method :image do
123
+ old_image = nil
124
+ rot_deg = deg.round % 360
125
+
126
+ if is? :animated
127
+ old_image = animated.image
128
+ elsif is? :graphical
129
+ old_image = graphical.image
130
+ end
131
+
132
+ if old_image
133
+ old_image.rotozoom(rot_deg,1,true)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,17 @@
1
+ require 'director'
2
+
3
+ class PhysicalDirector < Director
4
+ def find_physical_obj(shape)
5
+ @actors.select{|a|a.respond_to?(:shape) && a.shape==shape}.first
6
+ end
7
+
8
+ def remove_physical_obj(shape)
9
+ act = find_physical_obj shape
10
+ act.remove_self
11
+ act
12
+ end
13
+
14
+ def actor_removed(act)
15
+ act.level.unregister_physical_object act if act.is? :physical
16
+ end
17
+ end
@@ -0,0 +1,89 @@
1
+ # Levels represent on level of game play. Some games will likely have only one
2
+ # level. Level is responsible for loading its background, props, and directors.
3
+ # PhysicalLevel adds a physics space to the Level
4
+ require 'level'
5
+ require 'physics'
6
+ require 'physical_director'
7
+ class PhysicalLevel < Level
8
+
9
+ attr_accessor :space
10
+
11
+ def initialize(actor_factory, resource_manager, sound_manager, viewport, opts={})
12
+ @actor_factory = actor_factory
13
+ @director = PhysicalDirector.new
14
+ @actor_factory.director = @director
15
+
16
+ @resource_manager = resource_manager
17
+ @sound_manager = sound_manager
18
+ @viewport = viewport
19
+ @opts = opts
20
+
21
+ @space = Space.new
22
+ @space.iterations = 20
23
+ @space.elastic_iterations = 0
24
+
25
+ setup
26
+ end
27
+
28
+ PHYSICS_STEP = 25.0
29
+ def update_physics(time)
30
+ unless @physics_paused
31
+ steps = (time/PHYSICS_STEP).ceil
32
+ # from chipmunk demo
33
+ dt = 1.0/60/steps
34
+ steps.times do
35
+ @space.step dt
36
+ end
37
+ end
38
+ end
39
+
40
+ def pause_physics
41
+ @physics_paused = true
42
+ end
43
+
44
+ def restart_physics
45
+ @physics_paused = false
46
+ end
47
+
48
+ def update(time)
49
+ update_physics time
50
+ super
51
+ end
52
+
53
+ def register_physical_object(obj,static=false)
54
+ if static
55
+ obj.shapes.each do |shape|
56
+ @space.add_static_shape shape
57
+ end
58
+ else
59
+ @space.add_body(obj.body)
60
+
61
+ obj.shapes.each do |shape|
62
+ @space.add_shape shape
63
+ end
64
+ end
65
+ end
66
+
67
+ def register_physical_constraint(constraint)
68
+ @space.add_constraint constraint
69
+ end
70
+
71
+ def unregister_physical_constraint(constraint)
72
+ @space.remove_constraint constraint
73
+ end
74
+
75
+ def unregister_physical_object(obj,static=false)
76
+ if static
77
+ obj.physical.shapes.each do |shape|
78
+ @space.remove_static_shape shape
79
+ end
80
+ else
81
+ @space.remove_body(obj.body)
82
+
83
+ obj.physical.shapes.each do |shape|
84
+ @space.remove_shape shape
85
+ end
86
+ end
87
+ end
88
+
89
+ end
@@ -0,0 +1,27 @@
1
+ require 'chipmunk'
2
+
3
+ require 'numbers_ext'
4
+ include CP
5
+ ZeroVec2 = vec2(0,0)
6
+
7
+ class Space
8
+ alias :add_collision_func_old :add_collision_func
9
+
10
+ # allows for passing arrays of collision types not just single ones
11
+ # add_collision_func([:foo,:bar], [:baz,:yar]) becomes:
12
+ # add_collision_func(:foo, :baz)
13
+ # add_collision_func(:foo, :yar)
14
+ # add_collision_func(:bar, :baz)
15
+ # add_collision_func(:bar, :yar)
16
+ def add_collision_func(first_objs, second_objs, &block)
17
+ firsts = [first_objs].flatten
18
+ seconds = [second_objs].flatten
19
+
20
+ firsts.each do |f|
21
+ seconds.each do |s|
22
+ add_collision_func_old(f,s,&block)
23
+ end
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,13 @@
1
+ module Publisher
2
+ module InstanceMethods
3
+ def unsubscribe_all(listener)
4
+ if @subscriptions
5
+ for event in @subscriptions.keys
6
+ @subscriptions[event].delete_if do |block|
7
+ eval('self',block.binding).equal?(listener)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+ $: << "#{File.dirname(__FILE__)}/../config"
3
+ require "fileutils"
4
+ require 'inflector'
5
+ require 'svg_document'
6
+
7
+ class ResourceManager
8
+ def initialize
9
+ @loaded_images = {}
10
+ @loaded_fonts = {}
11
+ @loaded_svgs = {}
12
+ end
13
+
14
+ def load_actor_image(actor)
15
+ # use pngs only for now
16
+ actor_name = Inflector.underscore(actor.class)
17
+ return load_image("#{actor_name}.png")
18
+ end
19
+
20
+ def load_animation_set(actor, action)
21
+ # use pngs only for now
22
+ actor_dir = Inflector.underscore(actor.class)
23
+ frames = Dir.glob("#{GFX_PATH}#{actor_dir}/#{action}/*.png")
24
+ action_imgs = []
25
+
26
+ frames = frames.sort_by {|f| File.basename(f).to_i }
27
+
28
+ for frame in frames
29
+ rel_path = frame.slice(GFX_PATH.size,frame.size)
30
+ action_imgs << load_image(rel_path)
31
+ end
32
+ action_imgs
33
+ end
34
+
35
+ def load_image(file_name)
36
+ cached_img = @loaded_images[file_name]
37
+ if cached_img.nil?
38
+ begin
39
+ cached_img = Rubygame::Surface.load(File.expand_path(GFX_PATH + file_name))
40
+ rescue Exception => ex
41
+ #check global gamebox location
42
+ cached_img = Rubygame::Surface.load(File.expand_path(GAMEBOX_GFX_PATH + file_name))
43
+ end
44
+ @loaded_images[file_name] = cached_img
45
+ end
46
+ cached_img
47
+ end
48
+
49
+ def load_music(full_name)
50
+ begin
51
+ sound = Rubygame::Music.load(full_name)
52
+ return sound
53
+ rescue Rubygame::SDLError => ex
54
+ puts "Cannot load music " + full_name + " : " + ex
55
+ end
56
+ end
57
+
58
+ def load_sound(full_name)
59
+ begin
60
+ sound = Rubygame::Sound.load(full_name)
61
+ return sound
62
+ rescue Rubygame::SDLError => ex
63
+ puts "Cannot load sound " + full_name + " : " + ex
64
+ end
65
+ end
66
+
67
+ # loads TTF fonts from the fonts dir and caches them for later
68
+ def load_font(name, size)
69
+ @loaded_fonts[name] ||= {}
70
+ return @loaded_fonts[name][size] if @loaded_fonts[name][size]
71
+ begin
72
+ unless @ttf_loaded
73
+ TTF.setup
74
+ @ttf_loaded = true
75
+ end
76
+ full_name = File.expand_path(FONTS_PATH + name)
77
+ begin
78
+ font = TTF.new(full_name, size)
79
+ @loaded_fonts[name][size] = font
80
+ rescue Exception => ex
81
+ full_name = File.expand_path(GAMEBOX_FONTS_PATH + name)
82
+ font = TTF.new(full_name, size)
83
+ @loaded_fonts[name][size] = font
84
+ end
85
+ return font
86
+ rescue Exception => ex
87
+ puts "Cannot load font #{full_name}:#{ex}"
88
+ end
89
+ return nil
90
+ end
91
+
92
+ # TODO make this path include that app name?
93
+ def load_config(name)
94
+ conf = YAML::load_file(CONFIG_PATH + name + ".yml")
95
+ user_file = "#{ENV['HOME']}/.gamebox/#{name}.yml"
96
+ if File.exist? user_file
97
+ user_conf = YAML::load_file user_file
98
+ conf = conf.merge user_conf
99
+ end
100
+ conf
101
+ end
102
+
103
+ def save_settings(name, settings)
104
+ user_gamebox_dir = "#{ENV['HOME']}/.gamebox"
105
+ FileUtils.mkdir_p user_gamebox_dir
106
+ user_file = "#{ENV['HOME']}/.gamebox/#{name}.yml"
107
+ File.open user_file, "w" do |f|
108
+ f.write settings.to_yaml
109
+ end
110
+ end
111
+
112
+ def load_svg(file_name)
113
+ # TODO create LEVEL_PATH in environment
114
+ cached_svg = @loaded_svgs[file_name]
115
+ if cached_svg.nil?
116
+ cached_svg = SvgDocument.new(File.open(File.expand_path(DATA_PATH + "levels/" + file_name + ".svg")))
117
+ @loaded_svgs[file_name] = cached_svg
118
+ end
119
+ cached_svg
120
+ end
121
+
122
+ end