metro 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/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/bin/metro +11 -0
- data/lib/metro.rb +51 -0
- data/lib/metro/event_relay.rb +56 -0
- data/lib/metro/game.rb +37 -0
- data/lib/metro/game/dsl.rb +29 -0
- data/lib/metro/model.rb +12 -0
- data/lib/metro/scene.rb +192 -0
- data/lib/metro/scene_view/components/drawer.rb +44 -0
- data/lib/metro/scene_view/components/label.rb +23 -0
- data/lib/metro/scene_view/components/select.rb +62 -0
- data/lib/metro/scene_view/components/unsupported_component.rb +9 -0
- data/lib/metro/scene_view/json_view.rb +21 -0
- data/lib/metro/scene_view/no_view.rb +15 -0
- data/lib/metro/scene_view/scene_view.rb +52 -0
- data/lib/metro/scene_view/yaml_view.rb +21 -0
- data/lib/metro/scenes.rb +23 -0
- data/lib/metro/version.rb +3 -0
- data/lib/metro/window.rb +39 -0
- data/metro.gemspec +21 -0
- metadata +86 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Franklin Webber
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# metro
|
2
|
+
|
3
|
+
Metro is a framework built around [gosu](https://github.com/jlnr/gosu) the 2D game development library in Ruby. The goal of Metro is to enforce common conceptual structures and conventions making it easier to quickly generate a game.
|
4
|
+
|
5
|
+
> NOTE: This project is very early in development and at this point mostly a prototype to explore more of theses concepts to gain an understanding of core tools necessary to make games.
|
6
|
+
|
7
|
+
Please take a look at the [example game project](https://github.com/burtlo/starry-knight) that I am building alongside of 'metro' to see how it can be used to develop games.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'metro'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install metro
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
```
|
26
|
+
bundle exec metro [gamefilename]
|
27
|
+
```
|
28
|
+
|
29
|
+
By default Metro will look for a file named 'metro' within the current working directory if no *gamefilename* has been provided.
|
30
|
+
|
31
|
+
Please take a look at the [example game project](https://github.com/burtlo/starry-knight) that I am building alongside of 'metro' to see how it can be used to develop games.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/metro
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
path = __FILE__
|
4
|
+
while File.symlink?(path)
|
5
|
+
path = File.expand_path(File.readlink(__FILE__), File.dirname(__FILE__))
|
6
|
+
end
|
7
|
+
$:.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib'))
|
8
|
+
|
9
|
+
require 'metro'
|
10
|
+
|
11
|
+
Metro.run(*ARGV)
|
data/lib/metro.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'gosu'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
require 'metro/version'
|
5
|
+
require 'metro/window'
|
6
|
+
require 'metro/game'
|
7
|
+
require 'metro/model'
|
8
|
+
require 'metro/scene'
|
9
|
+
|
10
|
+
def asset_path(name)
|
11
|
+
File.join Dir.pwd, "assets", name
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def log
|
16
|
+
@log ||= begin
|
17
|
+
logger = Logger.new(STDOUT)
|
18
|
+
logger.level = Logger::DEBUG
|
19
|
+
logger
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Metro
|
24
|
+
extend self
|
25
|
+
|
26
|
+
def run(filename="metro")
|
27
|
+
load_game_files
|
28
|
+
load_game_configuration(filename)
|
29
|
+
start_game
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_game_files
|
33
|
+
$LOAD_PATH.unshift(Dir.pwd) unless $LOAD_PATH.include?(Dir.pwd)
|
34
|
+
Dir['models/*.rb'].each {|model| require model }
|
35
|
+
Dir['scenes/*.rb'].each {|scene| require scene }
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_game_configuration(filename)
|
39
|
+
game_contents = File.read(filename)
|
40
|
+
game_block = lambda {|instance| eval(game_contents) }
|
41
|
+
game = Game::DSL.parse(&game_block)
|
42
|
+
Game.setup game
|
43
|
+
end
|
44
|
+
|
45
|
+
def start_game
|
46
|
+
window = Window.new Game.width, Game.height, false
|
47
|
+
window.scene = Game.first_scene.new(window)
|
48
|
+
window.show
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Metro
|
2
|
+
class EventRelay
|
3
|
+
|
4
|
+
attr_reader :target, :window
|
5
|
+
|
6
|
+
attr_reader :up_actions, :down_actions, :held_actions
|
7
|
+
|
8
|
+
def initialize(target,window)
|
9
|
+
@target = target
|
10
|
+
@window = window
|
11
|
+
@up_actions ||= Hash.new(:_no_action)
|
12
|
+
@down_actions ||= Hash.new(:_no_action)
|
13
|
+
@held_actions ||= Hash.new(:_no_action)
|
14
|
+
end
|
15
|
+
|
16
|
+
def on(hash,args,block)
|
17
|
+
options = (args.last.is_a?(Hash) ? args.pop : {})
|
18
|
+
|
19
|
+
args.each do |keystroke|
|
20
|
+
hash[keystroke] = block || lambda { |instance| send(options[:do]) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_up(*args,&block)
|
25
|
+
on(@up_actions,args,block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_down(*args,&block)
|
29
|
+
on(@down_actions,args,block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_hold(*args,&block)
|
33
|
+
on(@held_actions,args,block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def button_up(id)
|
37
|
+
action = up_actions[id]
|
38
|
+
target.instance_eval(&action)
|
39
|
+
end
|
40
|
+
|
41
|
+
def trigger_held_buttons
|
42
|
+
held_actions.each do |key,action|
|
43
|
+
target.instance_eval(&action) if window.button_down?(key)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def button_down(id)
|
48
|
+
down_actions.each do |key,action|
|
49
|
+
if window.button_down?(key)
|
50
|
+
target.instance_eval(&action)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/metro/game.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'metro/game/dsl'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
module Game
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def setup(game_configuration)
|
8
|
+
@config = game_configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :config
|
12
|
+
|
13
|
+
def first_scene
|
14
|
+
config.first_scene
|
15
|
+
end
|
16
|
+
|
17
|
+
def width
|
18
|
+
config.width || 640
|
19
|
+
end
|
20
|
+
|
21
|
+
def height
|
22
|
+
config.height || 480
|
23
|
+
end
|
24
|
+
|
25
|
+
def dimensions
|
26
|
+
[ width, height ]
|
27
|
+
end
|
28
|
+
|
29
|
+
def center
|
30
|
+
[ width / 2 , height / 2 ]
|
31
|
+
end
|
32
|
+
|
33
|
+
# TODO: ZOrder related constants that belong to Starry Knight
|
34
|
+
Background, Stars, Players, UI = *0..3
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Metro
|
2
|
+
module Game
|
3
|
+
class DSL
|
4
|
+
|
5
|
+
def self.parse(&block)
|
6
|
+
config = new
|
7
|
+
config.instance_eval(&block)
|
8
|
+
config
|
9
|
+
end
|
10
|
+
|
11
|
+
def first_scene(scene_name = nil)
|
12
|
+
scene_name ? @first_scene = Scenes.find(scene_name) : @first_scene
|
13
|
+
end
|
14
|
+
|
15
|
+
def width(game_width = nil)
|
16
|
+
game_width ? @width = game_width : @width
|
17
|
+
end
|
18
|
+
|
19
|
+
def height(game_height = nil)
|
20
|
+
game_height ? @height = game_height : @height
|
21
|
+
end
|
22
|
+
|
23
|
+
def resolution(w,h)
|
24
|
+
[ width(w), height(h) ]
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/metro/model.rb
ADDED
data/lib/metro/scene.rb
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
require_relative 'scene_view/scene_view'
|
2
|
+
require_relative 'scene_view/components/drawer'
|
3
|
+
require_relative 'event_relay'
|
4
|
+
|
5
|
+
module Metro
|
6
|
+
|
7
|
+
#
|
8
|
+
# A scene is a basic unit of a game. Within a scene you define a number of methods
|
9
|
+
# that handle the initial setup, event configuration, logic updating, and drawing.
|
10
|
+
#
|
11
|
+
# @see #show
|
12
|
+
# @see #update
|
13
|
+
# @see #draw
|
14
|
+
# @see #events
|
15
|
+
#
|
16
|
+
# A fair number of private methods within Scene are prefaced with an underscore.
|
17
|
+
# These methods often call non-underscored methods within those methods. This allows
|
18
|
+
# for scene to configure or perform some functionality, while providing an interface
|
19
|
+
# so that every subclass does not have to constantly call `super`.
|
20
|
+
#
|
21
|
+
class Scene
|
22
|
+
|
23
|
+
#
|
24
|
+
# The window is the main instance of the game. Using window can access a lot of
|
25
|
+
# underlying Metro::Window, a subclass of Gosu::Window, that the Scene class is
|
26
|
+
# obfuscating.
|
27
|
+
#
|
28
|
+
# @see Metro::Window
|
29
|
+
# @see Gosu::Window
|
30
|
+
#
|
31
|
+
attr_reader :window
|
32
|
+
|
33
|
+
#
|
34
|
+
# The events object that is configured through the {#events} method, which stores
|
35
|
+
# all the gamepad and keyboard events defined.
|
36
|
+
#
|
37
|
+
# @see Events
|
38
|
+
#
|
39
|
+
attr_reader :event_relays
|
40
|
+
|
41
|
+
#
|
42
|
+
# Customized views that contain elements to be drawn will be handled by the
|
43
|
+
# view_drawer.
|
44
|
+
#
|
45
|
+
# @see SceneView::Drawer
|
46
|
+
#
|
47
|
+
attr_reader :view_drawer
|
48
|
+
|
49
|
+
#
|
50
|
+
# Captures all classes that subclass Scene.
|
51
|
+
#
|
52
|
+
def self.inherited(base)
|
53
|
+
scenes << base
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# All subclasses of Scene, this should be all the defined scenes
|
58
|
+
# within the game.
|
59
|
+
#
|
60
|
+
# @return an Array of Scene subclasses
|
61
|
+
#
|
62
|
+
def self.scenes
|
63
|
+
@scenes ||= []
|
64
|
+
end
|
65
|
+
|
66
|
+
# This provides the functionality for view handling.
|
67
|
+
include SceneView
|
68
|
+
|
69
|
+
#
|
70
|
+
# A scene is created with a window instance. When subclassing a Scene, you should
|
71
|
+
# hopefully not need to create an {#initialize} method or call `super` but instead
|
72
|
+
# implement the {#show} method which is the point of incision in the subclasses
|
73
|
+
# that allow for the subclasses of Scene to be setup correctly.
|
74
|
+
#
|
75
|
+
def initialize(window)
|
76
|
+
@window = window
|
77
|
+
|
78
|
+
@event_relays ||= []
|
79
|
+
|
80
|
+
@scene_events = EventRelay.new(self,window)
|
81
|
+
events(@scene_events)
|
82
|
+
|
83
|
+
@event_relays << @scene_events
|
84
|
+
|
85
|
+
@view_drawer = SceneView::Drawer.new(self)
|
86
|
+
|
87
|
+
show
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# This method should be defined in the Scene subclass.
|
92
|
+
#
|
93
|
+
# @param [Events] e is the object that you can register button presses
|
94
|
+
#
|
95
|
+
def events(e) ; end
|
96
|
+
|
97
|
+
def add_event_relay(event_relay)
|
98
|
+
@event_relays << event_relay
|
99
|
+
end
|
100
|
+
|
101
|
+
def trigger_held_buttons
|
102
|
+
event_relays.each do |er|
|
103
|
+
er.trigger_held_buttons
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def button_up(id)
|
108
|
+
event_relays.each do |er|
|
109
|
+
er.button_up(id)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def button_down(id)
|
114
|
+
event_relays.each do |er|
|
115
|
+
er.button_down(id)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# This method is solely a non-action method for when events are triggered
|
121
|
+
# for button up and button down
|
122
|
+
#
|
123
|
+
def _no_action ; end
|
124
|
+
|
125
|
+
# This method is called right after initialization
|
126
|
+
def show ; end
|
127
|
+
|
128
|
+
#
|
129
|
+
# This method handles the logic or game loop for the scene.
|
130
|
+
#
|
131
|
+
# @note This method should be implemented in the subclassed Scene
|
132
|
+
#
|
133
|
+
def update ; end
|
134
|
+
|
135
|
+
#
|
136
|
+
# The `_draw` method is called by the Game Window to allow for any view related
|
137
|
+
# drawing needs to be handled before calling the traditional `draw` method defined
|
138
|
+
# in the subclassed Scenes.
|
139
|
+
#
|
140
|
+
def _draw
|
141
|
+
view_drawer.draw(view)
|
142
|
+
draw
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# This method handles all the visual rendering of the scene.
|
147
|
+
#
|
148
|
+
# @note This method should be implemented in the subclassed Scene
|
149
|
+
#
|
150
|
+
def draw ; end
|
151
|
+
|
152
|
+
#
|
153
|
+
# `transition_to` performs the work of transitioning this scene
|
154
|
+
# to another scene.
|
155
|
+
#
|
156
|
+
# @param [String,Symbol,Class] scene_name the name of the Scene which can be either
|
157
|
+
# the class or a string/symbol representation of the shortened scene name.
|
158
|
+
#
|
159
|
+
def transition_to(scene_name)
|
160
|
+
new_scene = Scenes.create(scene_name,window)
|
161
|
+
_prepare_transition(new_scene)
|
162
|
+
window.scene = new_scene
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
#
|
167
|
+
# Before a scene is transitioned away from to a new scene, this private method is
|
168
|
+
# here to allow for any housekeeping or other work that needs to be done before
|
169
|
+
# calling the subclasses implementation of `prepare_transition`.
|
170
|
+
#
|
171
|
+
# @param [Scene] new_scene this is the instance of the scene that is about to replace
|
172
|
+
# the current scene.
|
173
|
+
#
|
174
|
+
def _prepare_transition(new_scene)
|
175
|
+
log.debug "Preparing to transition from scene #{self} to #{new_scene}"
|
176
|
+
prepare_transition(new_scene)
|
177
|
+
end
|
178
|
+
|
179
|
+
#
|
180
|
+
# Before a scene is transisitioned away from to a new scene, this method is called
|
181
|
+
# to allow for the scene to complete any taskss, stop any actions, or pass any
|
182
|
+
# information from the existing scene to the scene that is about to replace it.
|
183
|
+
#
|
184
|
+
# @note This method should be implemented in the subclassed Scene
|
185
|
+
#
|
186
|
+
# @param [Scene] new_scene this is the instance of the scene that is about to replace
|
187
|
+
# the current scene.
|
188
|
+
#
|
189
|
+
def prepare_transition(new_scene) ; end
|
190
|
+
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Metro
|
2
|
+
module SceneView
|
3
|
+
class Drawer
|
4
|
+
|
5
|
+
# The window is necessary as all drawing elements created require
|
6
|
+
# an access to this instance.
|
7
|
+
attr_reader :window
|
8
|
+
|
9
|
+
# The scene is necessary to ensure that any fields which contain
|
10
|
+
# variables within the application are properly interpolated.
|
11
|
+
attr_reader :scene
|
12
|
+
|
13
|
+
def initialize(scene)
|
14
|
+
@scene = scene
|
15
|
+
@window = scene.window
|
16
|
+
after_initialize
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_initialize ; end
|
20
|
+
|
21
|
+
def components
|
22
|
+
@components ||= begin
|
23
|
+
Hash.new(UnsupportedComponent).merge label: Label.new(scene),
|
24
|
+
select: Select.new(scene)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Render all the view elements defined that are supported by this drawer.
|
30
|
+
#
|
31
|
+
def draw(view)
|
32
|
+
view.each do |name,content|
|
33
|
+
component = content['type'].to_sym
|
34
|
+
components[component].draw(content)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
require_relative 'unsupported_component'
|
43
|
+
require_relative 'label'
|
44
|
+
require_relative 'select'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Metro
|
2
|
+
module SceneView
|
3
|
+
class Label < Drawer
|
4
|
+
|
5
|
+
def font
|
6
|
+
@font ||= Gosu::Font.new(window, Gosu::default_font_name, 20)
|
7
|
+
end
|
8
|
+
|
9
|
+
def draw(view)
|
10
|
+
label_text = scene.instance_eval( "\"#{view['text']}\"" )
|
11
|
+
|
12
|
+
label_color = view['color'] || 0xffffffff
|
13
|
+
label_color = label_color.to_i(16) if label_color.is_a? String
|
14
|
+
|
15
|
+
font.draw label_text,
|
16
|
+
view['x'], view['y'], view['z-order'],
|
17
|
+
view['x-factor'] || 1.0, view['y-factor'] || 1.0,
|
18
|
+
label_color
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Metro
|
2
|
+
module SceneView
|
3
|
+
class Select < Drawer
|
4
|
+
|
5
|
+
attr_accessor :selected_index, :options
|
6
|
+
|
7
|
+
def after_initialize
|
8
|
+
name, content = scene.view.find { |name,content| content['type'].to_sym == :select }
|
9
|
+
|
10
|
+
if content
|
11
|
+
@selected_index = 0
|
12
|
+
@options = content['options']
|
13
|
+
events = EventRelay.new(self,window)
|
14
|
+
|
15
|
+
events.on_up Gosu::KbLeft, Gosu::GpLeft, Gosu::KbUp, Gosu::GpUp, do: :previous_option
|
16
|
+
events.on_up Gosu::KbRight, Gosu::GpRight, Gosu::KbDown, Gosu::GpDown, do: :next_option
|
17
|
+
events.on_up Gosu::KbEnter, Gosu::KbReturn, Gosu::GpButton0, do: :selection
|
18
|
+
|
19
|
+
scene.add_event_relay events
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def selection
|
24
|
+
scene_method = options[selected_index].downcase.gsub(/\s/,'_')
|
25
|
+
scene.send scene_method
|
26
|
+
end
|
27
|
+
|
28
|
+
def previous_option
|
29
|
+
@selected_index = @selected_index - 1
|
30
|
+
@selected_index = options.length - 1 if @selected_index <= -1
|
31
|
+
end
|
32
|
+
|
33
|
+
def next_option
|
34
|
+
@selected_index = @selected_index + 1
|
35
|
+
@selected_index = 0 if @selected_index >= options.length
|
36
|
+
end
|
37
|
+
|
38
|
+
def _no_action ; end
|
39
|
+
|
40
|
+
def font
|
41
|
+
@font ||= Gosu::Font.new(window, Gosu::default_font_name, 20)
|
42
|
+
end
|
43
|
+
|
44
|
+
def draw(view)
|
45
|
+
view['options'].each_with_index do |option,index|
|
46
|
+
|
47
|
+
color = view["color"] || 0xffffffff
|
48
|
+
|
49
|
+
if index == selected_index
|
50
|
+
color = view["highlight-color"] || 0xffffff00
|
51
|
+
end
|
52
|
+
|
53
|
+
color = color.to_i(16) if color.is_a? String
|
54
|
+
|
55
|
+
y_position = view["y"] + view["padding"] * index
|
56
|
+
font.draw option, view["x"], y_position, Metro::Game::UI, 1.0, 1.0, color
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
module SceneView
|
5
|
+
|
6
|
+
class JSONView
|
7
|
+
def self.find(view_name)
|
8
|
+
File.exists? json_view_name(view_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.parse(view_name)
|
12
|
+
JSON.parse File.read json_view_name(view_name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.json_view_name(view_name)
|
16
|
+
File.extname(view_name) == "" ? "#{view_name}.json" : view_name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative 'yaml_view'
|
2
|
+
require_relative 'json_view'
|
3
|
+
require_relative 'no_view'
|
4
|
+
|
5
|
+
module Metro
|
6
|
+
module SceneView
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Supported view formats
|
14
|
+
#
|
15
|
+
def _view_parsers
|
16
|
+
[ YAMLView, JSONView, NoView ]
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Loads the view based on the view parsers.
|
21
|
+
#
|
22
|
+
def view
|
23
|
+
@view ||= begin
|
24
|
+
parser = _view_parsers.find { |parser| parser.find self.class.view_name }
|
25
|
+
parser.parse self.class.view_name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
|
31
|
+
#
|
32
|
+
# A Scene by default uses the name of the Scene to find it's associated
|
33
|
+
# view.
|
34
|
+
#
|
35
|
+
# @example Custom View Name
|
36
|
+
#
|
37
|
+
# class ClosingScene < Metro::Scene
|
38
|
+
# view_name :alternate
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
def view_name(filename = nil)
|
42
|
+
if filename
|
43
|
+
@view_name = File.join "views", filename.to_s
|
44
|
+
else
|
45
|
+
@view_name ||= File.join "views", "#{self.to_s[/^(.+)Scene$/,1].downcase}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
module SceneView
|
5
|
+
|
6
|
+
class YAMLView
|
7
|
+
def self.find(view_name)
|
8
|
+
File.exists? yaml_view_name(view_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.parse(view_name)
|
12
|
+
YAML.load File.read yaml_view_name(view_name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.yaml_view_name(view_name)
|
16
|
+
File.extname(view_name) == "" ? "#{view_name}.yaml" : view_name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/metro/scenes.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Metro
|
2
|
+
module Scenes
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def scenes
|
6
|
+
@scenes ||= Scene.scenes.inject({}) do |dict,scene|
|
7
|
+
name = scene.to_s.gsub(/Scene$/,'').downcase.to_sym
|
8
|
+
dict[name] = scene
|
9
|
+
dict[scene] = scene
|
10
|
+
dict
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
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
|
+
end
|
23
|
+
end
|
data/lib/metro/window.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'scenes'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
|
5
|
+
#
|
6
|
+
# A subclass of the Gosu::Window which simply acts as system
|
7
|
+
# to shuffle in and out scenes and transfer events.
|
8
|
+
#
|
9
|
+
class Window < Gosu::Window
|
10
|
+
|
11
|
+
attr_reader :scene
|
12
|
+
|
13
|
+
def initialize(width,height,something)
|
14
|
+
super width, height, something
|
15
|
+
end
|
16
|
+
|
17
|
+
def scene=(new_scene)
|
18
|
+
@scene = new_scene
|
19
|
+
end
|
20
|
+
|
21
|
+
def update
|
22
|
+
scene.trigger_held_buttons
|
23
|
+
scene.update
|
24
|
+
end
|
25
|
+
|
26
|
+
def draw
|
27
|
+
scene._draw
|
28
|
+
end
|
29
|
+
|
30
|
+
def button_up(id)
|
31
|
+
scene.button_up(id)
|
32
|
+
end
|
33
|
+
|
34
|
+
def button_down(id)
|
35
|
+
scene.button_down(id)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
data/metro.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'metro/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "metro"
|
8
|
+
gem.version = Metro::VERSION
|
9
|
+
gem.authors = ["Franklin Webber"]
|
10
|
+
gem.email = ["franklin.webber@gmail.com"]
|
11
|
+
gem.description = %q{A framework around Gosu to make game creation less tedious}
|
12
|
+
gem.summary = %q{A framework around Gosu to make game creation less tedious}
|
13
|
+
gem.homepage = "https://github.com/burtlo/metro"
|
14
|
+
|
15
|
+
gem.add_dependency 'gosu', '~> 0.7'
|
16
|
+
|
17
|
+
gem.files = `git ls-files`.split($/)
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
+
gem.require_paths = ["lib"]
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: metro
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Franklin Webber
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: gosu
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.7'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.7'
|
30
|
+
description: A framework around Gosu to make game creation less tedious
|
31
|
+
email:
|
32
|
+
- franklin.webber@gmail.com
|
33
|
+
executables:
|
34
|
+
- metro
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- Gemfile
|
40
|
+
- LICENSE.txt
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- bin/metro
|
44
|
+
- lib/metro.rb
|
45
|
+
- lib/metro/event_relay.rb
|
46
|
+
- lib/metro/game.rb
|
47
|
+
- lib/metro/game/dsl.rb
|
48
|
+
- lib/metro/model.rb
|
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
|
54
|
+
- lib/metro/scene_view/json_view.rb
|
55
|
+
- lib/metro/scene_view/no_view.rb
|
56
|
+
- lib/metro/scene_view/scene_view.rb
|
57
|
+
- lib/metro/scene_view/yaml_view.rb
|
58
|
+
- lib/metro/scenes.rb
|
59
|
+
- lib/metro/version.rb
|
60
|
+
- lib/metro/window.rb
|
61
|
+
- metro.gemspec
|
62
|
+
homepage: https://github.com/burtlo/metro
|
63
|
+
licenses: []
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.8.24
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: A framework around Gosu to make game creation less tedious
|
86
|
+
test_files: []
|