metro 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/gosu_ext/color.rb +24 -0
- data/lib/metro.rb +6 -2
- data/lib/metro/animation/animation.rb +78 -49
- data/lib/metro/animation/easing.rb +22 -19
- data/lib/metro/animation/implicit_animation.rb +84 -25
- data/lib/metro/game.rb +5 -1
- data/lib/metro/game/dsl.rb +4 -0
- data/lib/metro/models/generic.rb +12 -0
- data/lib/metro/models/image.rb +29 -0
- data/lib/metro/models/label.rb +29 -0
- data/lib/metro/models/model.rb +188 -0
- data/lib/metro/models/select.rb +77 -0
- data/lib/metro/scene.rb +106 -6
- data/lib/metro/scene_actor.rb +26 -0
- data/lib/metro/scene_view/scene_view.rb +24 -27
- data/lib/metro/version.rb +1 -1
- data/lib/metro/window.rb +1 -1
- metadata +9 -9
- data/lib/metro/model.rb +0 -12
- data/lib/metro/scene_view/drawers/artists_block.rb +0 -17
- data/lib/metro/scene_view/drawers/composite_drawer.rb +0 -87
- data/lib/metro/scene_view/drawers/drawer.rb +0 -115
- data/lib/metro/scene_view/drawers/image.rb +0 -31
- data/lib/metro/scene_view/drawers/label.rb +0 -28
- data/lib/metro/scene_view/drawers/select.rb +0 -70
@@ -0,0 +1,24 @@
|
|
1
|
+
class Gosu::Color
|
2
|
+
|
3
|
+
alias_method :gosu_initialize, :initialize
|
4
|
+
|
5
|
+
#
|
6
|
+
# Monkey-patching the initialize to allow for another Gosu::Color
|
7
|
+
# and Strings.
|
8
|
+
#
|
9
|
+
def initialize(*args)
|
10
|
+
if args.length == 1
|
11
|
+
value = args.first
|
12
|
+
if value.is_a? Gosu::Color
|
13
|
+
gosu_initialize value.alpha, value.red, value.green, value.blue
|
14
|
+
elsif value.is_a? String
|
15
|
+
gosu_initialize value.to_i(16)
|
16
|
+
else
|
17
|
+
gosu_initialize value
|
18
|
+
end
|
19
|
+
else
|
20
|
+
gosu_initialize *args
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/metro.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'gosu'
|
2
|
+
require 'gosu_ext/color'
|
3
|
+
|
2
4
|
require 'logger'
|
3
5
|
|
6
|
+
|
4
7
|
require 'metro/version'
|
5
8
|
require 'metro/window'
|
6
9
|
require 'metro/game'
|
7
|
-
require 'metro/model'
|
8
10
|
require 'metro/scene'
|
11
|
+
require 'metro/models/model'
|
12
|
+
require 'metro/models/generic'
|
9
13
|
|
10
14
|
def asset_path(name)
|
11
15
|
File.join Dir.pwd, "assets", name
|
@@ -50,7 +54,6 @@ module Metro
|
|
50
54
|
$LOAD_PATH.unshift(Dir.pwd) unless $LOAD_PATH.include?(Dir.pwd)
|
51
55
|
Dir['models/*.rb'].each {|model| require model }
|
52
56
|
Dir['scenes/*.rb'].each {|scene| require scene }
|
53
|
-
Dir['drawers/*.rb'].each {|drawer| require drawer }
|
54
57
|
end
|
55
58
|
|
56
59
|
def load_game_configuration(filename)
|
@@ -62,6 +65,7 @@ module Metro
|
|
62
65
|
|
63
66
|
def start_game
|
64
67
|
window = Window.new Game.width, Game.height, Game.fullscreen?
|
68
|
+
window.caption = Game.name
|
65
69
|
window.scene = Scenes.generate(Game.first_scene)
|
66
70
|
window.show
|
67
71
|
end
|
@@ -1,65 +1,94 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
module Metro
|
2
|
+
|
3
|
+
#
|
4
|
+
# Animation is the motion that gives a system it's life. An animation
|
5
|
+
# in this case is a really a mechanism that allows for an action to
|
6
|
+
# be repeated for a given interval of time.
|
7
|
+
#
|
8
|
+
class Animation
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
@current_step = 0
|
12
|
+
|
13
|
+
options.each do |key,value|
|
14
|
+
send :instance_variable_set, "@#{key}".to_sym, value
|
15
|
+
self.class.send :define_method, key do
|
16
|
+
instance_variable_get("@#{key}")
|
17
|
+
end
|
12
18
|
end
|
19
|
+
after_initialize
|
13
20
|
end
|
14
|
-
after_initialize
|
15
|
-
end
|
16
|
-
|
17
|
-
def completed?
|
18
|
-
current_step >= interval
|
19
|
-
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
#
|
23
|
+
# Sets the action that happens with each step of the animation.
|
24
|
+
#
|
25
|
+
def on_step(&block)
|
26
|
+
@step_block = block
|
27
|
+
end
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
+
#
|
30
|
+
# Sets the action that happens when the animation is completed.
|
31
|
+
#
|
32
|
+
def on_complete(&block)
|
33
|
+
@complete_block = block
|
34
|
+
end
|
29
35
|
|
30
|
-
|
31
|
-
|
32
|
-
|
36
|
+
#
|
37
|
+
# Perform a step of an animation, if it hasn't already been completed.
|
38
|
+
#
|
39
|
+
def update
|
40
|
+
return if completed?
|
33
41
|
|
34
|
-
|
35
|
-
|
36
|
-
end
|
42
|
+
execute_step
|
43
|
+
next_step
|
37
44
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
45
|
+
complete! if completed?
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# @return the current step of the animation.
|
50
|
+
#
|
51
|
+
attr_reader :current_step
|
52
|
+
|
53
|
+
attr_reader :step_block, :complete_block
|
54
|
+
|
55
|
+
#
|
56
|
+
# Move to the next step in the animation.
|
57
|
+
#
|
58
|
+
def next_step
|
59
|
+
@current_step = current_step + step_interval
|
44
60
|
end
|
45
|
-
end
|
46
61
|
|
47
|
-
|
48
|
-
|
49
|
-
|
62
|
+
#
|
63
|
+
# @return the interval at which the animation take place.
|
64
|
+
#
|
65
|
+
def step_interval
|
66
|
+
1
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# @return true if the animation has completed all the actions, false
|
71
|
+
# if there are remaining actions.
|
72
|
+
#
|
73
|
+
def completed?
|
74
|
+
current_step >= interval
|
75
|
+
end
|
50
76
|
|
51
|
-
|
52
|
-
|
53
|
-
|
77
|
+
#
|
78
|
+
# Perform the action that happens with each step of the animation.
|
79
|
+
#
|
80
|
+
def execute_step
|
81
|
+
context.instance_eval(&@step_block) if step_block and context
|
82
|
+
end
|
54
83
|
|
55
|
-
|
56
|
-
|
57
|
-
|
84
|
+
#
|
85
|
+
# Perform the action that happens when the animation is completed.
|
86
|
+
#
|
87
|
+
def complete!
|
88
|
+
context.instance_eval(&@complete_block) if complete_block and context
|
89
|
+
end
|
58
90
|
|
59
|
-
def completed(&block)
|
60
|
-
@completed = block if block
|
61
91
|
end
|
62
|
-
|
63
92
|
end
|
64
93
|
|
65
94
|
require_relative 'implicit_animation'
|
@@ -1,28 +1,31 @@
|
|
1
|
-
module
|
2
|
-
module
|
3
|
-
extend self
|
1
|
+
module Metro
|
2
|
+
module Easing
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
module Linear
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def linear(moment,start,change,interval)
|
8
|
+
change * moment / interval + start
|
9
|
+
end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
def calculate(start,final,interval)
|
12
|
+
change = final - start
|
13
|
+
(1..interval).map { |time| linear(time.to_f,start,change,interval) }
|
14
|
+
end
|
12
15
|
end
|
13
|
-
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
+
module EaseIn
|
18
|
+
extend self
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
def ease_in_quad(moment,start,change,interval)
|
21
|
+
change * (moment = moment / interval) * moment + start
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
def calculate(start,final,interval)
|
25
|
+
change = final - start
|
26
|
+
(1..interval).map { |time| ease_in_quad(time.to_f,start,change,interval) }
|
27
|
+
end
|
25
28
|
end
|
29
|
+
|
26
30
|
end
|
27
31
|
end
|
28
|
-
|
@@ -1,43 +1,102 @@
|
|
1
1
|
require_relative 'easing'
|
2
2
|
|
3
|
-
|
3
|
+
module Metro
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
#
|
6
|
+
# An Implicit Animation is an animation without all the work.
|
7
|
+
# This little animation will take care of figuring out moving an
|
8
|
+
# actor from one position to another, the rotation, the alpha,
|
9
|
+
# etc.
|
10
|
+
#
|
11
|
+
# @example Creating an explicit animation that moves a player
|
12
|
+
#
|
13
|
+
# animation = ImplicitAnimation.new actor: player,
|
14
|
+
# to: { x: final_x, y: final_y },
|
15
|
+
# interval: 80,
|
16
|
+
# easing: :ease_in,
|
17
|
+
# context: scene
|
18
|
+
#
|
19
|
+
# animation.on_complete do
|
20
|
+
# transition_to :main
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# Here an animation is created that will move the player to the
|
24
|
+
# position (final_x,final_y), specified in the :to hash that is
|
25
|
+
# provided, over the interval of 80 steps. Additionally the movement
|
26
|
+
# is done with an easing in.
|
27
|
+
#
|
28
|
+
# @note The actor object must respond to setter methods that match
|
29
|
+
# the specified attributes (e.g. x, y).
|
30
|
+
#
|
31
|
+
# The context provided is the context that the 'on_complete' block
|
32
|
+
# is executed. In this case, upon completition, transition the scene
|
33
|
+
# from the current one to the main scene.
|
34
|
+
#
|
35
|
+
class ImplicitAnimation < Animation
|
7
36
|
|
8
|
-
|
9
|
-
|
10
|
-
|
37
|
+
#
|
38
|
+
# @return the array of attributes that are being animated.
|
39
|
+
#
|
40
|
+
attr_reader :attributes
|
11
41
|
|
12
|
-
|
13
|
-
@
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
@steppings[stepping]
|
19
|
-
end
|
42
|
+
#
|
43
|
+
# @return a Hash that contains all the animation step deltas
|
44
|
+
# for each attribute.
|
45
|
+
#
|
46
|
+
attr_reader :deltas
|
20
47
|
|
21
|
-
|
22
|
-
@easing
|
23
|
-
|
48
|
+
#
|
49
|
+
# @return the type of easing that the implicit animation should employ.
|
50
|
+
# By default it uses linear but can be overridden when the easing is
|
51
|
+
# configured.
|
52
|
+
#
|
53
|
+
attr_reader :easing
|
24
54
|
|
25
|
-
|
26
|
-
|
55
|
+
#
|
56
|
+
# Additional initializion is required to calculate the attributes
|
57
|
+
# that are going to be animated and to determine each of their deltas.
|
58
|
+
#
|
59
|
+
def after_initialize
|
60
|
+
@deltas = {}
|
27
61
|
|
28
|
-
|
62
|
+
@attributes = to.map { |attribute,final| attribute }
|
29
63
|
|
30
|
-
|
31
|
-
|
32
|
-
|
64
|
+
to.each do |attribute,final|
|
65
|
+
start = actor.send(attribute)
|
66
|
+
deltas[attribute] = stepping(easing).calculate(start.to_f,final.to_f,interval.to_f)
|
67
|
+
end
|
33
68
|
end
|
34
69
|
|
35
|
-
|
70
|
+
#
|
71
|
+
# @return the correct easing based on the specified name. When the name
|
72
|
+
# provided does not match anything then default to linear easing.
|
73
|
+
#
|
74
|
+
def stepping(stepping)
|
75
|
+
@steppings ||= begin
|
76
|
+
hash = Hash.new(Easing::Linear)
|
77
|
+
hash.merge! linear: Easing::Linear,
|
78
|
+
ease_in: Easing::EaseIn
|
79
|
+
end
|
80
|
+
@steppings[stepping]
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# The ImplicitAnimation overrides the {Animation#execute_step} and
|
85
|
+
# updates the attributes of the actor based upon the value of the
|
86
|
+
# current animation step.
|
87
|
+
#
|
88
|
+
def execute_step
|
36
89
|
attributes.each do |attribute|
|
37
90
|
actor.send "#{attribute}=", delta_for_step(attribute)
|
38
91
|
end
|
39
92
|
end
|
40
93
|
|
41
|
-
|
94
|
+
#
|
95
|
+
# @return the delta for the attribute for the given step
|
96
|
+
#
|
97
|
+
def delta_for_step(attribute)
|
98
|
+
deltas[attribute].at(current_step)
|
99
|
+
end
|
42
100
|
|
101
|
+
end
|
43
102
|
end
|
data/lib/metro/game.rb
CHANGED
@@ -33,11 +33,15 @@ module Metro
|
|
33
33
|
def fullscreen?
|
34
34
|
!!config.fullscreen
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def debug?
|
38
38
|
!!config.debug
|
39
39
|
end
|
40
40
|
|
41
|
+
def name
|
42
|
+
config.name
|
43
|
+
end
|
44
|
+
|
41
45
|
# TODO: ZOrder related constants that belong to Starry Knight
|
42
46
|
Background, Stars, Players, UI = *0..3
|
43
47
|
|
data/lib/metro/game/dsl.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Metro
|
2
|
+
module Models
|
3
|
+
|
4
|
+
#
|
5
|
+
# Draws an Image
|
6
|
+
#
|
7
|
+
# @example Using the Image in a view file
|
8
|
+
# model: "metro::models::image"
|
9
|
+
#
|
10
|
+
class Image < Model
|
11
|
+
|
12
|
+
attr_accessor :angle, :center_x, :center_y, :x_factor, :y_factor
|
13
|
+
|
14
|
+
def image
|
15
|
+
@image ||= Gosu::Image.new(window,asset_path(path))
|
16
|
+
end
|
17
|
+
|
18
|
+
def draw
|
19
|
+
image.draw_rot x, y, z_order,
|
20
|
+
angle.to_f,
|
21
|
+
center_x, center_y,
|
22
|
+
x_factor, y_factor,
|
23
|
+
color
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|