fantasy 0.1.13 → 0.1.17
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +22 -1
- data/.yardopts +4 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +55 -0
- data/README.md +14 -6
- data/docs/Actor.html +2737 -0
- data/docs/Background.html +961 -0
- data/docs/Camera.html +791 -0
- data/docs/Clock.html +753 -0
- data/docs/Color.html +776 -0
- data/docs/Coordinates.html +730 -0
- data/docs/Cursor.html +752 -0
- data/docs/Disk.html +236 -0
- data/docs/Draggable.html +198 -0
- data/docs/Fantasy.html +121 -0
- data/docs/Game.html +904 -0
- data/docs/Global.html +2791 -0
- data/docs/Gravitier.html +179 -0
- data/docs/HudImage.html +979 -0
- data/docs/HudText.html +1151 -0
- data/docs/Image.html +506 -0
- data/docs/Jumper.html +189 -0
- data/docs/Mouse.html +226 -0
- data/docs/MoveByCursor.html +374 -0
- data/docs/MoveByDirection.html +179 -0
- data/docs/Mover.html +305 -0
- data/docs/Music.html +524 -0
- data/docs/Shape.html +1057 -0
- data/docs/Sound.html +374 -0
- data/docs/Tilemap.html +491 -0
- data/docs/Tween.html +186 -0
- data/docs/UserInputs.html +879 -0
- data/docs/Utils.html +345 -0
- data/docs/_index.html +346 -0
- data/docs/class_list.html +51 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +497 -0
- data/docs/file.CHANGELOG.html +121 -0
- data/docs/file.README.html +599 -0
- data/docs/file_list.html +61 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +599 -0
- data/docs/js/app.js +314 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +1931 -0
- data/docs/top-level-namespace.html +978 -0
- data/lib/fantasy/actor.rb +455 -123
- data/lib/fantasy/background.rb +109 -13
- data/lib/fantasy/base.rb +113 -1
- data/lib/fantasy/camera.rb +95 -11
- data/lib/fantasy/clock.rb +4 -2
- data/lib/fantasy/color.rb +158 -153
- data/lib/fantasy/coordinates.rb +5 -9
- data/lib/fantasy/cursor.rb +2 -1
- data/lib/fantasy/disk.rb +12 -8
- data/lib/fantasy/draggable.rb +22 -1
- data/lib/fantasy/global.rb +59 -31
- data/lib/fantasy/hud_image.rb +5 -3
- data/lib/fantasy/hud_text.rb +6 -2
- data/lib/fantasy/image.rb +12 -4
- data/lib/fantasy/includes/gravitier.rb +2 -0
- data/lib/fantasy/includes/jumper.rb +3 -2
- data/lib/fantasy/includes/log.rb +12 -0
- data/lib/fantasy/includes/move_by_cursors.rb +24 -15
- data/lib/fantasy/includes/move_by_direction.rb +2 -0
- data/lib/fantasy/includes/mover.rb +3 -0
- data/lib/fantasy/includes/user_inputs.rb +6 -0
- data/lib/fantasy/loop.rb +41 -44
- data/lib/fantasy/mouse.rb +2 -0
- data/lib/fantasy/music.rb +4 -2
- data/lib/fantasy/shape.rb +11 -2
- data/lib/fantasy/sound.rb +3 -1
- data/lib/fantasy/tilemap.rb +19 -13
- data/lib/fantasy/tween.rb +3 -1
- data/lib/fantasy/utils.rb +7 -13
- data/lib/fantasy/version.rb +1 -1
- data/lib/fantasy.rb +2 -0
- metadata +90 -4
- data/fantasy.gemspec +0 -40
- data/fonts/VT323-Regular.ttf +0 -0
data/lib/fantasy/actor.rb
CHANGED
@@ -1,3 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Represents one active entity in the game.
|
4
|
+
# An actor can be the Player sprite. Or one of the enemies. Or the bullet.
|
5
|
+
# An actor can also be a tree, or a wall
|
6
|
+
#
|
7
|
+
# @example Actor can be used directly
|
8
|
+
# player = Actor.new("warrior") # ./images/warrior.png
|
9
|
+
# player.position = Coordinates.new(100, 100)
|
10
|
+
# player.solid = true
|
11
|
+
# player.speed = 200
|
12
|
+
# player.layer = 1
|
13
|
+
# player.move_with_cursors
|
14
|
+
# player.collision_with = ["enemy", "bullets"] # default "all"
|
15
|
+
#
|
16
|
+
# player.on_collision do |other|
|
17
|
+
# if other.name == "enemy"
|
18
|
+
# player.destroy
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# player.on_after_move do
|
23
|
+
# if player.position.x > Global.screen_width
|
24
|
+
# player.position.x = Global.screen_width
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# if player.position.x < 0
|
28
|
+
# player.position.x = 0
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# @example Or in a subclass:
|
33
|
+
# class Player < Actor
|
34
|
+
# def initialize
|
35
|
+
# super("warrior") # ./images/warrior.png
|
36
|
+
# @position = Coordinates.new(100, 100)
|
37
|
+
# @solid = true
|
38
|
+
# @speed = 200
|
39
|
+
# @layer = 1
|
40
|
+
# @direction = Coordinates.zero
|
41
|
+
# @collision_with = ["enemy", "bullets"] # default "all"
|
42
|
+
# move_with_cursors
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# on_collision do |other|
|
46
|
+
# if other.name == "enemy"
|
47
|
+
# destroy
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# on_after_move do
|
52
|
+
# if @position.x > Global.screen_width
|
53
|
+
# @position.x = Global.screen_width
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# if @position.x < 0
|
57
|
+
# @position.x = 0
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
# end
|
1
61
|
class Actor
|
2
62
|
include MoveByCursor
|
3
63
|
include MoveByDirection
|
@@ -6,10 +66,173 @@ class Actor
|
|
6
66
|
include Jumper
|
7
67
|
include UserInputs
|
8
68
|
|
9
|
-
|
10
|
-
|
69
|
+
# Coordinates object where x and y represent the position of the Actor in the World (no necessarily in the Screen).
|
70
|
+
#
|
71
|
+
# Default `Coordinates.zero`.
|
72
|
+
#
|
73
|
+
# @return [Coordinates] the actual position
|
74
|
+
#
|
75
|
+
# @example Setting position
|
76
|
+
# actor = Actor.new("image")
|
77
|
+
# actor.position = Coordinates.new(10, 20)
|
78
|
+
# actor.position.x # => 10
|
79
|
+
#
|
80
|
+
# @example Modify position
|
81
|
+
# actor.position.x += 1
|
82
|
+
# actor.position.x # => 11
|
83
|
+
attr_accessor :position
|
84
|
+
|
85
|
+
# Controls the direction in which this Actor will move in the next frame.
|
86
|
+
#
|
87
|
+
# Default `Coordinates.zero`.
|
88
|
+
#
|
89
|
+
# @return [Coordinates] the actual direction
|
90
|
+
#
|
91
|
+
# @note The the pixels per second is represented by the `@speed` attribute
|
92
|
+
#
|
93
|
+
# @example Set direction
|
94
|
+
# actor = Actor.new("image")
|
95
|
+
# actor.direction = Coordinates.right
|
96
|
+
attr_accessor :direction
|
97
|
+
|
98
|
+
# Controls the pixels per second which this Actor will move in the next frame.
|
99
|
+
#
|
100
|
+
# Default `0`.
|
101
|
+
#
|
102
|
+
# @return [Float] the actual speed
|
103
|
+
#
|
104
|
+
# @note The the direction is represented by the `@direction` attribute
|
105
|
+
#
|
106
|
+
# @example Set speed
|
107
|
+
# actor = Actor.new("image")
|
108
|
+
# actor.speed = 10
|
109
|
+
attr_accessor :speed
|
110
|
+
|
111
|
+
# Controls impulse this Actor will receive when the (see #jump) is triggered.
|
112
|
+
#
|
113
|
+
# Default `0`.
|
114
|
+
#
|
115
|
+
# @return [Float] the actual jump_force
|
116
|
+
#
|
117
|
+
# @note The the direction will be `Coordinates.up`
|
118
|
+
#
|
119
|
+
# @example Set jump_force
|
120
|
+
# actor = Actor.new("image")
|
121
|
+
# actor.jump_force = 100
|
122
|
+
attr_accessor :jump_force
|
123
|
+
|
124
|
+
# Controls constant force this Actor will receive on each frame.
|
125
|
+
#
|
126
|
+
# Default `0`.
|
127
|
+
#
|
128
|
+
# @return [Float] the actual gravity
|
129
|
+
#
|
130
|
+
# @note The the direction will be `Coordinates.down`
|
131
|
+
#
|
132
|
+
# @example Set gravity
|
133
|
+
# actor = Actor.new("image")
|
134
|
+
# actor.gravity = 10
|
135
|
+
attr_accessor :gravity
|
136
|
+
|
137
|
+
# When `true` the Actor will cause and respond to collisions.
|
138
|
+
#
|
139
|
+
# When `false` the Actor won't cause neither respond to collisions.
|
140
|
+
#
|
141
|
+
# Default `true`.
|
142
|
+
#
|
143
|
+
# @return [Boolean] the actual solid value
|
144
|
+
#
|
145
|
+
# @param solid [true, false] only true or false
|
146
|
+
#
|
147
|
+
# @example Set solid
|
148
|
+
# actor = Actor.new("image")
|
149
|
+
# actor.solid = false
|
150
|
+
attr_accessor :solid
|
151
|
+
|
152
|
+
# The value to scale the image of the Actor when drawn.
|
153
|
+
# If the value is `2` the image will rendered at double of size.
|
154
|
+
# If the value is `0.5` the image will rendered at half of size.
|
155
|
+
#
|
156
|
+
# @note this value affects the attributes `width` and `height`
|
157
|
+
#
|
158
|
+
# Default `1`.
|
159
|
+
#
|
160
|
+
# @return [Float] the actual scale
|
161
|
+
#
|
162
|
+
# @example Set scale
|
163
|
+
# actor = Actor.new("image")
|
164
|
+
# actor.scale = 6
|
165
|
+
attr_accessor :scale
|
166
|
+
|
167
|
+
# The value to internal name of this Actor.
|
168
|
+
#
|
169
|
+
# It is useful for collision management for example.
|
170
|
+
#
|
171
|
+
# Default (same as `image_name`).
|
172
|
+
#
|
173
|
+
# @return [String] the actual name
|
174
|
+
#
|
175
|
+
# @example Set name
|
176
|
+
# actor = Actor.new("image")
|
177
|
+
# actor.name = "spaceship"
|
178
|
+
#
|
179
|
+
# @example Used in collision trigger
|
180
|
+
# actor = Actor.new("image")
|
181
|
+
# actor.on_collision do |other|
|
182
|
+
# if other.name == "enemy"
|
183
|
+
# # damage
|
184
|
+
# end
|
185
|
+
# end
|
186
|
+
#
|
187
|
+
# @example Used with `collision_with`
|
188
|
+
# actor = Actor.new("image")
|
189
|
+
# actor.collision_with = ["enemy", "bullet"]
|
190
|
+
attr_accessor :name
|
191
|
+
|
192
|
+
# In which layer the image of the Actor is rendered.
|
193
|
+
# Smaller numbers are rendered behind higher numbers.
|
194
|
+
#
|
195
|
+
# Default `0`.
|
196
|
+
#
|
197
|
+
# @return [Integer] the actual layer
|
198
|
+
#
|
199
|
+
# @example Set layer
|
200
|
+
# actor = Actor.new("image")
|
201
|
+
# actor.layer = -1
|
202
|
+
attr_accessor :layer
|
203
|
+
|
204
|
+
# Array of strings (or "all").
|
205
|
+
# Represents with which other solid Actors this Actor collide.
|
206
|
+
#
|
207
|
+
# Default `"all"`.
|
208
|
+
#
|
209
|
+
# @return [Array, String] the actual list of names of Actors to collide with
|
210
|
+
#
|
211
|
+
# @example Set with which other Actors this Actor is colliding:
|
212
|
+
# actor = Actor.new("image")
|
213
|
+
# actor.collision_with = ["enemy", "bullet"]
|
214
|
+
#
|
215
|
+
# @example Set this Actors collides with all other Actors
|
216
|
+
# actor = Actor.new("image")
|
217
|
+
# actor.collision_with = "all"
|
11
218
|
attr_accessor :collision_with
|
12
219
|
|
220
|
+
# Generate an Actor with all the default attribute values
|
221
|
+
# @example Generate an Actor
|
222
|
+
# actor = Actor.new("image")
|
223
|
+
# actor.position # => Coordinates.zero
|
224
|
+
# actor.direction # => Coordinates.zero
|
225
|
+
# actor.speed # => 0
|
226
|
+
# actor.scale # => 1
|
227
|
+
# actor.solid # => true
|
228
|
+
# actor.draggable_on_debug # => true
|
229
|
+
# actor.layer # => 0
|
230
|
+
# actor.gravity # => 0
|
231
|
+
# actor.jump_force # => 0
|
232
|
+
# actor.collision_with # => "all"
|
233
|
+
#
|
234
|
+
# @param image_name [string] the name of the image file from `./images/*`
|
235
|
+
# @return [Actor] the Actor
|
13
236
|
def initialize(image_name)
|
14
237
|
@image_name = image_name
|
15
238
|
@image = Image.new(image_name)
|
@@ -19,8 +242,7 @@ class Actor
|
|
19
242
|
@speed = 0
|
20
243
|
@scale = 1
|
21
244
|
|
22
|
-
@
|
23
|
-
@solid = false
|
245
|
+
@solid = true
|
24
246
|
@draggable_on_debug = true
|
25
247
|
@dragging = false
|
26
248
|
@dragging_offset = nil
|
@@ -40,59 +262,53 @@ class Actor
|
|
40
262
|
Global.actors << self
|
41
263
|
end
|
42
264
|
|
265
|
+
|
266
|
+
# Set a new image to the Actor.
|
267
|
+
# @param image_name [String] The image file from `./images/*`
|
268
|
+
#
|
269
|
+
# @example Set a new image
|
270
|
+
# actor = Actor.new("player_walk")
|
271
|
+
# actor.image_name = "player_jump"
|
43
272
|
def image=(image_name)
|
44
273
|
@image = Image.new(image_name)
|
45
274
|
end
|
46
275
|
|
276
|
+
# @return [Fixnum] the Actor width in pixels
|
47
277
|
def width
|
48
278
|
@image.width * @scale
|
49
279
|
end
|
50
280
|
|
281
|
+
# @return [Fixnum] the Actor height in pixels
|
51
282
|
def height
|
52
283
|
@image.height * @scale
|
53
284
|
end
|
54
285
|
|
286
|
+
# @return [Boolean] the value of `@solid`
|
287
|
+
def solid?
|
288
|
+
@solid
|
289
|
+
end
|
290
|
+
|
291
|
+
# @param value [Coordinates] set a new direction to the Actor.
|
292
|
+
# The vector is normalized
|
293
|
+
#
|
294
|
+
# @example Set a new direction
|
295
|
+
# actor = Actor.new("player_walking")
|
296
|
+
# actor.direction = Coordinates.up
|
55
297
|
def direction=(value)
|
56
298
|
@direction = value
|
57
299
|
@direction = @direction.normalize unless @direction.zero?
|
58
300
|
end
|
59
301
|
|
302
|
+
# @!visibility private
|
60
303
|
def draw
|
61
304
|
@image.draw(x: position_in_camera.x, y: position_in_camera.y, scale: @scale)
|
62
305
|
|
63
306
|
draw_debug if Global.debug
|
64
307
|
end
|
65
308
|
|
66
|
-
|
67
|
-
Utils.draw_frame(position_in_camera.x, position_in_camera.y, width, height, 1, Gosu::Color::RED) if solid
|
68
|
-
Global.pixel_fonts["medium"].draw_text("#{@position.x.floor},#{@position.y.floor}", position_in_camera.x, position_in_camera.y - 20, 1)
|
69
|
-
end
|
70
|
-
|
71
|
-
def position_in_camera
|
72
|
-
@position - Global.camera.position
|
73
|
-
end
|
74
|
-
|
75
|
-
# TODO: make this work optimized
|
76
|
-
# def position_top_left
|
77
|
-
# @position - position_delta
|
78
|
-
# end
|
79
|
-
|
80
|
-
# def position_delta
|
81
|
-
# case @alignment
|
82
|
-
# when "top-left"
|
83
|
-
# Coordinates.zero
|
84
|
-
# when "center"
|
85
|
-
# Coordinates.new(width/2, height/2)
|
86
|
-
# else
|
87
|
-
# raise "Actor.alignment value not valid '#{@alignment}'. Valid values: 'top-left, center'"
|
88
|
-
# end
|
89
|
-
# end
|
90
|
-
|
91
|
-
# TODO: I made more of this code while I was with Covid
|
92
|
-
# It looks horrible and it is crap
|
93
|
-
# I'll improve it some day :)
|
309
|
+
# @!visibility private
|
94
310
|
def move
|
95
|
-
mouse_position = Global.mouse_position +
|
311
|
+
mouse_position = Global.mouse_position + Camera.main.position
|
96
312
|
|
97
313
|
if @draggable_on_debug && Global.debug && !@dragging && Gosu.button_down?(Gosu::MS_LEFT) && Utils.collision_at?(self, mouse_position.x, mouse_position.y)
|
98
314
|
@dragging = true
|
@@ -126,28 +342,14 @@ class Actor
|
|
126
342
|
manage_collisions(last_position)
|
127
343
|
end
|
128
344
|
|
129
|
-
# # Jump moving
|
130
|
-
# unless @jump_force.zero?
|
131
|
-
# last_position = @position
|
132
|
-
# add_force_by_jump
|
133
|
-
# apply_forces(max_speed: @jump_speed || @jump_force)
|
134
|
-
|
135
|
-
# # Check collision after jump moving
|
136
|
-
# if @solid && @position != last_position
|
137
|
-
# if manage_collisions(last_position)
|
138
|
-
# @jumping = false
|
139
|
-
# end
|
140
|
-
# end
|
141
|
-
# end
|
142
|
-
|
143
345
|
# Gravity force
|
144
|
-
|
346
|
+
unless @gravity.zero?
|
145
347
|
add_force_by_gravity
|
146
348
|
end
|
147
349
|
|
148
350
|
# Apply forces
|
149
351
|
last_position = @position
|
150
|
-
apply_forces
|
352
|
+
apply_forces
|
151
353
|
|
152
354
|
# Check collision after gravity moving
|
153
355
|
if @solid && @position != last_position
|
@@ -159,145 +361,275 @@ class Actor
|
|
159
361
|
on_after_move_do
|
160
362
|
end
|
161
363
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
364
|
+
# Destroy this Actor is not longer, moved, or rendered, or cause any collision.
|
365
|
+
#
|
366
|
+
# @example Destroy an Actor
|
367
|
+
# actor = Actor.new("image")
|
368
|
+
# actor.destroy
|
369
|
+
def destroy
|
370
|
+
on_destroy_do
|
371
|
+
Global.actors.delete(self)
|
372
|
+
end
|
171
373
|
|
172
|
-
|
173
|
-
|
174
|
-
@velocity.y = 0
|
175
|
-
end
|
374
|
+
# rubocop:disable Metrics/MethodLength
|
375
|
+
# rubocop:disable Metrics/AbcSize
|
176
376
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
377
|
+
# @!visibility private
|
378
|
+
def clone
|
379
|
+
actor = self.class.new(@image_name)
|
380
|
+
actor.image_name = @image_name
|
381
|
+
actor.name = @name
|
382
|
+
actor.position = @position.clone
|
383
|
+
actor.direction = @direction.clone
|
181
384
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
# was_collision
|
385
|
+
actor.speed = @speed
|
386
|
+
actor.scale = @scale
|
387
|
+
actor.solid = @solid
|
388
|
+
actor.layer = @layer
|
389
|
+
actor.gravity = @gravity
|
390
|
+
actor.jump_force = @jump_force
|
391
|
+
actor.collision_with = @collision_with
|
190
392
|
|
191
|
-
|
192
|
-
|
393
|
+
actor.on_after_move_callback = @on_after_move_callback
|
394
|
+
actor.on_collision_callback = @on_collision_callback
|
395
|
+
actor.on_destroy_callback = @on_destroy_callback
|
396
|
+
actor.on_jumping_callback = @on_jumping_callback
|
397
|
+
actor.on_floor_callback = @on_floor_callback
|
193
398
|
|
194
|
-
|
195
|
-
|
399
|
+
actor.on_cursor_down_callback = @on_cursor_down_callback
|
400
|
+
actor.on_cursor_up_callback = @on_cursor_up_callback
|
401
|
+
actor.on_cursor_left_callback = @on_cursor_left_callback
|
402
|
+
actor.on_cursor_right_callback = @on_cursor_right_callback
|
403
|
+
actor.on_space_bar_callback = @on_space_bar_callback
|
404
|
+
actor.on_mouse_button_left_callback = @on_mouse_button_left_callback
|
196
405
|
|
197
|
-
|
198
|
-
end
|
406
|
+
actor.on_click_callback = @on_click_callback
|
199
407
|
|
200
|
-
|
201
|
-
@solid
|
408
|
+
actor
|
202
409
|
end
|
410
|
+
# rubocop:enable Metrics/AbcSize
|
411
|
+
# rubocop:enable Metrics/MethodLength
|
203
412
|
|
204
413
|
# Set callbacks
|
414
|
+
|
415
|
+
# The block to be executed after each frame
|
416
|
+
#
|
417
|
+
# @example Limit Actor movement horizontally
|
418
|
+
# actor = Actor.new("image")
|
419
|
+
# actor.on_after_move do
|
420
|
+
# if actor.position.x > 100
|
421
|
+
# actor.position.x = 100
|
422
|
+
# end
|
423
|
+
# end
|
205
424
|
def on_after_move(&block)
|
206
425
|
@on_after_move_callback = block
|
207
426
|
end
|
208
427
|
|
428
|
+
# The block to be executed when Actor collides with another Actor
|
429
|
+
#
|
430
|
+
# @example Collision detected with _"bullet"_
|
431
|
+
# actor = Actor.new("image")
|
432
|
+
# actor.on_collision do |other|
|
433
|
+
# if other.name == "bullet"
|
434
|
+
# actor.destroy
|
435
|
+
# end
|
436
|
+
# end
|
209
437
|
def on_collision(&block)
|
210
438
|
@on_collision_callback = block
|
211
439
|
end
|
212
440
|
|
441
|
+
# The block to be executed before the Actor is destroyed
|
442
|
+
#
|
443
|
+
# @example Executes when destroyed
|
444
|
+
# actor = Actor.new("image")
|
445
|
+
# actor.on_destroy do
|
446
|
+
# Sound.play("explosion")
|
447
|
+
# end
|
213
448
|
def on_destroy(&block)
|
214
449
|
@on_destroy_callback = block
|
215
450
|
end
|
216
451
|
|
452
|
+
# The block to be executed when the Actor starts jumping
|
453
|
+
#
|
454
|
+
# @example Change image when jumping
|
455
|
+
# actor = Actor.new("walk")
|
456
|
+
# actor.on_jumping do
|
457
|
+
# actor.image_name = "jump"
|
458
|
+
# end
|
217
459
|
def on_jumping(&block)
|
218
460
|
@on_jumping_callback = block
|
219
461
|
end
|
220
462
|
|
463
|
+
# The block to be executed when the Actor touches floor
|
464
|
+
#
|
465
|
+
# @example Change image when jumping
|
466
|
+
# actor = Actor.new("walk")
|
467
|
+
# actor.on_floor do
|
468
|
+
# actor.image_name = "land"
|
469
|
+
# Clock.new { actor.image_name = "walk" }.run_on(seconds: 0.8)
|
470
|
+
# end
|
221
471
|
def on_floor(&block)
|
222
472
|
@on_floor_callback = block
|
223
473
|
end
|
224
474
|
|
225
|
-
|
226
475
|
# Execute callbacks
|
476
|
+
|
477
|
+
# This method is triggered after each frame
|
478
|
+
#
|
479
|
+
# @example Limit Actor movement horizontally
|
480
|
+
# class Player < Actor
|
481
|
+
# def on_after_move_do
|
482
|
+
# if @position.x > 100
|
483
|
+
# @position.x = 100
|
484
|
+
# end
|
485
|
+
# end
|
486
|
+
# end
|
227
487
|
def on_after_move_do
|
228
488
|
instance_exec(&@on_after_move_callback) unless @on_after_move_callback.nil?
|
229
489
|
end
|
230
490
|
|
491
|
+
# This method is triggered when Actor collides with another Actor
|
492
|
+
#
|
493
|
+
# @example Limit Actor movement horizontally
|
494
|
+
# class Player < Actor
|
495
|
+
# def on_collision_do(other)
|
496
|
+
# if other.name == "bullet"
|
497
|
+
# destroy
|
498
|
+
# end
|
499
|
+
# end
|
500
|
+
# end
|
231
501
|
def on_collision_do(other)
|
232
502
|
instance_exec(other, &@on_collision_callback) unless @on_collision_callback.nil?
|
233
503
|
end
|
234
504
|
|
505
|
+
# This method is triggered before the Actor is destroyed
|
506
|
+
#
|
507
|
+
# @example Executes when destroyed
|
508
|
+
# class Player < Actor
|
509
|
+
# def on_destroy_do
|
510
|
+
# Sound.play("explosion")
|
511
|
+
# end
|
512
|
+
# end
|
235
513
|
def on_destroy_do
|
236
514
|
instance_exec(&@on_destroy_callback) unless @on_destroy_callback.nil?
|
237
515
|
end
|
238
516
|
|
517
|
+
# This method is triggered when the Actor starts jumping
|
518
|
+
#
|
519
|
+
# @example Change image when jumping
|
520
|
+
# class Player < Actor
|
521
|
+
# def on_jumping_do
|
522
|
+
# self.image_name = "jump"
|
523
|
+
# end
|
524
|
+
# end
|
239
525
|
def on_jumping_do
|
240
526
|
instance_exec(&@on_jumping_callback) unless @on_jumping_callback.nil?
|
241
527
|
end
|
242
528
|
|
529
|
+
# This method is triggered when the Actor touches floor
|
530
|
+
#
|
531
|
+
# @example Change image when jumping
|
532
|
+
# class Player < Actor
|
533
|
+
# def.on_floor_do
|
534
|
+
# self.image_name = "land"
|
535
|
+
# Clock.new { self.image_name = "walk" }.run_on(seconds: 0.8)
|
536
|
+
# end
|
537
|
+
# end
|
243
538
|
def on_floor_do
|
244
539
|
instance_exec(&@on_floor_callback) unless @on_floor_callback.nil?
|
245
540
|
end
|
246
541
|
|
247
542
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
543
|
+
protected
|
544
|
+
|
545
|
+
attr_accessor :image_name
|
546
|
+
|
547
|
+
# TODO: make this work optimized
|
548
|
+
# def position_top_left
|
549
|
+
# @position - position_delta
|
550
|
+
# end
|
551
|
+
|
552
|
+
# def position_delta
|
553
|
+
# case @alignment
|
554
|
+
# when "top-left"
|
555
|
+
# Coordinates.zero
|
556
|
+
# when "center"
|
557
|
+
# Coordinates.new(width/2, height/2)
|
558
|
+
# else
|
559
|
+
# raise "Actor.alignment value not valid '#{@alignment}'. Valid values: 'top-left, center'"
|
560
|
+
# end
|
561
|
+
# end
|
562
|
+
|
563
|
+
def draw_debug
|
564
|
+
Shape.rectangle(
|
565
|
+
position: position_in_camera,
|
566
|
+
width: width,
|
567
|
+
height: height,
|
568
|
+
color: Color.palette.transparent,
|
569
|
+
stroke_color: Color.palette.red,
|
570
|
+
stroke: 1
|
571
|
+
) if solid
|
572
|
+
|
573
|
+
Global.pixel_fonts["medium"].draw_text("#{@position.x.floor},#{@position.y.floor}", position_in_camera.x, position_in_camera.y - 20, 1)
|
257
574
|
end
|
258
575
|
|
259
|
-
def
|
260
|
-
|
261
|
-
Global.actors.delete(self)
|
576
|
+
def position_in_camera
|
577
|
+
@position - Camera.main.position
|
262
578
|
end
|
263
579
|
|
264
|
-
def
|
265
|
-
|
266
|
-
actor.image_name = @image_name
|
267
|
-
actor.name = @name
|
268
|
-
actor.position = @position.clone
|
269
|
-
actor.direction = @direction.clone
|
580
|
+
def manage_collisions(last_position)
|
581
|
+
@velocity ||= Coordinates.zero # In case it is not initialized yet
|
270
582
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
actor.solid = @solid
|
275
|
-
actor.layer = @layer
|
276
|
-
actor.gravity = @gravity
|
277
|
-
actor.jump_force = @jump_force
|
278
|
-
actor.collision_with = @collision_with
|
583
|
+
collisions.each do |other|
|
584
|
+
on_collision_do(other)
|
585
|
+
other.on_collision_do(self)
|
279
586
|
|
280
|
-
|
281
|
-
|
282
|
-
actor.on_destroy_callback = @on_destroy_callback
|
283
|
-
actor.on_jumping_callback = @on_jumping_callback
|
284
|
-
actor.on_floor_callback = @on_floor_callback
|
587
|
+
if other.position.y >= (last_position.y + height)
|
588
|
+
on_floor_do unless @on_floor
|
285
589
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
actor.on_space_bar_callback = @on_space_bar_callback
|
291
|
-
actor.on_mouse_button_left_callback = @on_mouse_button_left_callback
|
590
|
+
@on_floor = true
|
591
|
+
@jumping = false
|
592
|
+
@velocity.y = 0
|
593
|
+
end
|
292
594
|
|
293
|
-
|
595
|
+
if other.position.y + other.height <= last_position.y
|
596
|
+
@velocity.y = 0
|
597
|
+
end
|
598
|
+
end
|
294
599
|
|
295
|
-
|
600
|
+
# # Reset position pixel by pixel
|
601
|
+
# was_collision = false
|
602
|
+
# while collisions.any? && @position != last_position
|
603
|
+
# was_collision = true
|
604
|
+
# last_position_direction = last_position - @position
|
605
|
+
# @position += last_position_direction.normalize
|
606
|
+
# end
|
607
|
+
# was_collision
|
608
|
+
|
609
|
+
if collisions.any? # we don't cache collisions because position may be changed on collision callback
|
610
|
+
@position = last_position
|
611
|
+
|
612
|
+
return true
|
613
|
+
end
|
614
|
+
|
615
|
+
false
|
616
|
+
end
|
617
|
+
|
618
|
+
# rubocop:disable Style/Next
|
619
|
+
def collisions
|
620
|
+
Global.actors.reject { |e| e == self }.select(&:solid?).select do |other|
|
621
|
+
if(
|
622
|
+
(@collision_with == "all" || @collision_with.include?(other.name)) &&
|
623
|
+
(other.collision_with == "all" || other.collision_with.include?(name))
|
624
|
+
)
|
625
|
+
Utils.collision? self, other
|
626
|
+
end
|
627
|
+
end
|
296
628
|
end
|
629
|
+
# rubocop:enable Style/Next
|
297
630
|
|
298
631
|
protected
|
299
632
|
|
300
633
|
attr_accessor :on_after_move_callback, :on_collision_callback, :on_destroy_callback, :on_jumping_callback, :on_floor_callback
|
301
|
-
attr_accessor :on_cursor_down_callback, :on_cursor_up_callback, :on_cursor_left_callback, :on_cursor_right_callback, :on_space_bar_callback, :on_mouse_button_left_callback
|
302
634
|
attr_accessor :on_click_callback
|
303
635
|
end
|