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.
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,64 @@
1
+ require 'actor'
2
+ require 'graphical_actor_view'
3
+ class ActorFactory
4
+ constructor :input_manager, :sound_manager
5
+
6
+ attr_accessor :mode_manager, :director
7
+
8
+ # returns a hash of actor params
9
+ def cached_actor_def(actor)
10
+ @actor_cache ||= {}
11
+ cached_actor = @actor_cache[actor]
12
+ return cached_actor if cached_actor
13
+
14
+ begin
15
+ require actor.to_s
16
+ require actor.to_s+"_view"
17
+ rescue LoadError => ex
18
+ # maybe its included somewhere else
19
+ end
20
+ model_klass_name = Inflector.camelize actor
21
+ model_klass = Object.const_get model_klass_name
22
+
23
+ begin
24
+ view_klass = Object.const_get model_klass_name+"View"
25
+ rescue Exception => ex
26
+ # hrm...
27
+ end
28
+
29
+ actor_def = {
30
+ :model_klass => model_klass,
31
+ :view_klass => view_klass
32
+ }
33
+ @actor_cache[actor] = actor_def
34
+ actor_def
35
+ end
36
+
37
+
38
+ def build(actor, level, opts={})
39
+ actor_def = cached_actor_def actor
40
+
41
+ basic_opts = {
42
+ :level => level,
43
+ :input => @input_manager,
44
+ :sound => @sound_manager,
45
+ :resources => level.resource_manager
46
+ }
47
+ merged_opts = basic_opts.merge(opts)
48
+
49
+ model = actor_def[:model_klass].new merged_opts
50
+
51
+ view_klass = opts[:view]
52
+ view_klass ||= actor_def[:view_klass]
53
+
54
+ if model.is? :animated or model.is? :graphical or model.is? :physical
55
+ view_klass ||= GraphicalActorView
56
+ end
57
+ view_klass.new @mode_manager.current_mode, model if view_klass
58
+
59
+ # Register our new actor with the system
60
+ @director.add_actor model
61
+
62
+ return model
63
+ end
64
+ end
@@ -0,0 +1,35 @@
1
+ class ActorView
2
+ attr_accessor :actor, :mode, :layer, :parallax
3
+ def initialize(mode,actor)
4
+ @mode = mode
5
+ @actor = actor
6
+
7
+ @layer = 0
8
+ @parallax = 1
9
+ if @actor.is? :layered
10
+ @layer = @actor.layer
11
+ @parallax = @actor.parallax
12
+ end
13
+
14
+ actor.when :remove_me do
15
+ @mode.unregister_drawable self
16
+ end
17
+
18
+ actor.when :hide_me do
19
+ @mode.unregister_drawable self
20
+ end
21
+
22
+ actor.when :show_me do
23
+ @mode.register_drawable self
24
+ end
25
+
26
+ actor.show
27
+
28
+ setup
29
+ end
30
+
31
+ def setup
32
+ end
33
+
34
+ end
35
+
@@ -0,0 +1,61 @@
1
+ # LineOfSite is a class for finding neighbors in a map that are visible
2
+ class LineOfSite
3
+ def initialize(map)
4
+ @map = map
5
+ end
6
+
7
+ def losline(x, y, x2, y2)
8
+ brensenham_line(x, y, x2, y2).each do |i|
9
+ iterx, itery = *i
10
+ occ = @map.occupant(loc2(iterx,itery))
11
+ return unless occ
12
+ occ.lit = true
13
+ occ.seen = true
14
+
15
+ return if occ.solid?
16
+ end
17
+ end
18
+
19
+ # Brensenham line algorithm
20
+ def brensenham_line(x,y,x2,y2)
21
+ steep = false
22
+ coords = []
23
+ dx = (x2 - x).abs
24
+ if (x2 - x) > 0
25
+ sx = 1
26
+ else
27
+ sx = -1
28
+ end
29
+ dy = (y2 - y).abs
30
+ if (y2 - y) > 0
31
+ sy = 1
32
+ else
33
+ sy = -1
34
+ end
35
+ if dy > dx
36
+ steep = true
37
+ x,y = y,x
38
+ dx,dy = dy,dx
39
+ sx,sy = sy,sx
40
+ end
41
+ d = (2 * dy) - dx
42
+
43
+ dx.times do
44
+ if steep
45
+ coords << [y,x]
46
+ else
47
+ coords << [x,y]
48
+ end
49
+ while d >= 0
50
+ y = y + sy
51
+ d = d - (2 * dx)
52
+ end
53
+ x = x + sx
54
+ d = d + (2 * dy)
55
+ end
56
+ coords << [x2,y2]
57
+
58
+ coords
59
+ end
60
+
61
+ end
@@ -0,0 +1,107 @@
1
+ require 'algorithms'
2
+ include Containers
3
+
4
+ # Polaris is a star that guides, aka "The North Star". It implements the A* algorithm.
5
+ class Polaris
6
+ attr_reader :nodes_considered
7
+
8
+ def initialize(map)
9
+ @map = map
10
+ @nodes_considered = 0
11
+ end
12
+
13
+ def guide(from, to, unit_type=nil, max_depth=400)
14
+ return nil if @map.blocked?(from, unit_type) || @map.blocked?(to, unit_type)
15
+ from_element = PathElement.new(from)
16
+ from_element.dist_from = @map.distance(from,to)
17
+ open = PriorityQueue.new { |x, y| (x <=> y) == -1 }
18
+ open.push from_element, from_element.rating
19
+ closed = SplayTreeMap.new
20
+ step = 0
21
+
22
+ until open.empty? || step > max_depth
23
+ step += 1
24
+
25
+ current_element = open.pop
26
+ @nodes_considered += 1
27
+
28
+ loc = current_element.location
29
+ if @map.cost(loc,to) == 0
30
+ path = []
31
+ until current_element.parent.nil?
32
+ path.unshift current_element
33
+ current_element = current_element.parent
34
+ end
35
+
36
+ return path
37
+ else
38
+ closed.push current_element.location, current_element
39
+ @map.neighbors(loc).each do |next_door|
40
+ el = PathElement.new(next_door,current_element)
41
+ next if closed.has_key? next_door
42
+
43
+ if @map.blocked? next_door, unit_type
44
+ #closed.push el.location, el
45
+ else
46
+ current_rating = current_element.cost_to + @map.cost(loc, next_door)
47
+
48
+ # add to open
49
+ el.cost_to = current_rating
50
+ el.dist_from = @map.distance(next_door,to)
51
+
52
+ open.push el, el.rating
53
+ end
54
+ end
55
+ end
56
+ end
57
+ nil
58
+ end
59
+ end
60
+
61
+ class PathElement
62
+ include Comparable
63
+
64
+ attr_accessor :location, :parent
65
+ attr_reader :cost_to, :dist_from, :rating
66
+ def initialize(location=nil,parent=nil)
67
+ @location = location
68
+ @parent = parent
69
+ @cost_to = 0
70
+ @dist_from = 0
71
+ @rating = 99_999
72
+ end
73
+
74
+ def cost_to=(new_cost)
75
+ @cost_to = new_cost
76
+ reset_rating
77
+ end
78
+
79
+ def dist_from=(new_dist_from)
80
+ @dist_from = new_dist_from
81
+ reset_rating
82
+ end
83
+
84
+ def reset_rating
85
+ @rating = @cost_to + @dist_from
86
+ end
87
+
88
+ def to_s
89
+ "#{@location} at cost of #{@cost_to} and rating of #{@rating}"
90
+ end
91
+
92
+ def <=>(b)
93
+ a = self
94
+ if a.rating < b.rating
95
+ return -1
96
+ elsif a.rating > b.rating
97
+ return 1
98
+ else
99
+ 0
100
+ end
101
+ end
102
+
103
+ def ==(other)
104
+ return false if other.nil?
105
+ @location == other.location
106
+ end
107
+ end
@@ -0,0 +1,21 @@
1
+ # TwoDGridLocation exibits an x,y,cost location
2
+ class TwoDGridLocation
3
+ attr_accessor :x,:y
4
+ def initialize(x,y);@x=x;@y=y;end
5
+ def ==(other)
6
+ @x == other.x and @y == other.y
7
+ end
8
+
9
+ def <=>(b)
10
+ ret = 1
11
+ if @x == b.x && @y == b.y
12
+ ret = 0
13
+ end
14
+ ret = -1 if @x <= b.x && @y < b.y
15
+ return ret
16
+ end
17
+
18
+ def to_s
19
+ "#{@x},#{@y}"
20
+ end
21
+ end
@@ -0,0 +1,77 @@
1
+ require 'ai/two_d_grid_location'
2
+
3
+ # TwoDGridMap exibits the contract that the map requires.
4
+ # Works on an X,Y grid that uses Ftors for 2D vectors
5
+ class TwoDGridMap
6
+ attr_accessor :w, :h
7
+ TRAVEL_COST_DIAG = 14
8
+ TRAVEL_COST_STRAIGHT = 10
9
+
10
+ def initialize(w,h)
11
+ @w = w
12
+ @h = h
13
+ @grid = {}
14
+ end
15
+
16
+ # place thing at location. If thing is nil, location will be placed in the map
17
+ def place(location, thing=nil)
18
+ thing ||= location
19
+ @grid[location.x] ||= {}
20
+ @grid[location.x][location.y] = thing
21
+ end
22
+
23
+ def occupant(location)
24
+ @grid[location.x][location.y] if @grid[location.x]
25
+ end
26
+
27
+ def clear(location)
28
+ @grid[location.x] ||= {}
29
+ @grid[location.x][location.y] = nil
30
+ end
31
+
32
+ # is the location available for the specified type
33
+ def blocked?(location, type=nil)
34
+ return true if type == :blocked
35
+ return true if location.x >= @w || location.y >= @h || location.x < 0 || location.y < 0
36
+ if @grid[location.x] and @grid[location.x][location.y]
37
+ return true
38
+ else
39
+ return false
40
+ end
41
+ end
42
+
43
+ # returns a list of neighbors and their distance
44
+ def neighbors(location)
45
+ x = location.x
46
+ y = location.y
47
+ [
48
+ TwoDGridLocation.new(x-1, y-1),
49
+ TwoDGridLocation.new(x-1, y+1),
50
+ TwoDGridLocation.new(x+1, y-1),
51
+ TwoDGridLocation.new(x+1, y+1),
52
+ TwoDGridLocation.new(x-1, y),
53
+ TwoDGridLocation.new(x+1, y),
54
+ TwoDGridLocation.new(x, y-1),
55
+ TwoDGridLocation.new(x, y+1)
56
+ ]
57
+ end
58
+
59
+ def distance(from,to)
60
+ h_diagonal = [(from.x-to.x).abs, (from.y-to.y).abs].min
61
+ h_straight = ((from.x-to.x).abs + (from.y-to.y).abs)
62
+ return TRAVEL_COST_DIAG * h_diagonal + TRAVEL_COST_STRAIGHT * (h_straight - 2*h_diagonal)
63
+ end
64
+
65
+ # return the cost to go from => to (assuming from and to are neighbors)
66
+ def cost(from, to)
67
+ if from.x == to.x or from.y == to.y
68
+ if from.x == to.x and from.y == to.y
69
+ 0
70
+ else
71
+ TRAVEL_COST_STRAIGHT
72
+ end
73
+ else
74
+ TRAVEL_COST_DIAG
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,16 @@
1
+ class Module
2
+ # Encapsulates the common pattern of:
3
+ #
4
+ # alias_method :foo_without_feature, :foo
5
+ # alias_method :foo, :foo_with_feature
6
+ #
7
+ # With this, you simply do:
8
+ #
9
+ # alias_method_chain :foo, :feature
10
+ #
11
+ # And both aliases are set up for you.
12
+ def alias_method_chain(target, feature)
13
+ alias_method "#{target}_without_#{feature}", target
14
+ alias_method target, "#{target}_with_#{feature}"
15
+ end
16
+ end
@@ -0,0 +1,84 @@
1
+ require 'behavior'
2
+ # keeps track of an image for you based on the actor's class, and
3
+ # current action, and frame num
4
+ # by default it expects images to be:
5
+ # data/graphics/classname/action/01..n.png
6
+ class Animated < Behavior
7
+ FRAME_UPDATE_TIME = 60
8
+
9
+ attr_accessor :frame_time, :frame_num, :animating
10
+ def setup
11
+ @images = {}
12
+ @frame_time = 0
13
+
14
+ # all animated actors have to have an idle animation
15
+ # data/graphics/ship/idle/1.png
16
+ @frame_num = 0
17
+ self.action = :idle
18
+
19
+ animated_obj = self
20
+
21
+ @actor.instance_eval do
22
+ (class << self; self; end).class_eval do
23
+ define_method :image do
24
+ animated_obj.image
25
+ end
26
+ define_method :start_animating do
27
+ animated_obj.start_animating
28
+ end
29
+ define_method :stop_animating do
30
+ animated_obj.stop_animating
31
+ end
32
+ define_method :action= do |action_sym|
33
+ animated_obj.action = action_sym
34
+ end
35
+ define_method :animated do
36
+ animated_obj
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ def update(time)
44
+ return unless @animating
45
+ @frame_time += time
46
+ if @frame_time > FRAME_UPDATE_TIME
47
+ next_frame
48
+ @frame_time = @frame_time-FRAME_UPDATE_TIME
49
+ end
50
+ end
51
+
52
+ def next_frame()
53
+ @frame_num = (@frame_num + 1) % @images[@action].size
54
+ end
55
+
56
+ # load all the images for this action
57
+ def load_action(action)
58
+ @actor.resource_manager.load_animation_set @actor, action
59
+ end
60
+
61
+ def action=(new_action)
62
+ @images[new_action] ||= load_action(new_action)
63
+ if @images[new_action].size > 1
64
+ start_animating
65
+ else
66
+ stop_animating
67
+ end
68
+ @frame_num = 0
69
+ @action = new_action
70
+ end
71
+
72
+ # returns the current image, or nil if no action is defined
73
+ def image
74
+ @images[@action][@frame_num]
75
+ end
76
+
77
+ def start_animating
78
+ @animating = true
79
+ end
80
+
81
+ def stop_animating
82
+ @animating = false
83
+ end
84
+ end