or2d 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/or2d/animation.rb +60 -0
- data/lib/or2d/animations/composite_animations.rb +160 -0
- data/lib/or2d/animations/entity_animations.rb +221 -0
- data/lib/or2d/composite.rb +73 -0
- data/lib/or2d/composites/projectile.rb +97 -0
- data/lib/or2d/composites/sprite.rb +245 -0
- data/lib/or2d/composites/text.rb +167 -0
- data/lib/or2d/console.rb +199 -0
- data/lib/or2d/entity.rb +78 -0
- data/lib/or2d/instance.rb +186 -0
- data/lib/or2d/patches/music.rb +30 -0
- data/lib/or2d/patches/renderable.rb +5 -0
- data/lib/or2d/patches/sound.rb +18 -0
- data/lib/or2d/patches/sprite.rb +20 -0
- data/lib/or2d/patches/window.rb +9 -0
- data/lib/or2d/resource.rb +182 -0
- data/lib/or2d/scene.rb +160 -0
- data/lib/or2d/scenes/placeholder_scene.rb +70 -0
- data/lib/or2d/version.rb +50 -0
- data/lib/or2d.rb +94 -0
- metadata +146 -0
@@ -0,0 +1,245 @@
|
|
1
|
+
module OR2D::Composites
|
2
|
+
# The Composite Sprite class is a composite entity that is made up of multiple sprites entities that behave as the composite layers.
|
3
|
+
class Sprite < OR2D::Composite
|
4
|
+
include OR2D::Animations::CompositeAnimations
|
5
|
+
|
6
|
+
# Constructs a new Composite Sprite object.
|
7
|
+
# @param options [Hash] a hash of options
|
8
|
+
def initialize(options)
|
9
|
+
super(options[:id] || "SpriteComposite_#{SecureRandom.uuid}")
|
10
|
+
if options[:layers]
|
11
|
+
options[:layers].each do |layer|
|
12
|
+
add_layer(layer[:type], layer, entity: layer[:entity])
|
13
|
+
end
|
14
|
+
else
|
15
|
+
add_layer(:sprite, options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Add a layer to the Sprite. This will also reorder the z-index of all other layers in the Sprite.
|
20
|
+
# @param type [Symbol] the type of Entity object to add
|
21
|
+
# @param options [Hash] a hash of options to pass to the Entity object
|
22
|
+
# @param entity [OR2D::Entity] an optional Entity object to add if the type is :entity
|
23
|
+
# @param position [Symbol] the position to add the layer to, either :top or :bottom
|
24
|
+
def add_layer(type, options, entity: nil, position: :top)
|
25
|
+
if @layers.empty?
|
26
|
+
super(type, options, entity: entity)
|
27
|
+
id = @layers.keys.first
|
28
|
+
elsif position == :top
|
29
|
+
super(type, options.merge(z: OR2D.game.entities[@layers.keys.first].resource.z + 1), entity: entity)
|
30
|
+
sort_by_z
|
31
|
+
id = @layers.keys.first
|
32
|
+
elsif position == :bottom
|
33
|
+
super(type, options.merge(z: OR2D.game.entities[@layers.keys.last].resource.z - 1), entity: entity)
|
34
|
+
sort_by_z
|
35
|
+
id = @layers.keys.last
|
36
|
+
else
|
37
|
+
add_layer(type, options, entity: entity, position: :top)
|
38
|
+
end
|
39
|
+
|
40
|
+
@layers[id][:offsets] = [options[:x_offset] || 0,
|
41
|
+
options[:y_offset] || 0,
|
42
|
+
options[:width_offset] || 0,
|
43
|
+
options[:height_offset] || 0]
|
44
|
+
apply_offsets(id)
|
45
|
+
id
|
46
|
+
end
|
47
|
+
|
48
|
+
# Remove a layer from the Sprite. This will also reorder the z-index of all other layers in the Sprite.
|
49
|
+
# @param id [String] the id of the layer to remove
|
50
|
+
def remove_layer(id)
|
51
|
+
super(id)
|
52
|
+
sort_by_z unless @layers.empty? || @layers.size == 1
|
53
|
+
end
|
54
|
+
|
55
|
+
# Bring a layer to the front of the Sprite. This will also reorder the z-index of all other layers in the Sprite.
|
56
|
+
# @param id [String] the id of the layer to bring to the front
|
57
|
+
def bring_to_front(id)
|
58
|
+
OR2D.game.entities[id].resource.z = OR2D.game.entities[@layers.keys.first].resource.z
|
59
|
+
@layers.each_key do |key|
|
60
|
+
next if key == id
|
61
|
+
|
62
|
+
OR2D.game.entities[key].resource.z -= 1
|
63
|
+
end
|
64
|
+
sort_by_z
|
65
|
+
end
|
66
|
+
|
67
|
+
# Send a layer to the back of the Sprite. This will also reorder the z-index of all other layers in the Sprite.
|
68
|
+
# @param id [String] the id of the layer to send to the back
|
69
|
+
def send_to_back(id)
|
70
|
+
OR2D.game.entities[id].resource.z = OR2D.game.entities[@layers.keys.last].resource.z
|
71
|
+
@layers.each_key do |key|
|
72
|
+
next if key == id
|
73
|
+
|
74
|
+
OR2D.game.entities[key].resource.z += 1
|
75
|
+
end
|
76
|
+
sort_by_z
|
77
|
+
end
|
78
|
+
|
79
|
+
# Swap the z-index of two layers in the Sprite. This will also reorder the z-index of all other layers in the Sprite.
|
80
|
+
# @param from_idx [String] the index of the id of the layer to swap
|
81
|
+
# @param to_idx [String] the index of the id of the layer to swap with
|
82
|
+
def swap(from_idx, to_idx)
|
83
|
+
from = @layers.keys[from_idx]
|
84
|
+
to = @layers.keys[to_idx]
|
85
|
+
OR2D.game.entities[from].resource.z, OR2D.game.entities[to].resource.z = OR2D.game.entities[to].resource.z, OR2D.game.entities[from].resource.z
|
86
|
+
sort_by_z
|
87
|
+
end
|
88
|
+
|
89
|
+
# Set the height of all layers in the Sprite.
|
90
|
+
# @param height [Integer] the height to set
|
91
|
+
def height=(height)
|
92
|
+
@layers.each_key do |id|
|
93
|
+
OR2D.game.entities[id].height = height + @layers[id][:offsets][3]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Get the height of a specific layer.
|
98
|
+
# @param layer_idx [Integer] the index of the layer to get the height of
|
99
|
+
def get_layer_height(layer_idx = -1)
|
100
|
+
OR2D.game.entities[@layers.keys[layer_idx]].height
|
101
|
+
end
|
102
|
+
|
103
|
+
# Set the height of the Sprite or a specific layer with or without offsets.
|
104
|
+
# @param height [Integer] the height to set
|
105
|
+
# @param layer_id [String] the id of the layer to set the height of
|
106
|
+
# @param offsets [Boolean] whether or not to apply offsets to the height
|
107
|
+
def set_layer_height(layer_id, height, offsets: true)
|
108
|
+
OR2D.game.entities[layer_id].height = offsets ? height + @layers[layer_id][:offsets][3] : height
|
109
|
+
end
|
110
|
+
|
111
|
+
# Set the width of the Sprite.
|
112
|
+
# @param width [Integer] the width to set
|
113
|
+
def width=(width)
|
114
|
+
@layers.each_key do |id|
|
115
|
+
OR2D.game.entities[id].width = width + @layers[id][:offsets][2]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Get the width of a specific layer.
|
120
|
+
# @param layer_idx [Integer] the index of the layer to get the width of
|
121
|
+
def get_layer_width(layer_idx = -1)
|
122
|
+
OR2D.game.entities[@layers.keys[layer_idx]].width
|
123
|
+
end
|
124
|
+
|
125
|
+
# Set the width of the Sprite or a specific layer with or without offsets.
|
126
|
+
# @param width [Integer] the width to set
|
127
|
+
# @param layer_id [String] the id of the layer to set the width of
|
128
|
+
# @param offsets [Boolean] whether or not to apply offsets to the width
|
129
|
+
def set_layer_width(layer_id, width, offsets: true)
|
130
|
+
OR2D.game.entities[layer_id].width = offsets ? width + @layers[layer_id][:offsets][2] : width
|
131
|
+
end
|
132
|
+
|
133
|
+
# Get the x-coordinate of the Sprite. This is determined by the last layer's x-coordinate.
|
134
|
+
# @return [Integer] the x-coordinate of the Sprite
|
135
|
+
def x
|
136
|
+
OR2D.game.entities[@layers.keys.last].x
|
137
|
+
end
|
138
|
+
|
139
|
+
# Set the x-coordinate of the Sprite with offsets.
|
140
|
+
# @param x_coordinate [Integer] the x-coordinate to set
|
141
|
+
def x=(x_coordinate)
|
142
|
+
@layers.each_key do |id|
|
143
|
+
OR2D.game.entities[id].x = x_coordinate + @layers[id][:offsets][0]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Get the x-coordinate of a specific layer.
|
148
|
+
# @param layer_idx [Integer] the index of the layer to get the x-coordinate of
|
149
|
+
def get_layer_x(layer_idx = -1)
|
150
|
+
OR2D.game.entities[@layers.keys[layer_idx]].x
|
151
|
+
end
|
152
|
+
|
153
|
+
# Set the x-coordinate of a specific layer with or without offsets.
|
154
|
+
# @param x_coordinate [Integer] the x-coordinate to set
|
155
|
+
# @param layer_id [Integer] the layer to set the x-coordinate of
|
156
|
+
# @param offsets [Boolean] whether or not to apply offsets
|
157
|
+
def set_layer_x(layer_id, x_coordinate, offsets: true)
|
158
|
+
OR2D.game.entities[layer_id].x = offsets ? x_coordinate + @layers[layer_id][:offsets][0] : x_coordinate
|
159
|
+
end
|
160
|
+
|
161
|
+
# Get the y-coordinate of the Sprite. This is determined by the last layer's y-coordinate.
|
162
|
+
# @return [Integer] the y-coordinate of the Sprite
|
163
|
+
def y
|
164
|
+
OR2D.game.entities[@layers.keys.last].y
|
165
|
+
end
|
166
|
+
|
167
|
+
# Set the y-coordinate of the Sprite with offsets.
|
168
|
+
# @param y_coordinate [Integer] the y-coordinate to set
|
169
|
+
def y=(y_coordinate)
|
170
|
+
@layers.each_key do |id|
|
171
|
+
OR2D.game.entities[id].y = y_coordinate + @layers[id][:offsets][1]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Get the y-coordinate of a specific layer.
|
176
|
+
# @param layer_idx [Integer] the index of the layer to get the y-coordinate of
|
177
|
+
def get_layer_y(layer_idx = -1)
|
178
|
+
OR2D.game.entities[@layers.keys[layer_idx]].y
|
179
|
+
end
|
180
|
+
|
181
|
+
# Set the y-coordinate of the Sprite or a specific layer with or without offsets.
|
182
|
+
# @param y_coordinate [Integer] the y-coordinate to set
|
183
|
+
# @param layer_id [String] the id of the layer to set the y-coordinate of
|
184
|
+
# @param offsets [Boolean] whether or not to apply offsets to the y-coordinate
|
185
|
+
def set_layer_y(layer_id, y_coordinate, offsets: true)
|
186
|
+
OR2D.game.entities[layer_id].y = offsets ? y_coordinate + @layers[layer_id][:offsets][1] : y_coordinate
|
187
|
+
end
|
188
|
+
|
189
|
+
# Plays all animations for layers that are visible.
|
190
|
+
# @param options [Hash] the options to play the animations with
|
191
|
+
# @note Animations should be passed using the following convention:
|
192
|
+
def play(options = {})
|
193
|
+
if options.key?(:layers)
|
194
|
+
options[:layers].each do |layer_id, options|
|
195
|
+
next unless @layers[layer_id][:show]
|
196
|
+
next unless OR2D.game.entities[layer_id].resource.respond_to?(:play)
|
197
|
+
next if options[:except].include?(layer_id)
|
198
|
+
|
199
|
+
OR2D.game.entities[layer_id].resource.play(animation: options[:animation],
|
200
|
+
loop: options[:loop],
|
201
|
+
flip: options[:flip],
|
202
|
+
&options[:done])
|
203
|
+
|
204
|
+
end
|
205
|
+
elsif options.key?(:layer)
|
206
|
+
return unless @layers[options[:layer]][:show]
|
207
|
+
return unless OR2D.game.entities[options[:layer]].resource.respond_to?(:play)
|
208
|
+
|
209
|
+
OR2D.game.entities[options[:layer]].resource.play(animation: options[:animation],
|
210
|
+
loop: options[:loop],
|
211
|
+
flip: options[:flip],
|
212
|
+
&options[:done])
|
213
|
+
else
|
214
|
+
@layers.each do |id, properties|
|
215
|
+
next unless properties[:show]
|
216
|
+
next unless OR2D.game.entities[id].resource.respond_to?(:play)
|
217
|
+
next if options[:except].include?(id)
|
218
|
+
|
219
|
+
OR2D.game.entities[id].resource.play(animation: options[:animation],
|
220
|
+
loop: options[:loop],
|
221
|
+
flip: options[:flip],
|
222
|
+
&options[:done])
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Sort the layers of the Sprite by their by z-coordinate.
|
228
|
+
def sort_by_z
|
229
|
+
@layers.keys
|
230
|
+
.sort_by! { |key| -OR2D.game.entities[key].resource.z }
|
231
|
+
.each { |k| @layers[k] = @layers.delete(k) }
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def apply_all_offsets
|
237
|
+
@layers.each_key { |id| apply_offsets(id) }
|
238
|
+
end
|
239
|
+
|
240
|
+
def apply_offsets(layer_id)
|
241
|
+
OR2D.game.entities[layer_id].x += @layers[layer_id][:offsets][0]
|
242
|
+
OR2D.game.entities[layer_id].y += @layers[layer_id][:offsets][1]
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module OR2D::Composites
|
2
|
+
# The Composite Text class is a composite entity that can be used to display multiple lines of text. It displays each line of text on a separate layer. It displays sentences character by character.
|
3
|
+
class Text < OR2D::Composite
|
4
|
+
include OR2D::Animations::CompositeAnimations
|
5
|
+
|
6
|
+
# Construct a new Composite Text object.
|
7
|
+
# @param options [Hash] the options to create the Composite Text object with
|
8
|
+
# @option options [Integer] :limit (24) the maximum number of characters that can be displayed on a single line
|
9
|
+
# @option options [Integer] :lines (0) the number of lines that can be displayed
|
10
|
+
# @option options [Integer] :update_interval (5) the number of frames between each update
|
11
|
+
def initialize(options = {})
|
12
|
+
super(options[:id] || "TextComposite_#{SecureRandom.uuid}")
|
13
|
+
@limit = options[:limit] || 24
|
14
|
+
@lines = 0
|
15
|
+
@update_interval = options[:update_interval] || 5
|
16
|
+
if options[:lines]
|
17
|
+
options[:lines].each do |line_opt|
|
18
|
+
add_line(line_opt)
|
19
|
+
end
|
20
|
+
elsif options[:line]
|
21
|
+
add_line(options[:line])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get the x coordinate of the text object.
|
26
|
+
# @param last [Boolean] whether to get the x coordinate of the last layer or the first layer
|
27
|
+
# @return [Integer] the x coordinate of the text object
|
28
|
+
def x(last: false)
|
29
|
+
OR2D.game.entities[last ? @layers.keys.last : @layers.keys.first].x
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get the y coordinate of the text object.
|
33
|
+
# @param last [Boolean] whether to get the y coordinate of the last layer or the first layer
|
34
|
+
# @return [Integer] the y coordinate of the text object
|
35
|
+
def y(last: false)
|
36
|
+
OR2D.game.entities[last ? @layers.keys.last : @layers.keys.first].y
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set the y coordinate of the text object.
|
40
|
+
# @param value [Integer] the y coordinate to set
|
41
|
+
def y=(value)
|
42
|
+
@layers.each_key do |key|
|
43
|
+
offset = if key == @layers.keys.first
|
44
|
+
0
|
45
|
+
else
|
46
|
+
previous = @layers.keys[@layers.keys.index(key) - 1]
|
47
|
+
OR2D.game.entities[previous].y + (OR2D.game.entities[previous].resource.size / OR2D.scale)
|
48
|
+
end
|
49
|
+
OR2D.game.entities[key].y = value + offset
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Set the x coordinate of the text object.
|
54
|
+
# @param value [Integer] the x coordinate to set
|
55
|
+
def x=(value)
|
56
|
+
@layers.each_key do |key|
|
57
|
+
OR2D.game.entities[key].x = value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Clear text for a specific layer or all layers
|
62
|
+
# @param layer_idx [Integer, Symbol] the index of the layer to clear or :all to clear all layers
|
63
|
+
def clear(layer_idx)
|
64
|
+
if layer_idx == :all
|
65
|
+
@layers.each do |id, properties|
|
66
|
+
properties[:buffer] = String.new
|
67
|
+
properties[:cursor] = 0
|
68
|
+
end
|
69
|
+
else
|
70
|
+
@layers[@layers.keys[layer_idx]][:buffer] = String.new
|
71
|
+
@layers[@layers.keys[layer_idx]][:cursor] = 0
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Add a new line to the text object. If there are no layers, the line will be added in place. If there are layers, the line will be added below the last layer.
|
76
|
+
# @param options [Hash] the options to create the layer with
|
77
|
+
def add_line(options = {})
|
78
|
+
@lines += 1
|
79
|
+
unless @layers.empty?
|
80
|
+
options.merge!(y: OR2D.game.entities[@layers.keys.last].y + (OR2D.game.entities[@layers.keys.last].resource.size + OR2D.scale))
|
81
|
+
end
|
82
|
+
add_layer(options)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Set the text for a specific layer.
|
86
|
+
# @param text [String] the text to set
|
87
|
+
# @param layer_idx [Integer, Symbol] the index of the layer to set the text for
|
88
|
+
def set_text(text, layer_idx)
|
89
|
+
@layers[@layers.keys[layer_idx]][:buffer] = text.slice(0, @limit)
|
90
|
+
@layers[@layers.keys[layer_idx]][:cursor] = 0
|
91
|
+
end
|
92
|
+
|
93
|
+
# Append text to a specific layer.
|
94
|
+
# @param text [String] the text to append
|
95
|
+
# @param layer_idx [Integer, Symbol] the index of the layer to append the text to
|
96
|
+
def append_text(text, layer_idx)
|
97
|
+
return if @layers[@layers.keys[layer_idx]][:buffer].length >= @limit
|
98
|
+
|
99
|
+
@layers[@layers.keys[layer_idx]][:buffer] += text
|
100
|
+
@layers[@layers.keys[layer_idx]][:buffer] = @layers[@layers.keys[layer_idx]][:buffer].slice(0, @limit)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Is the text object empty?
|
104
|
+
# @return [Boolean] whether the text object is empty
|
105
|
+
def empty?
|
106
|
+
@layers.empty?
|
107
|
+
end
|
108
|
+
|
109
|
+
# Update the text object. This works by updating the text for each layer one character at a time only on key frames determined by the update interval.
|
110
|
+
def update(force: false)
|
111
|
+
return unless force || OR2D.game.key_frame?(@update_interval)
|
112
|
+
|
113
|
+
@layers.each do |id, properties|
|
114
|
+
OR2D.game.entities[id].resource.text = properties[:buffer].slice(0, properties[:cursor])
|
115
|
+
properties[:cursor] += 1 if properties[:cursor] < properties[:buffer].length
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Show the text object. This works by showing each layer one at a time.
|
120
|
+
def show
|
121
|
+
@lines.times do |iteration|
|
122
|
+
if iteration == 1
|
123
|
+
OR2D.game.entities[@layers.keys[0]].show if @layers[@layers.keys[0]][:show]
|
124
|
+
elsif @layers[@layers.keys[iteration - 1]][:show]
|
125
|
+
OR2D.game.entities[@layers.keys[iteration - 1]].show
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Remove a layer from the text object. This works by removing the layer and adjusting the y coordinates of the remaining layers.
|
131
|
+
def remove_layer(id, adjust: true)
|
132
|
+
if adjust && @lines > 1
|
133
|
+
@lines.times do |index|
|
134
|
+
OR2D.game.entities[@layers.keys[index - 1]].y -= OR2D.game.entities[id].resource.size + OR2D.scale
|
135
|
+
end
|
136
|
+
end
|
137
|
+
@lines -= 1
|
138
|
+
super(id)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Hide the text object. This works by hiding each layer one at a time.
|
142
|
+
def hide
|
143
|
+
@lines.times do |index|
|
144
|
+
OR2D.game.entities[@layers.keys[index]].hide
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Destroy the text object. This works by destroying each layer one at a time.
|
149
|
+
# @note This will also destroy the text object.
|
150
|
+
def destroy
|
151
|
+
@lines.times do |index|
|
152
|
+
OR2D.game.entities[@layers.keys[index]].destroy
|
153
|
+
end
|
154
|
+
super
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def add_layer(options = {})
|
160
|
+
buffer = options[:text] || String.new
|
161
|
+
id = super(:text, options.merge(text: ''))
|
162
|
+
@layers[id][:buffer] = buffer
|
163
|
+
@layers[id][:cursor] = 0
|
164
|
+
show
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/lib/or2d/console.rb
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
module OR2D
|
2
|
+
# The Console class is used to construct Console objects that allow execution of Ruby code at runtime.
|
3
|
+
class Console
|
4
|
+
|
5
|
+
# @!attribute [r] display
|
6
|
+
# @return [OR2D::Composites::Text] the display of the Console object
|
7
|
+
attr_reader :display
|
8
|
+
|
9
|
+
# @!attribute [r] boundary
|
10
|
+
# @return [Ruby2D::Rectangle] the boundary of the Console object
|
11
|
+
attr_reader :boundary
|
12
|
+
|
13
|
+
# Constructs a new Console object.
|
14
|
+
# @param options [Hash] the options to create the console with
|
15
|
+
def initialize(options = {})
|
16
|
+
@boundary = Ruby2D::Rectangle.new(x: 0, y: -(OR2D.game.window.get(:height) / 2), z: 0,
|
17
|
+
width: OR2D.game.window.get(:width),
|
18
|
+
height: (OR2D.game.window.get(:height) / 2),
|
19
|
+
color: 'green', opacity: 0.25)
|
20
|
+
OR2D.game.window.add(@boundary)
|
21
|
+
@properties = { input_size: (8 * OR2D.scale), output_size: (4 * OR2D.scale), max_length: options[:max_length] || 24 }
|
22
|
+
@properties[:max_lines] = (@boundary.height / (@properties[:output_size] * OR2D.scale)).to_i - @properties[:output_size]
|
23
|
+
|
24
|
+
|
25
|
+
@prompt = options[:prompt] || '>> '
|
26
|
+
@buffer = String.new
|
27
|
+
@display = OR2D::Composites::Text.new
|
28
|
+
@display.add_line(text: 'OR2D Console', color: 'yellow', size: @properties[:output_size],
|
29
|
+
x: @boundary.x + 16, y: @boundary.y + (16 * OR2D.scale), z: @boundary.z + 1)
|
30
|
+
@input = OR2D::Entity.new(:text, { text: @prompt, color: 'white',
|
31
|
+
x: @boundary.x + 16, y: (@boundary.y + @boundary.height) - (16 * OR2D.scale),
|
32
|
+
z: @boundary.z + 1, size: @properties[:input_size],
|
33
|
+
show: true })
|
34
|
+
@state = State.new(:RETRACTED, false, false)
|
35
|
+
|
36
|
+
setup_events
|
37
|
+
end
|
38
|
+
|
39
|
+
# Add a line of text to the console.
|
40
|
+
def add_line(options)
|
41
|
+
@display.add_line(options.merge(size: @properties[:output_size]))
|
42
|
+
end
|
43
|
+
|
44
|
+
# Remove the console text displays from the game instance window.
|
45
|
+
def remove
|
46
|
+
@input.destroy
|
47
|
+
@display.destroy
|
48
|
+
OR2D.game.window.remove(@boundary)
|
49
|
+
@descriptors.each_value { |descriptor| OR2D.game.window.off(descriptor) }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Update the console.
|
53
|
+
def update
|
54
|
+
case @state.animation
|
55
|
+
when :RETRACTED
|
56
|
+
if @boundary.y >= -@boundary.height
|
57
|
+
@boundary.y -= 16
|
58
|
+
@input.y -= 16
|
59
|
+
@display.y -= 16 unless @display.empty?
|
60
|
+
else
|
61
|
+
@state.animation = :DRAWN
|
62
|
+
@state.drawn = false
|
63
|
+
end
|
64
|
+
when :PULL_DOWN
|
65
|
+
if @boundary.y <= -16 * OR2D.scale
|
66
|
+
@boundary.y += 16
|
67
|
+
@input.y += 16
|
68
|
+
@display.y += 16 unless @display.empty?
|
69
|
+
else
|
70
|
+
@state.animation = :DRAWN
|
71
|
+
@state.drawn = true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@display.update
|
76
|
+
@display.remove_layer(@display.layers.keys.first) if @display.layers.length > @properties[:max_lines]
|
77
|
+
@input.resource.text = @prompt + @buffer if @state.drawn
|
78
|
+
OR2D.game.window.add(@boundary)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Retracts the console from view.
|
82
|
+
def retract
|
83
|
+
@state.animation = :RETRACTED
|
84
|
+
end
|
85
|
+
|
86
|
+
# Pulls the console into view.
|
87
|
+
def pull_down
|
88
|
+
@state.animation = :PULL_DOWN
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# Contains the state of the console.
|
94
|
+
State = Struct.new(:animation, :drawn, :enabled) do
|
95
|
+
|
96
|
+
# Enables console input
|
97
|
+
def enable
|
98
|
+
self.enabled = true
|
99
|
+
end
|
100
|
+
|
101
|
+
# Disables console input
|
102
|
+
def disable
|
103
|
+
self.enabled = false
|
104
|
+
end
|
105
|
+
|
106
|
+
# Toggle console input
|
107
|
+
def toggle
|
108
|
+
self.enabled = !self.enabled
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def setup_events
|
113
|
+
@descriptors = {}
|
114
|
+
|
115
|
+
@descriptors[:std_input] = OR2D.game.window.on(:key_up) do |event|
|
116
|
+
case event.key
|
117
|
+
when '`'
|
118
|
+
@state.toggle
|
119
|
+
@state.enabled ? pull_down : retract
|
120
|
+
end
|
121
|
+
|
122
|
+
if @state.drawn &&
|
123
|
+
((!event.key.match?(/escape/) &&
|
124
|
+
!event.key.match?(/enter/) &&
|
125
|
+
!event.key.match?(/return/) &&
|
126
|
+
!event.key.match?(/backspace/) &&
|
127
|
+
!event.key.match?(/space/) &&
|
128
|
+
!event.key.match?(/shift/) &&
|
129
|
+
!event.key.match?(/control/) &&
|
130
|
+
!event.key.match?(/alt/) &&
|
131
|
+
!event.key.match?(/tab/) &&
|
132
|
+
!event.key.match?(/capslock/) &&
|
133
|
+
!event.key.match?(/pageup/) &&
|
134
|
+
!event.key.match?(/pagedown/) &&
|
135
|
+
!event.key.match?(/end/) &&
|
136
|
+
!event.key.match?(/home/) &&
|
137
|
+
!event.key.match?(/left/) &&
|
138
|
+
!event.key.match?(/up/) &&
|
139
|
+
!event.key.match?(/right/) &&
|
140
|
+
!event.key.match?(/down/) &&
|
141
|
+
!event.key.match?(/insert/) &&
|
142
|
+
!event.key.match?(/delete/) &&
|
143
|
+
!event.key.match?(/f1|f2|f3|f4|f5|f6|f7|f8|f9|f10/)) &&
|
144
|
+
event.key =~ /[a-zA-Z0-9]/ &&
|
145
|
+
(@properties[:max_length].zero? || @buffer.length < @properties[:max_length]))
|
146
|
+
@buffer.concat(OR2D.game.modifiers[:shift] ? event.key.capitalize : event.key)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
@descriptors[:special_input] = OR2D.game.window.on(:key_up) do |event|
|
151
|
+
case event.key
|
152
|
+
when /enter|return/
|
153
|
+
begin
|
154
|
+
output = instance_eval(@buffer)
|
155
|
+
rescue StandardError => e
|
156
|
+
output = e.message
|
157
|
+
puts e.backtrace
|
158
|
+
end
|
159
|
+
|
160
|
+
@display.add_line(text: "#{@buffer} #=> #{output}",
|
161
|
+
size: @properties[:output_size],
|
162
|
+
color: 'white',
|
163
|
+
show: true)
|
164
|
+
@buffer.clear
|
165
|
+
when /backspace/ then @buffer.slice!(-1)
|
166
|
+
when /delete/ then @buffer.clear
|
167
|
+
when /space/ then @buffer << ' '
|
168
|
+
when /-|minus|hyphen/ then @buffer << (OR2D.game.modifiers[:shift] ? '_' : '-')
|
169
|
+
when '\\' then @buffer << (OR2D.game.modifiers[:shift] ? '|' : '\\')
|
170
|
+
when '.' then @buffer << (OR2D.game.modifiers[:shift] ? '>' : '.')
|
171
|
+
when ',' then @buffer << (OR2D.game.modifiers[:shift] ? '<' : ',')
|
172
|
+
when ';' then @buffer << (OR2D.game.modifiers[:shift] ? ':' : ';')
|
173
|
+
when '{' then @buffer << (OR2D.game.modifiers[:shift] ? '[' : '{')
|
174
|
+
when '}' then @buffer << (OR2D.game.modifiers[:shift] ? ']' : '}')
|
175
|
+
when '[' then @buffer << (OR2D.game.modifiers[:shift] ? '{' : '[')
|
176
|
+
when ']' then @buffer << (OR2D.game.modifiers[:shift] ? '}' : ']')
|
177
|
+
when /=|equals/ then @buffer << (OR2D.game.modifiers[:shift] ? '+' : '=')
|
178
|
+
when "'" then @buffer << (OR2D.game.modifiers[:shift] ? '"' : "'")
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Numbers
|
183
|
+
@descriptors[:numeric_input] = OR2D.game.window.on(:key_up) do |event|
|
184
|
+
case event.key
|
185
|
+
when '1' then @buffer << (OR2D.game.modifiers[:shift] ? '!' : '1')
|
186
|
+
when '2' then @buffer << (OR2D.game.modifiers[:shift] ? '@' : '2')
|
187
|
+
when '3' then @buffer << (OR2D.game.modifiers[:shift] ? '#' : '3')
|
188
|
+
when '4' then @buffer << (OR2D.game.modifiers[:shift] ? '$' : '4')
|
189
|
+
when '5' then @buffer << (OR2D.game.modifiers[:shift] ? '%' : '5')
|
190
|
+
when '6' then @buffer << (OR2D.game.modifiers[:shift] ? '^' : '6')
|
191
|
+
when '7' then @buffer << (OR2D.game.modifiers[:shift] ? '&' : '7')
|
192
|
+
when '8' then @buffer << (OR2D.game.modifiers[:shift] ? '*' : '8')
|
193
|
+
when '9' then @buffer << (OR2D.game.modifiers[:shift] ? '(' : '9')
|
194
|
+
when '0' then @buffer << (OR2D.game.modifiers[:shift] ? ')' : '0')
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
data/lib/or2d/entity.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
module OR2D
|
2
|
+
|
3
|
+
# A Entity object represents a single entity in an OR2D instance. All entities have an ID, and a natural boundary
|
4
|
+
# that is provided by it's parent class (i.e. Ruby2D::Rectangle). It may also have a resource that can be rendered to
|
5
|
+
# the screen. It is recommended to use inheritance to create new entities.
|
6
|
+
class Entity < Ruby2D::Rectangle
|
7
|
+
include OR2D::Animations::EntityAnimations
|
8
|
+
|
9
|
+
# @!attribute [r] id
|
10
|
+
# @return [String] the entity's ID
|
11
|
+
attr_reader :id
|
12
|
+
|
13
|
+
# @!attribute [r] resource
|
14
|
+
# @return [Ruby2D::Image, Ruby2D::Sprite, Ruby2D::Text, Ruby2D::Triangle, Ruby2D::Quad, Ruby2D::Circle, Ruby2D::Square, Ruby2D::Line, Ruby2D::Rectangle] the entity's resource
|
15
|
+
attr_reader :resource
|
16
|
+
|
17
|
+
# Constructs a new Entity object.
|
18
|
+
# @param type [Symbol] the type of entity to create
|
19
|
+
# @param options [Hash] the options to create the entity with
|
20
|
+
def initialize(type, options = {})
|
21
|
+
super(x: options[:x] || 0,
|
22
|
+
y: options[:y] || 0,
|
23
|
+
width: options[:width].nil? ? 1 : options[:width] * OR2D.scale,
|
24
|
+
height: options[:height].nil? ? 1 : options[:height] * OR2D.scale,
|
25
|
+
opacity: options[:show_boundary] ? 0.55 : 0.0,
|
26
|
+
color: 'green')
|
27
|
+
@id = options[:id] || SecureRandom.uuid
|
28
|
+
@resource = options[:resource] || OR2D::Resource.create(type, options)
|
29
|
+
@width = @resource.width if @resource.respond_to?(:width)
|
30
|
+
@height = @resource.height if @resource.respond_to?(:height)
|
31
|
+
show if options[:show]
|
32
|
+
ensure
|
33
|
+
OR2D.game.add_entity(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Set the Entity x coordinate.
|
37
|
+
# @param x_coordinate [Integer] the x coordinate of the Entity on the screen
|
38
|
+
def x=(x_coordinate)
|
39
|
+
super(x_coordinate)
|
40
|
+
@resource.x = x_coordinate if @resource.respond_to?(:x=)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Set the Entity y coordinate.
|
44
|
+
# @param y_coordinate [Integer] the y coordinate of the Entity on the screen
|
45
|
+
def y=(y_coordinate)
|
46
|
+
super(y_coordinate)
|
47
|
+
@resource.y = y_coordinate if @resource.respond_to?(:y=)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Show the entity's boundary.
|
51
|
+
def toggle_boundary
|
52
|
+
@color.opacity = if @color.opacity <= 0.0
|
53
|
+
0.35
|
54
|
+
else
|
55
|
+
0.0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Show the entity on the game instance window.
|
60
|
+
def show
|
61
|
+
OR2D.game.window.add(self)
|
62
|
+
OR2D.game.window.add(@resource) if @resource
|
63
|
+
end
|
64
|
+
|
65
|
+
# Hide the entity from the game instance window.
|
66
|
+
def hide
|
67
|
+
OR2D.game.window.remove(self)
|
68
|
+
OR2D.game.window.remove(@resource) if @resource
|
69
|
+
end
|
70
|
+
|
71
|
+
# Remove the entity from the game instance window, and from the game instance's entity list.
|
72
|
+
def destroy
|
73
|
+
OR2D.game.window.remove(self)
|
74
|
+
OR2D.game.window.remove(@resource) if @resource
|
75
|
+
OR2D.game.remove_entity(@id)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|