metro 0.0.1 → 0.0.2

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.
@@ -0,0 +1,81 @@
1
+ require_relative 'artists_block'
2
+ require_relative 'label'
3
+ require_relative 'select'
4
+ require_relative 'image'
5
+
6
+ module Metro
7
+ module SceneView
8
+
9
+ #
10
+ # The CompositeDrawer is a special drawer that looks at all the created drawers
11
+ # that have been defined and then determines which one should be used when drawing
12
+ # for a particular view type.
13
+ #
14
+ # This Drawer is used in the SceneView to handle the multitude of view objects
15
+ # that are thrown at it.
16
+ #
17
+ # @see SceneView
18
+ #
19
+ class CompositeDrawer < Drawer
20
+
21
+ #
22
+ # Render all the view elements defined that are supported by this drawer.
23
+ #
24
+ def draw(view)
25
+ view.each do |name,content|
26
+ type = content['type']
27
+ drawers[type].draw(content.merge 'name' => name)
28
+ end
29
+ end
30
+
31
+ #
32
+ # Given all the registered drawers map the things that they can draw
33
+ # to the particular drawer.
34
+ #
35
+ # @return a Hash which maps the types of things that can be drawn to
36
+ # the specific drawer.
37
+ #
38
+ def drawers
39
+ @drawers ||= begin
40
+
41
+ # By default fall back to having artist's block when you do not know
42
+ # how to draw a particular view component.
43
+
44
+ hash = Hash.new(ArtistsBlock)
45
+
46
+ Drawer.drawers.each do |drawer|
47
+ drawer.draws_types.each do |type|
48
+
49
+ if not hash.key?(type) or (hash.key?(type) and override_on_conflict?(drawer,type))
50
+ hash[type] = drawer.new(scene)
51
+ end
52
+
53
+ end
54
+ end
55
+
56
+ hash
57
+ end
58
+ end
59
+
60
+ #
61
+ # @return true if the drawer should override the existing drawer, false if the drawer
62
+ # should leave the existing drawer in it's place.
63
+ #
64
+ def override_on_conflict?(drawer,type)
65
+ if drawer.draw_options[:override]
66
+ true
67
+ else
68
+ log.warn override_warning_message(drawer,type)
69
+ false
70
+ end
71
+ end
72
+
73
+ def override_warning_message(drawer,type)
74
+ [ "Drawer Attempting to Override Existing Drawer For '#{type}'",
75
+ "#{drawer} will NOT be drawing '#{type}' as it is being handled by another Drawer.",
76
+ "To override this in the #{drawer.class} class specify the parameter \"draws '#{type}', overrides: true\"" ].join("\n")
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,115 @@
1
+ module Metro
2
+ module SceneView
3
+
4
+ #
5
+ # A Drawer subclass does all the artistic work defined in the view granted by
6
+ # the {SceneView}. A Drawer at it's core defines a subclass which species
7
+ # the things that it can draw and then the draw method which it will draw
8
+ # those things.
9
+ #
10
+ # @example Creating a drawer to handle lines
11
+ #
12
+ # class Line < Metro::SceneView::Drawer
13
+ # draws :lines
14
+ #
15
+ # def draw(view)
16
+ # # Code would draw a line from:
17
+ # # view['x1'],view['y1'] to view['x2'],view['y2']
18
+ # # with a thickness of view['thickness']
19
+ # end
20
+ # end
21
+ #
22
+ class Drawer
23
+
24
+ #
25
+ # Allows a Drawer to specify what 'type' components it is able to draw. The
26
+ # 'type' is defined within the view objects.
27
+ #
28
+ # class LabelDrawer < Metro::SceneView::Drawer
29
+ # draws 'labels', 'shiny-labels', 'pulsing-labels'
30
+ # end
31
+ #
32
+ # @param [String,Array<String>] args a list of 'types' that this drawer is capable
33
+ # of drawing.
34
+ #
35
+ def self.draws(*args)
36
+ @draws_types = args.flatten.compact.reject {|arg| arg.is_a? Hash }
37
+ @draws_options = args.flatten.compact.find {|arg| arg.is_a? Hash }
38
+ end
39
+
40
+ #
41
+ # This method is called right after initialization. Allowing for additional
42
+ # configuration.
43
+ #
44
+ # @note This method should be implemented in the Drawer subclass.
45
+ #
46
+ def after_initialize ; end
47
+
48
+ #
49
+ # This method is called on the Drawer so that it renders content.
50
+ #
51
+ # @note This method should be implemented in the Drawer subclass.
52
+ #
53
+ # @param [Hash] view the hash content of the view.
54
+ #
55
+ def draw(view) ; end
56
+
57
+ #
58
+ # @return the instance of window that is often necessary to create Gosu
59
+ # components for rendering.
60
+ #
61
+ attr_reader :window
62
+
63
+ #
64
+ # @return the scene that is being drawn. This is required if the view content
65
+ # requires live information from the scene or if the drawing is effected
66
+ # by the state of the scene.
67
+ #
68
+ attr_reader :scene
69
+
70
+ #
71
+ # Captures all classes that subclass Drawer.
72
+ #
73
+ def self.inherited(base)
74
+ drawers << base
75
+ end
76
+
77
+ #
78
+ # All subclasses of Drawer, this should be all the defined scenes within the game.
79
+ #
80
+ # @return an Array of Drawer subclasses
81
+ #
82
+ def self.drawers
83
+ @drawers ||= []
84
+ end
85
+
86
+ #
87
+ # @return an array of all the types of components that this Drawer
88
+ # is able to handle drawing.
89
+ #
90
+ def self.draws_types
91
+ Array(@draws_types)
92
+ end
93
+
94
+ def self.draw_options
95
+ @draws_options || {}
96
+ end
97
+
98
+ #
99
+ # This initialize sets up the drawer. If a subclass Drawer needs to perform
100
+ # some customization, it is prefered to call {#after_initialize}.
101
+ #
102
+ # @see #after_initialize
103
+ #
104
+ # @param [Scene] scene the scene that this Drawer is going to be drawing. A
105
+ # window is retrieved from the scene.
106
+ #
107
+ def initialize(scene)
108
+ @scene = scene
109
+ @window = scene.window
110
+ after_initialize
111
+ end
112
+
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,30 @@
1
+ module Metro
2
+ module SceneView
3
+
4
+ class Image < Drawer
5
+ draws 'image'
6
+
7
+ attr_reader :images
8
+
9
+ def after_initialize
10
+ @images = {}
11
+
12
+ content_images = scene.view.find_all { |name,content| self.class.draws_types.include?(content['type']) }
13
+
14
+ content_images.each do |name,content|
15
+ @images[name] = create_image(content)
16
+ end
17
+ end
18
+
19
+ def create_image(content)
20
+ Gosu::Image.new(window,asset_path(content['path']))
21
+ end
22
+
23
+ def draw(view)
24
+ images[view['name']].draw(view['x'],view['y'],1)
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -1,6 +1,11 @@
1
1
  module Metro
2
2
  module SceneView
3
+
4
+ #
5
+ # Draws a string of text.
6
+ #
3
7
  class Label < Drawer
8
+ draws 'label'
4
9
 
5
10
  def font
6
11
  @font ||= Gosu::Font.new(window, Gosu::default_font_name, 20)
@@ -1,6 +1,16 @@
1
1
  module Metro
2
2
  module SceneView
3
+
4
+ #
5
+ # Draws a a menu of options. It is called a Select as it is named after the HTML
6
+ # element select. A select drawer also inserts itself into the scene as an event
7
+ # target as it needs to maintain the state of the menu. When an option is selected
8
+ # an event is fired based on the name of the option.
9
+ #
10
+ # @note Only one 'select' can be defined for a given scene.
11
+ #
3
12
  class Select < Drawer
13
+ draws 'select'
4
14
 
5
15
  attr_accessor :selected_index, :options
6
16
 
@@ -34,8 +44,6 @@ module Metro
34
44
  @selected_index = @selected_index + 1
35
45
  @selected_index = 0 if @selected_index >= options.length
36
46
  end
37
-
38
- def _no_action ; end
39
47
 
40
48
  def font
41
49
  @font ||= Gosu::Font.new(window, Gosu::default_font_name, 20)
@@ -3,15 +3,35 @@ require 'json'
3
3
  module Metro
4
4
  module SceneView
5
5
 
6
+ #
7
+ # Provides support for a JSON Representation of a view.
8
+ #
6
9
  class JSONView
7
- def self.find(view_name)
10
+
11
+ #
12
+ # Determine if a view exists for this specified format
13
+ #
14
+ # @param [String] view_name the name of the view to find
15
+ # @return a true if the json view exists and false if it does not exist.
16
+ #
17
+ def self.exists?(view_name)
8
18
  File.exists? json_view_name(view_name)
9
19
  end
10
20
 
21
+ #
22
+ # Parse the contents of the view given the name.
23
+ #
24
+ # @param [String] view_name the name of the view to read
25
+ # @return a Hash that contains the contents of the view.
26
+ #
11
27
  def self.parse(view_name)
12
28
  JSON.parse File.read json_view_name(view_name)
13
29
  end
14
30
 
31
+ #
32
+ # A helper method to generate the name of the json view file. In this case
33
+ # it is the view name with the suffix .json.
34
+ #
15
35
  def self.json_view_name(view_name)
16
36
  File.extname(view_name) == "" ? "#{view_name}.json" : view_name
17
37
  end
@@ -2,10 +2,21 @@ module Metro
2
2
  module SceneView
3
3
 
4
4
  class NoView
5
- def self.find(view_name)
5
+
6
+ #
7
+ # A NoView is a last resort view which means this is will always will exist.
8
+ #
9
+ # @param [String] view_name the name of the view to find
10
+ # @return a true if the json view exists and false if it does not exist.
11
+ #
12
+ def self.exists?(view_name)
6
13
  true
7
14
  end
8
15
 
16
+ #
17
+ # A NoView will return an empty Hash to provide compatibility with other view
18
+ # types.
19
+ #
9
20
  def self.parse(view_name)
10
21
  {}
11
22
  end
@@ -2,11 +2,29 @@ require_relative 'yaml_view'
2
2
  require_relative 'json_view'
3
3
  require_relative 'no_view'
4
4
 
5
+ require_relative 'drawers/drawer'
6
+ require_relative 'drawers/composite_drawer'
7
+
5
8
  module Metro
9
+
10
+ #
11
+ # SceneView provides support for a Scene to have a view as well as giving
12
+ # additional tools to also help draw that view.
13
+ #
6
14
  module SceneView
7
15
 
16
+ #
17
+ # When the module is included insure that all the class helper methods are added
18
+ # at the same time. As well as re-defining the {Scene#base_draw} method to allow
19
+ # for the use of the view_drawer.
20
+ #
8
21
  def self.included(base)
9
22
  base.extend ClassMethods
23
+
24
+ base.send :define_method, :base_draw do
25
+ view_drawer.draw(view)
26
+ draw
27
+ end
10
28
  end
11
29
 
12
30
  #
@@ -17,15 +35,25 @@ module Metro
17
35
  end
18
36
 
19
37
  #
20
- # Loads the view based on the view parsers.
38
+ # Loads and caches the view content based on the avilable view parsers and
39
+ # the view files defined.
40
+ #
41
+ # @return a Hash of view content.
21
42
  #
22
43
  def view
23
44
  @view ||= begin
24
- parser = _view_parsers.find { |parser| parser.find self.class.view_name }
45
+ parser = _view_parsers.find { |parser| parser.exists? self.class.view_name }
25
46
  parser.parse self.class.view_name
26
47
  end
27
48
  end
28
49
 
50
+ #
51
+ # @return an instance of a SceneView::Drawer that is capable of drawing
52
+ # the Scene.
53
+ def view_drawer
54
+ @view_drawer ||= SceneView::CompositeDrawer.new(self)
55
+ end
56
+
29
57
  module ClassMethods
30
58
 
31
59
  #
@@ -35,14 +63,16 @@ module Metro
35
63
  # @example Custom View Name
36
64
  #
37
65
  # class ClosingScene < Metro::Scene
38
- # view_name :alternate
66
+ # view_name 'alternative'
39
67
  # end
68
+ #
69
+ # ClosingScene.view_name # => views/alternative
40
70
  #
41
71
  def view_name(filename = nil)
42
72
  if filename
43
73
  @view_name = File.join "views", filename.to_s
44
74
  else
45
- @view_name ||= File.join "views", "#{self.to_s[/^(.+)Scene$/,1].downcase}"
75
+ @view_name ||= File.join "views", scene_name
46
76
  end
47
77
  end
48
78
 
@@ -4,14 +4,31 @@ module Metro
4
4
  module SceneView
5
5
 
6
6
  class YAMLView
7
- def self.find(view_name)
7
+
8
+ #
9
+ # Determine if a view exists for this specified format
10
+ #
11
+ # @param [String] view_name the name of the view to find
12
+ # @return a true if the yaml view exists and false if it does not exist.
13
+ #
14
+ def self.exists?(view_name)
8
15
  File.exists? yaml_view_name(view_name)
9
16
  end
10
17
 
18
+ #
19
+ # Parse the contents of the view given the name.
20
+ #
21
+ # @param [String] view_name the name of the view to read
22
+ # @return a Hash that contains the contents of the view.
23
+ #
11
24
  def self.parse(view_name)
12
25
  YAML.load File.read yaml_view_name(view_name)
13
26
  end
14
27
 
28
+ #
29
+ # A helper method to generate the name of the yaml view file. In this case
30
+ # it is the view name with the suffix .yaml.
31
+ #
15
32
  def self.yaml_view_name(view_name)
16
33
  File.extname(view_name) == "" ? "#{view_name}.yaml" : view_name
17
34
  end
data/lib/metro/scenes.rb CHANGED
@@ -1,23 +1,65 @@
1
1
  module Metro
2
+
3
+ #
4
+ # @example Finding a scene based on the scene name
5
+ #
6
+ # class IntroScene < Metro::Scene
7
+ # # ... scene content ...
8
+ # end
9
+ #
10
+ # Scenes.find("intro") # => IntroScene
11
+ # Scenes.find(:intro) # => IntroScene
12
+ # Scenes.find(IntroScene) # => IntroScene
13
+ #
14
+ # @example Creating a scene instance based on the scene name
15
+ #
16
+ # class IntroScene < Metro::Scene
17
+ # # ... scene content ...
18
+ # end
19
+ #
20
+ # Scenes.generate("intro") # => [SCENE: title]
21
+ # Scenes.generate(:intro) # => [SCENE: title]
22
+ # Scenes.generate(IntroScene) # => [SCENE: title]
23
+ #
2
24
  module Scenes
3
25
  extend self
4
26
 
5
- def scenes
6
- @scenes ||= Scene.scenes.inject({}) do |dict,scene|
7
- name = scene.to_s.gsub(/Scene$/,'').downcase.to_sym
27
+ #
28
+ # Finds the scene based on the specified scene name.
29
+ #
30
+ # @param [String,Symbol] scene_name the name of the scene to locate.
31
+ # @return the Scene class that is found matching the specified scene name.
32
+ #
33
+ def find(scene_name)
34
+ scenes_hash[scene_name]
35
+ end
36
+
37
+ #
38
+ # Finds the scene with the specified name and then creates an instance of that
39
+ # scene.
40
+ #
41
+ # @param [String,Symbol] scene_name the name of the scene to locate.
42
+ # @return an instance of Scene that is found matching the specified scene name
43
+ #
44
+ def generate(scene_name)
45
+ find(scene_name).new
46
+ end
47
+
48
+ private
49
+
50
+ #
51
+ # @return a Hash that allows for accessing symbol names of the scenes
52
+ # as well as the class name constants to allow for the scenes to be found.
53
+ #
54
+ def scenes_hash
55
+ @scenes_hash ||= Scene.scenes.inject({}) do |dict,scene|
56
+ name = scene.scene_name
8
57
  dict[name] = scene
58
+ dict[name.to_sym] = scene
9
59
  dict[scene] = scene
10
60
  dict
11
61
  end
12
62
  end
13
63
 
14
- def find(scene_name)
15
- scenes[scene_name.to_sym]
16
- end
17
-
18
- def create(scene_name,window)
19
- find(scene_name).new(window)
20
- end
21
-
22
64
  end
23
65
  end
data/lib/metro/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Metro
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/metro/window.rb CHANGED
@@ -4,33 +4,60 @@ module Metro
4
4
 
5
5
  #
6
6
  # A subclass of the Gosu::Window which simply acts as system
7
- # to shuffle in and out scenes and transfer events.
7
+ # to shuffle in and out scenes and relay event information.
8
8
  #
9
9
  class Window < Gosu::Window
10
10
 
11
- attr_reader :scene
11
+ #
12
+ # The scene of the window.
13
+ #
14
+ # @see Scene
15
+ #
16
+ attr_accessor :scene
12
17
 
13
- def initialize(width,height,something)
14
- super width, height, something
18
+ #
19
+ # @param [Fixnum] width the width of the game window
20
+ # @param [Fixnum] height the height of the game window
21
+ # @param [TrueClass,FalseClass] fullscreen the boolean flag to enable or
22
+ # disable fullscreen
23
+ #
24
+ def initialize(width,height,fullscreen)
25
+ super width, height, fullscreen
15
26
  end
16
27
 
17
- def scene=(new_scene)
18
- @scene = new_scene
28
+ def scene=(scene)
29
+ scene.window = self
30
+ @scene = scene
19
31
  end
20
32
 
33
+ #
34
+ # This is called every update interval while the window is being shown.
35
+ #
21
36
  def update
22
- scene.trigger_held_buttons
37
+ scene.fire_events_for_held_buttons
23
38
  scene.update
24
39
  end
25
40
 
41
+ #
42
+ # This is called after every {#update} and when the OS wants the window to
43
+ # repaint itself.
44
+ #
26
45
  def draw
27
- scene._draw
46
+ scene.base_draw
28
47
  end
29
48
 
49
+ #
50
+ # Called before {#update} when the user releases a button while the window
51
+ # has focus.
52
+ #
30
53
  def button_up(id)
31
54
  scene.button_up(id)
32
55
  end
33
56
 
57
+ #
58
+ # Called before {#update} when the user presses a button while the window
59
+ # has focus.
60
+ #
34
61
  def button_down(id)
35
62
  scene.button_down(id)
36
63
  end
data/lib/metro.rb CHANGED
@@ -23,16 +23,34 @@ end
23
23
  module Metro
24
24
  extend self
25
25
 
26
- def run(filename="metro")
26
+ #
27
+ # @return [String] the default filename that contains the game contents
28
+ #
29
+ def default_game_filename
30
+ 'metro'
31
+ end
32
+
33
+ #
34
+ # Run will load the contents of the game contents and game files
35
+ # within the current working directory and start the game. By default
36
+ # calling run with no parameter will look for a game file
37
+ #
38
+ # @param [String] filename the name of the game file to run. When not specified
39
+ # the value uses the default filename.
40
+ #
41
+ def run(filename=default_game_filename)
27
42
  load_game_files
28
43
  load_game_configuration(filename)
29
44
  start_game
30
45
  end
31
46
 
47
+ private
48
+
32
49
  def load_game_files
33
50
  $LOAD_PATH.unshift(Dir.pwd) unless $LOAD_PATH.include?(Dir.pwd)
34
51
  Dir['models/*.rb'].each {|model| require model }
35
52
  Dir['scenes/*.rb'].each {|scene| require scene }
53
+ Dir['drawers/*.rb'].each {|drawer| require drawer }
36
54
  end
37
55
 
38
56
  def load_game_configuration(filename)
@@ -43,8 +61,8 @@ module Metro
43
61
  end
44
62
 
45
63
  def start_game
46
- window = Window.new Game.width, Game.height, false
47
- window.scene = Game.first_scene.new(window)
64
+ window = Window.new Game.width, Game.height, Game.fullscreen?
65
+ window.scene = Scenes.generate(Game.first_scene)
48
66
  window.show
49
67
  end
50
68
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-18 00:00:00.000000000 Z
12
+ date: 2012-10-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gosu
@@ -47,10 +47,12 @@ files:
47
47
  - lib/metro/game/dsl.rb
48
48
  - lib/metro/model.rb
49
49
  - lib/metro/scene.rb
50
- - lib/metro/scene_view/components/drawer.rb
51
- - lib/metro/scene_view/components/label.rb
52
- - lib/metro/scene_view/components/select.rb
53
- - lib/metro/scene_view/components/unsupported_component.rb
50
+ - lib/metro/scene_view/drawers/artists_block.rb
51
+ - lib/metro/scene_view/drawers/composite_drawer.rb
52
+ - lib/metro/scene_view/drawers/drawer.rb
53
+ - lib/metro/scene_view/drawers/image.rb
54
+ - lib/metro/scene_view/drawers/label.rb
55
+ - lib/metro/scene_view/drawers/select.rb
54
56
  - lib/metro/scene_view/json_view.rb
55
57
  - lib/metro/scene_view/no_view.rb
56
58
  - lib/metro/scene_view/scene_view.rb