minigl 1.3.7 → 1.3.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -4
- data/lib/minigl/forms.rb +694 -698
- data/lib/minigl/game_object.rb +250 -255
- data/lib/minigl/global.rb +470 -470
- data/lib/minigl/map.rb +153 -155
- data/lib/minigl/movement.rb +467 -467
- data/lib/minigl/text.rb +141 -141
- data/test/game_object_tests.rb +48 -48
- data/test/iso_game.rb +27 -27
- data/test/map_tests.rb +51 -51
- data/test/movement_tests.rb +78 -78
- data/test/res_tests.rb +15 -15
- metadata +2 -2
data/lib/minigl/map.rb
CHANGED
@@ -1,47 +1,45 @@
|
|
1
1
|
require_relative 'global'
|
2
2
|
|
3
3
|
module AGL
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# :nodoc:
|
9
|
-
|
10
|
-
# :nodoc:
|
11
|
-
MinusPiDiv4 = -Math::PI / 4
|
4
|
+
# This class provides easy control of a tile map, i.e., a map consisting of
|
5
|
+
# a grid of equally sized tiles. It also provides viewport control, through
|
6
|
+
# its camera property and methods.
|
7
|
+
class Map
|
8
|
+
Sqrt2Div2 = Math.sqrt(2) / 2 # :nodoc:
|
9
|
+
MinusPiDiv4 = -Math::PI / 4 # :nodoc:
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
# A Vector where x is the tile width and y is the tile height.
|
12
|
+
attr_reader :tile_size
|
15
13
|
|
16
|
-
|
17
|
-
|
14
|
+
# A Vector where x is the horizontal tile count and y the vertical count.
|
15
|
+
attr_reader :size
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
# A Rectangle representing the region of the map that is currently
|
18
|
+
# visible.
|
19
|
+
attr_reader :cam
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
21
|
+
# Creates a new map.
|
22
|
+
#
|
23
|
+
# Parameters:
|
24
|
+
# [t_w] The width of the tiles.
|
25
|
+
# [t_h] The height of the tiles.
|
26
|
+
# [t_x_count] The horizontal count of tiles in the map.
|
27
|
+
# [t_y_count] The vertical count of tiles in the map.
|
28
|
+
# [scr_w] Width of the viewport for the map.
|
29
|
+
# [scr_h] Height of the viewport for the map.
|
32
30
|
# [isometric] Whether to use a isometric map. By default, an ortogonal map
|
33
31
|
# is used.
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
32
|
+
# [limit_cam] Whether the camera should respect the bounds of the map
|
33
|
+
# (i.e., when given coordinates that would imply regions
|
34
|
+
# outside the map to appear in the screen, the camera would
|
35
|
+
# move to the nearest position where only the map shows up
|
36
|
+
# in the screen).
|
37
|
+
def initialize t_w, t_h, t_x_count, t_y_count, scr_w = 800, scr_h = 600, isometric = false, limit_cam = true
|
38
|
+
@tile_size = Vector.new t_w, t_h
|
39
|
+
@size = Vector.new t_x_count, t_y_count
|
40
|
+
@cam = Rectangle.new 0, 0, scr_w, scr_h
|
41
|
+
@limit_cam = limit_cam
|
42
|
+
@isometric = isometric
|
45
43
|
if isometric
|
46
44
|
initialize_isometric
|
47
45
|
elsif limit_cam
|
@@ -49,116 +47,115 @@ module AGL
|
|
49
47
|
@max_y = t_y_count * t_h - scr_h
|
50
48
|
end
|
51
49
|
set_camera 0, 0
|
52
|
-
|
50
|
+
end
|
53
51
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
52
|
+
# Returns a Vector with the total size of the map, in pixels (x for the
|
53
|
+
# width and y for the height).
|
54
|
+
def get_absolute_size
|
55
|
+
return Vector.new(@tile_size.x * @size.x, @tile_size.y * @size.y) unless @isometric
|
56
|
+
avg = (@size.x + @size.y) * 0.5
|
57
|
+
Vector.new (avg * @tile_size.x).to_i, (avg * @tile_size.y).to_i
|
58
|
+
end
|
61
59
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
60
|
+
# Returns a Vector with the coordinates of the center of the map.
|
61
|
+
def get_center
|
62
|
+
abs_size = get_absolute_size
|
63
|
+
Vector.new(abs_size.x * 0.5, abs_size.y * 0.5)
|
64
|
+
end
|
67
65
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
66
|
+
# Returns the position in the screen corresponding to the given tile
|
67
|
+
# indices.
|
68
|
+
#
|
69
|
+
# Parameters:
|
70
|
+
# [map_x] The index of the tile in the horizontal direction. It must be in
|
71
|
+
# the interval <code>0..t_x_count</code>.
|
72
|
+
# [map_y] The index of the tile in the vertical direction. It must be in
|
73
|
+
# the interval <code>0..t_y_count</code>.
|
74
|
+
def get_screen_pos map_x, map_y
|
75
|
+
return Vector.new(map_x * @tile_size.x - @cam.x, map_y * @tile_size.y - @cam.y) unless @isometric
|
76
|
+
Vector.new ((map_x - map_y - 1) * @tile_size.x * 0.5) - @cam.x + @x_offset,
|
77
|
+
((map_x + map_y) * @tile_size.y * 0.5) - @cam.y
|
78
|
+
end
|
81
79
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
80
|
+
# Returns the tile in the map that corresponds to the given position in
|
81
|
+
# the screen, as a Vector, where x is the horizontal index and y the
|
82
|
+
# vertical index.
|
83
|
+
#
|
84
|
+
# Parameters:
|
85
|
+
# [scr_x] The x-coordinate in the screen.
|
86
|
+
# [scr_y] The y-coordinate in the screen.
|
87
|
+
def get_map_pos scr_x, scr_y
|
88
|
+
return Vector.new((scr_x + @cam.x) / @tile_size.x, (scr_y + @cam.y) / @tile_size.y) unless @isometric
|
91
89
|
|
92
90
|
# Obtém a posição transformada para as coordenadas isométricas
|
93
|
-
|
94
|
-
|
95
|
-
# Depois divide pelo tamanho do quadrado para achar a posição da matriz
|
96
|
-
Vector.new((v.x * @inverse_square_size).to_i, (v.y * @inverse_square_size).to_i)
|
97
|
-
end
|
91
|
+
v = get_isometric_position scr_x, scr_y
|
98
92
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
# [v] A Vector representing the tile, with x as the horizontal index and
|
103
|
-
# y as the vertical index.
|
104
|
-
def is_in_map v
|
105
|
-
v.x >= 0 && v.y >= 0 && v.x < @size.x && v.y < @size.y
|
106
|
-
end
|
93
|
+
# Depois divide pelo tamanho do quadrado para achar a posição da matriz
|
94
|
+
Vector.new((v.x * @inverse_square_size).to_i, (v.y * @inverse_square_size).to_i)
|
95
|
+
end
|
107
96
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
@cam.y = cam_y
|
117
|
-
set_bounds
|
118
|
-
end
|
97
|
+
# Verifies whether a tile is inside the map.
|
98
|
+
#
|
99
|
+
# Parameters:
|
100
|
+
# [v] A Vector representing the tile, with x as the horizontal index and
|
101
|
+
# y as the vertical index.
|
102
|
+
def is_in_map v
|
103
|
+
v.x >= 0 && v.y >= 0 && v.x < @size.x && v.y < @size.y
|
104
|
+
end
|
119
105
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
end
|
106
|
+
# Sets the top left corner of the viewport to the given position of the
|
107
|
+
# map. Note that this is not the position in the screen.
|
108
|
+
#
|
109
|
+
# Parameters:
|
110
|
+
# [cam_x] The x-coordinate inside the map, in pixels (not a tile index).
|
111
|
+
# [cam_y] The y-coordinate inside the map, in pixels (not a tile index).
|
112
|
+
def set_camera cam_x, cam_y
|
113
|
+
@cam.x = cam_x
|
114
|
+
@cam.y = cam_y
|
115
|
+
set_bounds
|
116
|
+
end
|
132
117
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
for i in @min_vis_x..@max_vis_x
|
146
|
-
pos = get_screen_pos i, j
|
147
|
-
yield i, j, pos.x, pos.y
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
118
|
+
# Moves the viewport by the given amount of pixels.
|
119
|
+
#
|
120
|
+
# Parameters:
|
121
|
+
# [x] The amount of pixels to move horizontally. Negative values will
|
122
|
+
# cause the camera to move to the left.
|
123
|
+
# [y] The amount of pixels to move vertically. Negative values will cause
|
124
|
+
# the camera to move up.
|
125
|
+
def move_camera x, y
|
126
|
+
@cam.x += x
|
127
|
+
@cam.y += y
|
128
|
+
set_bounds
|
129
|
+
end
|
151
130
|
|
152
|
-
|
131
|
+
# Iterates through the currently visible tiles, providing the horizontal
|
132
|
+
# tile index, the vertical tile index, the x-coordinate (in pixels) and
|
133
|
+
# the y-coordinate (in pixels), of each tile, in that order, to a given
|
134
|
+
# block of code.
|
135
|
+
#
|
136
|
+
# Example:
|
137
|
+
#
|
138
|
+
# map.foreach do |i, j, x, y|
|
139
|
+
# draw_tile tiles[i][j], x, y
|
140
|
+
# end
|
141
|
+
def foreach
|
142
|
+
for j in @min_vis_y..@max_vis_y
|
143
|
+
for i in @min_vis_x..@max_vis_x
|
144
|
+
pos = get_screen_pos i, j
|
145
|
+
yield i, j, pos.x, pos.y
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
153
149
|
|
154
|
-
|
155
|
-
if @isometric
|
156
|
-
v1 = get_isometric_position(0, 0)
|
157
|
-
v2 = get_isometric_position(@cam.w - 1, 0)
|
158
|
-
v3 = get_isometric_position(@cam.w - 1, @cam.h - 1)
|
159
|
-
v4 = get_isometric_position(0, @cam.h - 1)
|
150
|
+
private
|
160
151
|
|
161
|
-
|
152
|
+
def set_bounds
|
153
|
+
if @limit_cam
|
154
|
+
if @isometric
|
155
|
+
v1 = get_isometric_position(0, 0)
|
156
|
+
v2 = get_isometric_position(@cam.w - 1, 0)
|
157
|
+
v3 = get_isometric_position(@cam.w - 1, @cam.h - 1)
|
158
|
+
v4 = get_isometric_position(0, @cam.h - 1)
|
162
159
|
if v1.x < -@max_offset
|
163
160
|
offset = -(v1.x + @max_offset)
|
164
161
|
@cam.x += offset * Sqrt2Div2
|
@@ -183,39 +180,40 @@ module AGL
|
|
183
180
|
@cam.y -= offset * Sqrt2Div2 / @tile_ratio
|
184
181
|
v4.y = @iso_abs_size.y + @max_offset
|
185
182
|
end
|
186
|
-
|
187
|
-
|
188
|
-
@min_vis_x = get_map_pos(0, 0).x
|
189
|
-
@min_vis_y = get_map_pos(@cam.w - 1, 0).y
|
190
|
-
@max_vis_x = get_map_pos(@cam.w - 1, @cam.h - 1).x
|
191
|
-
@max_vis_y = get_map_pos(0, @cam.h - 1).y
|
192
|
-
else
|
193
|
-
if @limit_cam
|
183
|
+
else
|
194
184
|
@cam.x = 0 if @cam.x < 0
|
195
185
|
@cam.x = @max_x if @cam.x > @max_x
|
196
186
|
@cam.y = 0 if @cam.y < 0
|
197
187
|
@cam.y = @max_y if @cam.y > @max_y
|
198
188
|
end
|
199
|
-
|
200
|
-
|
201
|
-
@max_vis_x = (@cam.x + @cam.w - 1) / @tile_size.x
|
202
|
-
@max_vis_y = (@cam.y + @cam.h - 1) / @tile_size.y
|
203
|
-
end
|
189
|
+
end
|
190
|
+
|
204
191
|
@cam.x = @cam.x.round
|
205
192
|
@cam.y = @cam.y.round
|
193
|
+
if @isometric
|
194
|
+
@min_vis_x = get_map_pos(0, 0).x
|
195
|
+
@min_vis_y = get_map_pos(@cam.w - 1, 0).y
|
196
|
+
@max_vis_x = get_map_pos(@cam.w - 1, @cam.h - 1).x
|
197
|
+
@max_vis_y = get_map_pos(0, @cam.h - 1).y
|
198
|
+
else
|
199
|
+
@min_vis_x = @cam.x / @tile_size.x
|
200
|
+
@min_vis_y = @cam.y / @tile_size.y
|
201
|
+
@max_vis_x = (@cam.x + @cam.w - 1) / @tile_size.x
|
202
|
+
@max_vis_y = (@cam.y + @cam.h - 1) / @tile_size.y
|
203
|
+
end
|
206
204
|
|
207
|
-
|
208
|
-
|
205
|
+
if @min_vis_y < 0; @min_vis_y = 0
|
206
|
+
elsif @min_vis_y > @size.y - 1; @min_vis_y = @size.y - 1; end
|
209
207
|
|
210
|
-
|
211
|
-
|
208
|
+
if @max_vis_y < 0; @max_vis_y = 0
|
209
|
+
elsif @max_vis_y > @size.y - 1; @max_vis_y = @size.y - 1; end
|
212
210
|
|
213
|
-
|
214
|
-
|
211
|
+
if @min_vis_x < 0; @min_vis_x = 0
|
212
|
+
elsif @min_vis_x > @size.x - 1; @min_vis_x = @size.x - 1; end
|
215
213
|
|
216
|
-
|
217
|
-
|
218
|
-
|
214
|
+
if @max_vis_x < 0; @max_vis_x = 0
|
215
|
+
elsif @max_vis_x > @size.x - 1; @max_vis_x = @size.x - 1; end
|
216
|
+
end
|
219
217
|
|
220
218
|
def initialize_isometric
|
221
219
|
@x_offset = (@size.y * 0.5 * @tile_size.x).round
|
@@ -254,5 +252,5 @@ module AGL
|
|
254
252
|
position.x -= @isometric_offset_x; position.y -= @isometric_offset_y
|
255
253
|
position
|
256
254
|
end
|
257
|
-
|
255
|
+
end
|
258
256
|
end
|
data/lib/minigl/movement.rb
CHANGED
@@ -1,471 +1,471 @@
|
|
1
1
|
require_relative 'global'
|
2
2
|
|
3
3
|
module AGL
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
4
|
+
# Represents an object with a rectangular bounding box and the +passable+
|
5
|
+
# property. It is the simplest structure that can be passed as an element of
|
6
|
+
# the +obst+ array parameter of the +move+ method.
|
7
|
+
class Block
|
8
|
+
# The x-coordinate of the top left corner of the bounding box.
|
9
|
+
attr_reader :x
|
10
|
+
|
11
|
+
# The y-coordinate of the top left corner of the bounding box.
|
12
|
+
attr_reader :y
|
13
|
+
|
14
|
+
# The width of the bounding box.
|
15
|
+
attr_reader :w
|
16
|
+
|
17
|
+
# The height of the bounding box.
|
18
|
+
attr_reader :h
|
19
|
+
|
20
|
+
# Whether a moving object can pass through this block when coming from
|
21
|
+
# below. This is a common feature of platforms in platform games.
|
22
|
+
attr_reader :passable
|
23
|
+
|
24
|
+
# Creates a new block.
|
25
|
+
#
|
26
|
+
# Parameters:
|
27
|
+
# [x] The x-coordinate of the top left corner of the bounding box.
|
28
|
+
# [y] The y-coordinate of the top left corner of the bounding box.
|
29
|
+
# [w] The width of the bounding box.
|
30
|
+
# [h] The height of the bounding box.
|
31
|
+
# [passable] Whether a moving object can pass through this block when
|
32
|
+
# coming from below. This is a common feature of platforms in platform
|
33
|
+
# games.
|
34
|
+
def initialize x, y, w, h, passable
|
35
|
+
@x = x; @y = y; @w = w; @h = h
|
36
|
+
@passable = passable
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the bounding box of this block as a Rectangle.
|
40
|
+
def bounds
|
41
|
+
Rectangle.new @x, @y, @w, @h
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Represents a ramp, i.e., an inclined structure which allows walking over
|
46
|
+
# it while automatically going up or down. It can be imagined as a right
|
47
|
+
# triangle, with a side parallel to the x axis and another one parallel to
|
48
|
+
# the y axis. You must provide instances of this class (or derived classes)
|
49
|
+
# to the +ramps+ array parameter of the +move+ method.
|
50
|
+
class Ramp
|
51
|
+
# The x-coordinate of the top left corner of a rectangle that completely
|
52
|
+
# (and precisely) encloses the ramp (thought of as a right triangle).
|
53
|
+
attr_reader :x
|
54
|
+
|
55
|
+
# The y-coordinate of the top left corner of the rectangle described in
|
56
|
+
# the +x+ attribute.
|
57
|
+
attr_reader :y
|
58
|
+
|
59
|
+
# The width of the ramp.
|
60
|
+
attr_reader :w
|
61
|
+
|
62
|
+
# The height of the ramp.
|
63
|
+
attr_reader :h
|
64
|
+
|
65
|
+
# Whether the height of the ramp increases from left to right (decreases
|
66
|
+
# from left to right when +false+).
|
67
|
+
attr_reader :left
|
68
|
+
|
69
|
+
# Creates a new ramp.
|
70
|
+
#
|
71
|
+
# Parameters:
|
72
|
+
# [x] The x-coordinate of the top left corner of a rectangle that
|
73
|
+
# completely (and precisely) encloses the ramp (thought of as a right
|
74
|
+
# triangle).
|
75
|
+
# [y] The y-coordinate of the top left corner of the rectangle described
|
76
|
+
# above.
|
77
|
+
# [w] The width of the ramp (which corresponds to the width of the
|
78
|
+
# rectangle described above).
|
79
|
+
# [h] The height of the ramp (which corresponds to the height of the
|
80
|
+
# rectangle described above, and to the difference between the lowest
|
81
|
+
# point of the ramp, where it usually meets the floor, and the
|
82
|
+
# highest).
|
83
|
+
# [left] Whether the height of the ramp increases from left to right. Use
|
84
|
+
# +false+ for a ramp that goes down from left to right.
|
85
|
+
def initialize x, y, w, h, left
|
86
|
+
@x = x
|
87
|
+
@y = y
|
88
|
+
@w = w
|
89
|
+
@h = h
|
90
|
+
@left = left
|
91
|
+
end
|
92
|
+
|
93
|
+
# Checks if an object is in contact with this ramp (standing over it).
|
94
|
+
#
|
95
|
+
# Parameters:
|
96
|
+
# [obj] The object to check contact with. It must have the +x+, +y+, +w+
|
97
|
+
# and +h+ accessible attributes determining its bounding box.
|
98
|
+
def contact? obj
|
99
|
+
obj.x.round(6) == get_x(obj).round(6) && obj.y.round(6) == get_y(obj).round(6)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Checks if an object is intersecting this ramp (inside the corresponding
|
103
|
+
# right triangle and at the floor level or above).
|
104
|
+
#
|
105
|
+
# Parameters:
|
106
|
+
# [obj] The object to check intersection with. It must have the +x+, +y+,
|
107
|
+
# +w+ and +h+ accessible attributes determining its bounding box.
|
108
|
+
def intersects obj
|
109
|
+
obj.x + obj.w > @x && obj.x < @x + @w && obj.y > get_y(obj) && obj.y <= @y + @h - obj.h
|
110
|
+
end
|
111
|
+
|
112
|
+
# :nodoc:
|
113
|
+
def can_collide? obj
|
114
|
+
@can_collide = (obj.speed.y >= 0 and not intersects(obj))
|
115
|
+
end
|
116
|
+
|
117
|
+
def check_intersection obj
|
118
|
+
if @can_collide and intersects obj
|
119
|
+
obj.y = get_y obj
|
120
|
+
obj.speed.y = 0
|
121
|
+
# a = @w / @h
|
122
|
+
# x = get_x(obj)
|
123
|
+
# y = get_y(obj)
|
124
|
+
# w = obj.x - x
|
125
|
+
# h = obj.y - y
|
126
|
+
# dx = w * h / (w * a + h)
|
127
|
+
# dy = dx * a
|
128
|
+
#
|
129
|
+
# obj.x -= dx
|
130
|
+
# obj.y -= dy
|
131
|
+
# obj.speed.x *= (@w / (@w + @h))
|
132
|
+
# obj.speed.y = 0
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def get_x obj
|
137
|
+
return @x + (1.0 * (@y + @h - obj.y - obj.h) * @w / @h) - obj.w if @left
|
138
|
+
@x + (1.0 * (obj.y + obj.h - @y) * @w / @h)
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_y obj
|
142
|
+
return @y - obj.h if @left && obj.x + obj.w > @x + @w
|
143
|
+
return @y + (1.0 * (@x + @w - obj.x - obj.w) * @h / @w) - obj.h if @left
|
144
|
+
return @y - obj.h if obj.x < @x
|
145
|
+
@y + (1.0 * (obj.x - @x) * @h / @w) - obj.h
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# This module provides objects with physical properties and methods for
|
150
|
+
# moving. It allows moving with or without collision checking (based on
|
151
|
+
# rectangular bounding boxes), including a method to behave as an elevator,
|
152
|
+
# affecting other objects' positions as it moves.
|
153
|
+
module Movement
|
154
|
+
# The mass of the object, in arbitrary units. The default value for
|
155
|
+
# GameObject instances, for example, is 1. The larger the mass (i.e., the
|
156
|
+
# heavier the object), the more intense the forces applied to the object
|
157
|
+
# have to be in order to move it.
|
158
|
+
attr_reader :mass
|
159
|
+
|
160
|
+
# A Vector with the current speed of the object (x: horizontal component,
|
161
|
+
# y: vertical component).
|
162
|
+
attr_reader :speed
|
163
|
+
|
164
|
+
# Width of the bounding box.
|
165
|
+
attr_reader :w
|
166
|
+
|
167
|
+
# Height of the bounding box.
|
168
|
+
attr_reader :h
|
169
|
+
|
170
|
+
# Whether a moving object can pass through this block when coming from
|
171
|
+
# below. This is a common feature of platforms in platform games.
|
172
|
+
attr_reader :passable
|
173
|
+
|
174
|
+
# The object that is making contact with this from above. If there's no
|
175
|
+
# contact, returns +nil+.
|
176
|
+
attr_reader :top
|
177
|
+
|
178
|
+
# The object that is making contact with this from below. If there's no
|
179
|
+
# contact, returns +nil+.
|
180
|
+
attr_reader :bottom
|
181
|
+
|
182
|
+
# The object that is making contact with this from the left. If there's no
|
183
|
+
# contact, returns +nil+.
|
184
|
+
attr_reader :left
|
185
|
+
|
186
|
+
# The object that is making contact with this from the right. If there's
|
187
|
+
# no contact, returns +nil+.
|
188
|
+
attr_reader :right
|
189
|
+
|
190
|
+
# The x-coordinate of the top left corner of the bounding box.
|
191
|
+
attr_accessor :x
|
192
|
+
|
193
|
+
# The y-coordinate of the top left corner of the bounding box.
|
194
|
+
attr_accessor :y
|
195
|
+
|
196
|
+
# A Vector with the horizontal and vertical components of a force that
|
197
|
+
# be applied in the next time +move+ is called.
|
198
|
+
attr_accessor :stored_forces
|
199
|
+
|
200
|
+
# Returns the bounding box as a Rectangle.
|
201
|
+
def bounds
|
202
|
+
Rectangle.new @x, @y, @w, @h
|
203
|
+
end
|
204
|
+
|
205
|
+
# Moves this object, based on the forces being applied to it, and
|
206
|
+
# performing collision checking.
|
207
|
+
#
|
208
|
+
# Parameters:
|
209
|
+
# [forces] A Vector where x is the horizontal component of the resulting
|
210
|
+
# force and y is the vertical component.
|
211
|
+
# [obst] An array of obstacles to be considered in the collision checking.
|
212
|
+
# Obstacles must be instances of Block (or derived classes), or
|
213
|
+
# objects that <code>include Movement</code>.
|
214
|
+
# [ramps] An array of ramps to be considered in the collision checking.
|
215
|
+
# Ramps must be instances of Ramp (or derived classes).
|
216
|
+
def move forces, obst, ramps
|
217
|
+
forces.x += Game.gravity.x; forces.y += Game.gravity.y
|
218
|
+
forces.x += @stored_forces.x; forces.y += @stored_forces.y
|
219
|
+
@stored_forces.x = @stored_forces.y = 0
|
220
|
+
|
221
|
+
# check_contact obst, ramps
|
222
|
+
forces.x = 0 if (forces.x < 0 and @left) or (forces.x > 0 and @right)
|
223
|
+
forces.y = 0 if (forces.y < 0 and @top) or (forces.y > 0 and @bottom)
|
224
|
+
|
225
|
+
@speed.x += forces.x / @mass; @speed.y += forces.y / @mass
|
226
|
+
@speed.x = 0 if @speed.x.abs < @min_speed.x
|
227
|
+
@speed.y = 0 if @speed.y.abs < @min_speed.y
|
228
|
+
@speed.x = (@speed.x <=> 0) * @max_speed.x if @speed.x.abs > @max_speed.x
|
229
|
+
@speed.y = (@speed.y <=> 0) * @max_speed.y if @speed.y.abs > @max_speed.y
|
230
|
+
|
231
|
+
ramps.each do |r|
|
232
|
+
r.can_collide? self
|
233
|
+
end
|
234
|
+
|
235
|
+
x = @speed.x < 0 ? @x + @speed.x : @x
|
236
|
+
y = @speed.y < 0 ? @y + @speed.y : @y
|
237
|
+
w = @w + (@speed.x < 0 ? -@speed.x : @speed.x)
|
238
|
+
h = @h + (@speed.y < 0 ? -@speed.y : @speed.y)
|
239
|
+
move_bounds = Rectangle.new x, y, w, h
|
240
|
+
coll_list = []
|
241
|
+
obst.each do |o|
|
242
|
+
coll_list << o if move_bounds.intersects o.bounds
|
243
|
+
end
|
244
|
+
|
245
|
+
if coll_list.length > 0
|
246
|
+
up = @speed.y < 0; rt = @speed.x > 0; dn = @speed.y > 0; lf = @speed.x < 0
|
247
|
+
if @speed.x == 0 || @speed.y == 0
|
248
|
+
# Ortogonal
|
249
|
+
if rt; x_lim = find_right_limit coll_list
|
250
|
+
elsif lf; x_lim = find_left_limit coll_list
|
251
|
+
elsif dn; y_lim = find_down_limit coll_list
|
252
|
+
elsif up; y_lim = find_up_limit coll_list
|
253
|
+
end
|
254
|
+
if rt && @x + @w + @speed.x > x_lim; @x = x_lim - @w; @speed.x = 0
|
255
|
+
elsif lf && @x + @speed.x < x_lim; @x = x_lim; @speed.x = 0
|
256
|
+
elsif dn && @y + @h + @speed.y > y_lim; @y = y_lim - @h; @speed.y = 0
|
257
|
+
elsif up && @y + @speed.y < y_lim; @y = y_lim; @speed.y = 0
|
258
|
+
end
|
259
|
+
else
|
260
|
+
# Diagonal
|
261
|
+
x_aim = @x + @speed.x + (rt ? @w : 0); x_lim_def = x_aim
|
262
|
+
y_aim = @y + @speed.y + (dn ? @h : 0); y_lim_def = y_aim
|
263
|
+
coll_list.each do |c|
|
264
|
+
if c.passable; x_lim = x_aim
|
265
|
+
elsif rt; x_lim = c.x
|
266
|
+
else; x_lim = c.x + c.w
|
267
|
+
end
|
268
|
+
if dn; y_lim = c.y
|
269
|
+
elsif c.passable; y_lim = y_aim
|
270
|
+
else; y_lim = c.y + c.h
|
271
|
+
end
|
272
|
+
|
273
|
+
if c.passable
|
274
|
+
y_lim_def = y_lim if dn && @y + @h <= y_lim && y_lim < y_lim_def
|
275
|
+
elsif (rt && @x + @w > x_lim) || (lf && @x < x_lim)
|
276
|
+
# Can't limit by x, will limit by y
|
277
|
+
y_lim_def = y_lim if (dn && y_lim < y_lim_def) || (up && y_lim > y_lim_def)
|
278
|
+
elsif (dn && @y + @h > y_lim) || (up && @y < y_lim)
|
279
|
+
# Can't limit by y, will limit by x
|
280
|
+
x_lim_def = x_lim if (rt && x_lim < x_lim_def) || (lf && x_lim > x_lim_def)
|
281
|
+
else
|
282
|
+
x_time = 1.0 * (x_lim - @x - (@speed.x < 0 ? 0 : @w)) / @speed.x
|
283
|
+
y_time = 1.0 * (y_lim - @y - (@speed.y < 0 ? 0 : @h)) / @speed.y
|
284
|
+
if x_time > y_time
|
285
|
+
# Will limit by x
|
286
|
+
x_lim_def = x_lim if (rt && x_lim < x_lim_def) || (lf && x_lim > x_lim_def)
|
287
|
+
elsif (dn && y_lim < y_lim_def) || (up && y_lim > y_lim_def)
|
288
|
+
y_lim_def = y_lim
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
if x_lim_def != x_aim
|
293
|
+
@speed.x = 0
|
294
|
+
if lf; @x = x_lim_def
|
295
|
+
else; @x = x_lim_def - @w
|
296
|
+
end
|
297
|
+
end
|
298
|
+
if y_lim_def != y_aim
|
299
|
+
@speed.y = 0
|
300
|
+
if up; @y = y_lim_def
|
301
|
+
else; @y = y_lim_def - @h
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
@x += @speed.x
|
307
|
+
@y += @speed.y
|
308
|
+
|
309
|
+
ramps.each do |r|
|
310
|
+
r.check_intersection self
|
311
|
+
end
|
312
|
+
check_contact obst, ramps
|
313
|
+
end
|
314
|
+
|
315
|
+
# Moves this object as an elevator (i.e., potentially carrying other
|
316
|
+
# objects) towards a given point.
|
317
|
+
#
|
318
|
+
# Parameters:
|
319
|
+
# [aim] A Vector specifying where the object will move to.
|
320
|
+
# [speed] The constant speed at which the object will move. This must be
|
321
|
+
# provided as a scalar, not a vector.
|
322
|
+
# [obstacles] An array of obstacles to be considered in the collision
|
323
|
+
# checking, and carried along when colliding from above.
|
324
|
+
# Obstacles must be instances of Block (or derived classes),
|
325
|
+
# or objects that <code>include Movement</code>.
|
326
|
+
def move_carrying aim, speed, obstacles
|
327
|
+
x_d = aim.x - @x; y_d = aim.y - @y
|
328
|
+
distance = Math.sqrt(x_d**2 + y_d**2)
|
329
|
+
@speed.x = 1.0 * x_d * speed / distance
|
330
|
+
@speed.y = 1.0 * y_d * speed / distance
|
331
|
+
|
332
|
+
x_aim = @x + @speed.x; y_aim = @y + @speed.y
|
333
|
+
passengers = []
|
334
|
+
obstacles.each do |o|
|
335
|
+
if @x + @w > o.x && o.x + o.w > @x
|
336
|
+
foot = o.y + o.h
|
337
|
+
if foot.round(6) == @y.round(6) || @speed.y < 0 && foot < @y && foot > y_aim
|
338
|
+
passengers << o
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
if @speed.x > 0 && x_aim >= aim.x || @speed.x < 0 && x_aim <= aim.x
|
344
|
+
passengers.each do |p| p.x += aim.x - @x end
|
345
|
+
@x = aim.x; @speed.x = 0
|
346
|
+
else
|
347
|
+
passengers.each do |p| p.x += @speed.x end
|
348
|
+
@x = x_aim
|
349
|
+
end
|
350
|
+
if @speed.y > 0 && y_aim >= aim.y || @speed.y < 0 && y_aim <= aim.y
|
351
|
+
@y = aim.y; @speed.y = 0
|
352
|
+
else
|
353
|
+
@y = y_aim
|
354
|
+
end
|
355
|
+
|
356
|
+
passengers.each do |p| p.y = @y - p.h end
|
357
|
+
end
|
358
|
+
|
359
|
+
# Moves this object, without performing any collision checking, towards
|
360
|
+
# the specified point.
|
361
|
+
#
|
362
|
+
# Parameters:
|
363
|
+
# [aim] A Vector specifying where the object will move to.
|
364
|
+
# [speed] The constant speed at which the object will move. This must be
|
365
|
+
# provided as a scalar, not a vector.
|
366
|
+
def move_free aim, speed
|
367
|
+
x_d = aim.x - @x; y_d = aim.y - @y
|
368
|
+
distance = Math.sqrt(x_d**2 + y_d**2)
|
369
|
+
@speed.x = 1.0 * x_d * speed / distance
|
370
|
+
@speed.y = 1.0 * y_d * speed / distance
|
371
|
+
|
372
|
+
if (@speed.x < 0 and @x + @speed.x <= aim.x) or (@speed.x >= 0 and @x + @speed.x >= aim.x)
|
373
|
+
@x = aim.x
|
374
|
+
@speed.x = 0
|
375
|
+
else
|
376
|
+
@x += @speed.x
|
377
|
+
end
|
378
|
+
|
379
|
+
if (@speed.y < 0 and @y + @speed.y <= aim.y) or (@speed.y >= 0 and @y + @speed.y >= aim.y)
|
380
|
+
@y = aim.y
|
381
|
+
@speed.y = 0
|
382
|
+
else
|
383
|
+
@y += @speed.y
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
# Causes the object to move in cycles across multiple given points (the
|
388
|
+
# method must be called repeatedly, and it returns the value that must be
|
389
|
+
# provided to +cur_point+ after the first call). If obstacles are
|
390
|
+
# provided, it will behave as an elevator (as in +move_carrying+).
|
391
|
+
#
|
392
|
+
# Parameters:
|
393
|
+
# [points] An array of Vectors representing the path that the object will
|
394
|
+
# perform.
|
395
|
+
# [cur_point] The index of the point in the path that the object is
|
396
|
+
# currently moving to. In the first call, it is a good idea to
|
397
|
+
# provide 0, while in the subsequent calls, you must provide
|
398
|
+
# the return value of this method.
|
399
|
+
# [speed] The constant speed at which the object will move. This must be
|
400
|
+
# provided as a scalar, not a vector.
|
401
|
+
# [obstacles] An array of obstacles to be considered in the collision
|
402
|
+
# checking, and carried along when colliding from above.
|
403
|
+
# Obstacles must be instances of Block (or derived classes),
|
404
|
+
# or objects that <code>include Movement</code>.
|
405
|
+
def cycle points, cur_point, speed, obstacles = nil
|
406
|
+
if obstacles
|
407
|
+
move_carrying points[cur_point], speed, obstacles
|
408
|
+
else
|
409
|
+
move_free points[cur_point], speed
|
410
|
+
end
|
411
|
+
if @speed.x == 0 and @speed.y == 0
|
412
|
+
if cur_point == points.length - 1; cur_point = 0
|
413
|
+
else; cur_point += 1; end
|
414
|
+
end
|
415
|
+
cur_point
|
416
|
+
end
|
417
|
+
|
418
|
+
private
|
419
|
+
|
420
|
+
def check_contact obst, ramps
|
421
|
+
@top = @bottom = @left = @right = nil
|
422
|
+
obst.each do |o|
|
423
|
+
x2 = @x + @w; y2 = @y + @h; x2o = o.x + o.w; y2o = o.y + o.h
|
424
|
+
@right = o if !o.passable && x2.round(6) == o.x.round(6) && y2 > o.y && @y < y2o
|
425
|
+
@left = o if !o.passable && @x.round(6) == x2o.round(6) && y2 > o.y && @y < y2o
|
426
|
+
@bottom = o if y2.round(6) == o.y.round(6) && x2 > o.x && @x < x2o
|
427
|
+
@top = o if !o.passable && @y.round(6) == y2o.round(6) && x2 > o.x && @x < x2o
|
428
|
+
end
|
429
|
+
if @bottom.nil?
|
430
|
+
ramps.each do |r|
|
431
|
+
if r.contact? self
|
432
|
+
@bottom = r
|
433
|
+
break
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
def find_right_limit coll_list
|
440
|
+
limit = @x + @w + @speed.x
|
441
|
+
coll_list.each do |c|
|
442
|
+
limit = c.x if !c.passable && c.x < limit
|
443
|
+
end
|
444
|
+
limit
|
445
|
+
end
|
446
|
+
|
447
|
+
def find_left_limit coll_list
|
448
|
+
limit = @x + @speed.x
|
449
|
+
coll_list.each do |c|
|
450
|
+
limit = c.x + c.w if !c.passable && c.x + c.w > limit
|
451
|
+
end
|
452
|
+
limit
|
453
|
+
end
|
454
|
+
|
455
|
+
def find_down_limit coll_list
|
456
|
+
limit = @y + @h + @speed.y
|
457
|
+
coll_list.each do |c|
|
458
|
+
limit = c.y if c.y < limit && c.y >= @y + @h
|
459
|
+
end
|
460
|
+
limit
|
461
|
+
end
|
462
|
+
|
463
|
+
def find_up_limit coll_list
|
464
|
+
limit = @y + @speed.y
|
465
|
+
coll_list.each do |c|
|
466
|
+
limit = c.y + c.h if !c.passable && c.y + c.h > limit
|
467
|
+
end
|
468
|
+
limit
|
469
|
+
end
|
470
|
+
end
|
471
471
|
end
|