metro 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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