or2d 0.0.0
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 +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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 69d868c6eb2d8bf4781708c14470be61e2b51081c6e4769005af19dfffdbe82d
|
4
|
+
data.tar.gz: 3427253c8d35fd728edc4b7a5c9841d8b0f58ea13b9b45ac59eea36596625d1e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 44d7d7cd85cf7896666e687600276d12f0e271919d84a796fec627db5e3184e7ffb9304bc7b69f0456a7df73e5a7e42660e3e8fde402ee972e2056a978b4246a
|
7
|
+
data.tar.gz: 83b07d35364f4fdeebef9a791cbe6d39b5ea36a956940c9291d00eb97537455fde9c3d2becb9b1fd17bb4714c774e9970e59ad14bd10e1458c449f4c3b9857a2
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module OR2D
|
2
|
+
# The Animation class represents a single animation. It is used to animate entities in the game.
|
3
|
+
class Animation
|
4
|
+
|
5
|
+
# @!attribute [r] playing
|
6
|
+
# @return [Boolean] whether or not the animation is currently playing
|
7
|
+
attr_accessor :playing
|
8
|
+
|
9
|
+
# @!attribute [r] target
|
10
|
+
# @return [Integer] the ID of the entity to animate
|
11
|
+
attr_reader :target
|
12
|
+
|
13
|
+
# @!attribute [r] cache
|
14
|
+
# @return [Hash] the cache of the animation
|
15
|
+
attr_reader :cache
|
16
|
+
|
17
|
+
# Constructs a new animation.
|
18
|
+
# @param entity_id [Integer] the ID of the entity to animate
|
19
|
+
# @param _ [Proc] the block to execute
|
20
|
+
def initialize(entity_id, &_)
|
21
|
+
@target = entity_id
|
22
|
+
@playing = true
|
23
|
+
@cache = {}
|
24
|
+
@worker = Fiber.new do |animation|
|
25
|
+
loop do
|
26
|
+
break unless playing?
|
27
|
+
|
28
|
+
block_given? && playing? ? yield(animation) : complete
|
29
|
+
rescue StandardError => e
|
30
|
+
puts "An error occurred while animating entity #{entity_id}: #{e.message}"
|
31
|
+
puts e.backtrace if OR2D.debug?
|
32
|
+
ensure
|
33
|
+
Fiber.yield if playing?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Advances a single frame of the animation.
|
39
|
+
def resume
|
40
|
+
@worker.resume(self) if playing?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Completes the animation.
|
44
|
+
def complete
|
45
|
+
@playing = false
|
46
|
+
end
|
47
|
+
|
48
|
+
# Is the animation complete?
|
49
|
+
# @return [Boolean] whether or not the animation is complete
|
50
|
+
def complete?
|
51
|
+
!@playing || @playing == false || !@worker.alive?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Is the animation playing?
|
55
|
+
# @return [Boolean] whether or not the animation is playing
|
56
|
+
def playing?
|
57
|
+
@playing == true && @worker.alive?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
module OR2D::Animations
|
2
|
+
|
3
|
+
# A module that provides functions for animating the layers of a Composite object.
|
4
|
+
module CompositeAnimations
|
5
|
+
|
6
|
+
# Fade the a single layer of a Composite object, or all layers if no target is specified.
|
7
|
+
# @param speed [Float] the speed at which to fade
|
8
|
+
# @param target [Symbol, Integer] the index of the layer to fade or :all to fade all layers
|
9
|
+
def fade(speed: nil, target: :all)
|
10
|
+
if target == :all
|
11
|
+
@layers.each_key do |layer|
|
12
|
+
OR2D.game.entities[layer].fade(speed: speed)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
OR2D.game.entities[@layers.keys[target]].fade(speed: speed)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Fade in a single layer of a Composite object, or all layers if no target is specified.
|
20
|
+
# @param speed [Float] the speed at which to fade in
|
21
|
+
# @param target [Symbol, Integer] the index of the layer to fade in or :all to fade in all layers
|
22
|
+
def fade_in(speed: nil, target: :all)
|
23
|
+
if target == :all
|
24
|
+
@layers.each_key do |layer|
|
25
|
+
OR2D.game.entities[layer].fade_in(speed: speed)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
OR2D.game.entities[@layers.keys[target]].fade_in(speed: speed)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Fade out a single layer of a Composite object, or all layers if no target is specified.
|
33
|
+
# @param speed [Float] the speed at which to fade out
|
34
|
+
# @param target [Symbol, Integer] the index of the layer to fade out or :all to fade out all layers
|
35
|
+
def fade_out(speed: nil, target: :all)
|
36
|
+
if target == :all
|
37
|
+
@layers.each_key do |layer|
|
38
|
+
OR2D.game.entities[layer].fade_out(speed: speed)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
OR2D.game.entities[@layers.keys[target]].fade_out(speed: speed)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Rotate a single layer of a Composite object, or all layers if no target is specified.
|
46
|
+
# @param speed [Float] the speed at which to rotate
|
47
|
+
# @param angle [Float] the angle at which to rotate
|
48
|
+
# @param clockwise [Boolean] whether to rotate clockwise or counter-clockwise
|
49
|
+
# @param target [Symbol, Integer] the index of the layer to rotate or :all to rotate all layers
|
50
|
+
def rotation(speed: 0.1, angle: 360, clockwise: true, target: :all)
|
51
|
+
if target == :all
|
52
|
+
@layers.each_key do |layer|
|
53
|
+
OR2D.game.entities[layer].rotation(speed: speed, angle: angle, clockwise: clockwise)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
OR2D.game.entities[@layers.keys[target]].rotation(speed: speed, angle: angle, clockwise: clockwise)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Grow a single layer of a Composite object, or all layers if no target is specified.
|
61
|
+
# @param factor [Float] the factor by which to grow
|
62
|
+
# @param delay [Integer] the delay before growing
|
63
|
+
# @param target [Symbol, Integer] the index of the layer to grow or :all to grow all layers
|
64
|
+
def grow(factor: 1.0, delay: 100, target: :all)
|
65
|
+
if target == :all
|
66
|
+
@layers.each_key do |layer|
|
67
|
+
OR2D.game.entities[layer].grow(factor: factor, delay: delay)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
OR2D.game.entities[@layers.keys[target]].grow(factor: factor, delay: delay)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Grow the text of a single layer of a Composite object, or all layers if no target is specified.
|
75
|
+
# @param factor [Float] the factor by which to grow the text
|
76
|
+
# @param delay [Integer] the delay before growing the text
|
77
|
+
# @param target [Symbol, Integer] the index of the layer to grow the text or :all to grow the text of all layers
|
78
|
+
def grow_text_composite(factor: nil, delay: nil, target: :all)
|
79
|
+
if target == :all
|
80
|
+
@layers.each_key do |layer|
|
81
|
+
OR2D.game.entities[layer].grow_text(factor: factor, delay: delay)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
OR2D.game.entities[@layers.keys[target]].grow_text(factor: factor, delay: delay)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Grow the entity of a single layer of a Composite object, or all layers if no target is specified.
|
89
|
+
# @param factor [Float] the factor by which to grow the entity
|
90
|
+
# @param delay [Integer] the delay before growing the entity
|
91
|
+
# @param target [Symbol, Integer] the index of the layer to grow the entity or :all to grow the entity of all layers
|
92
|
+
def grow_entity(factor: nil, delay: nil, target: :all)
|
93
|
+
if target == :all
|
94
|
+
@layers.each_key do |layer|
|
95
|
+
OR2D.game.entities[layer].grow_entity(factor: factor, delay: delay)
|
96
|
+
end
|
97
|
+
else
|
98
|
+
OR2D.game.entities[@layers.keys[target]].grow_entity(factor: factor, delay: delay)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Shrink a single layer of a Composite object, or all layers if no target is specified.
|
103
|
+
# @param factor [Float] the factor by which to shrink
|
104
|
+
# @param delay [Integer] the delay before shrinking
|
105
|
+
# @param target [Symbol, Integer] the index of the layer to shrink or :all to shrink all layers
|
106
|
+
def shrink(factor: 1.0, delay: 100, target: :all)
|
107
|
+
if target == :all
|
108
|
+
@layers.each_key do |layer|
|
109
|
+
OR2D.game.entities[layer].shrink(factor: factor, delay: delay)
|
110
|
+
end
|
111
|
+
else
|
112
|
+
OR2D.game.entities[@layers.keys[target]].shrink(factor: factor, delay: delay)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Shrink the text of a single layer of a Composite object, or all layers if no target is specified.
|
117
|
+
# @param factor [Float] the factor by which to shrink the text
|
118
|
+
# @param delay [Integer] the delay before shrinking the text
|
119
|
+
# @param target [Symbol, Integer] the index of the layer to shrink the text or :all to shrink the text of all layers
|
120
|
+
def shrink_text(factor: nil, delay: nil, target: :all)
|
121
|
+
if target == :all
|
122
|
+
@layers.each_key do |layer|
|
123
|
+
OR2D.game.entities[layer].shrink_text(factor: factor, delay: delay)
|
124
|
+
end
|
125
|
+
else
|
126
|
+
OR2D.game.entities[@layers.keys[target]].shrink_text(factor: factor, delay: delay)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Shrinks the entity of a single layer of a Composite object, or all layers if no target is specified.
|
131
|
+
# @param factor [Float] the factor by which to shrink the entity
|
132
|
+
# @param delay [Integer] the delay before shrinking the entity
|
133
|
+
# @param target [Symbol, Integer] the index of the layer to shrink the entity or :all to shrink the entity of all layers
|
134
|
+
def shrink_entity(factor: nil, delay: nil, target: nil)
|
135
|
+
if target == :all
|
136
|
+
@layers.each_key do |layer|
|
137
|
+
OR2D.game.entities[layer].shrink_entity(factor: factor, delay: delay)
|
138
|
+
end
|
139
|
+
else
|
140
|
+
OR2D.game.entities[@layers.keys[target]].shrink_entity(factor: factor, delay: delay)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Shake a single layer of a Composite object, or all layers if no target is specified.
|
145
|
+
# @param duration [Integer] the duration of the shake
|
146
|
+
# @param magnitude [Integer] the magnitude of the shake
|
147
|
+
# @param target [Symbol, Integer] the index of the layer to shake or :all to shake all layers
|
148
|
+
# @example Shake all layers of a Composite object
|
149
|
+
def shake(target: :all, duration: 100, magnitude: 10)
|
150
|
+
if target == :all
|
151
|
+
@layers.each_key do |layer|
|
152
|
+
OR2D.game.entities[layer].shake(duration: duration, magnitude: magnitude)
|
153
|
+
end
|
154
|
+
else
|
155
|
+
OR2D.game.entities[@layers.keys[target]].shake(duration: duration, magnitude: magnitude)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
module OR2D::Animations
|
2
|
+
# A module that contains methods for animating entities.
|
3
|
+
module EntityAnimations
|
4
|
+
# Fades an Animatable object in and out.
|
5
|
+
# @param speed [Float] the speed at which to fade the object in and out
|
6
|
+
# @param entity [OR2D::Entity] the entity to fade in and out
|
7
|
+
def fade(speed: 0.1, entity: self)
|
8
|
+
if entity.resource.color.opacity.zero? || entity.resource.color.opacity.negative?
|
9
|
+
fade_in(entity: entity, speed: speed)
|
10
|
+
else
|
11
|
+
fade_out(entity: entity, speed: speed)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Fades an Animatable object out.
|
16
|
+
# @param speed [Float] the speed at which to fade the object out
|
17
|
+
# @param entity [OR2D::Entity] the entity to fade out
|
18
|
+
def fade_out(speed: 0.1, entity: self)
|
19
|
+
OR2D.game.animate(entity.id) do |animation|
|
20
|
+
if entity.resource.color.opacity.zero? || entity.resource.color.opacity.negative?
|
21
|
+
animation.complete
|
22
|
+
else
|
23
|
+
entity.resource.color.opacity -= speed
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Fades an Animatable object in.
|
29
|
+
# @param speed [Float] the speed at which to fade the object in
|
30
|
+
# @param entity [OR2D::Entity] the entity to fade in
|
31
|
+
def fade_in(speed: 0.1, entity: self)
|
32
|
+
OR2D.game.animate(entity.id) do |animation|
|
33
|
+
if entity.resource.color.opacity >= 1.0
|
34
|
+
animation.complete
|
35
|
+
else
|
36
|
+
entity.resource.color.opacity += speed
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Rotates an Animatable object.
|
42
|
+
# @param speed [Float] the speed at which to rotate the object
|
43
|
+
# @param angle [Integer] the angle at which to stop rotating the object
|
44
|
+
# @param clockwise [Boolean] whether or not to rotate the object clockwise
|
45
|
+
# @param entity [OR2D::Entity] the entity to rotate
|
46
|
+
def rotation(speed: 1.0, angle: 360, clockwise: true, entity: self)
|
47
|
+
OR2D.game.animate(entity.id) do |animation|
|
48
|
+
if clockwise
|
49
|
+
entity.resource.rotate += speed
|
50
|
+
else
|
51
|
+
entity.resource.rotate -= speed
|
52
|
+
end
|
53
|
+
|
54
|
+
case angle
|
55
|
+
when Range then animation.complete if angle.include?(entity.resource.rotate)
|
56
|
+
when Integer then animation.complete if (entity.resource.rotate % angle).zero?
|
57
|
+
else rotation(speed: speed, clockwise: clockwise, entity: entity)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Grows an Animatable object.
|
63
|
+
# @param factor [Float] the factor at which to grow the object
|
64
|
+
# @param entity [OR2D::Entity] the entity to grow
|
65
|
+
# @param delay [Integer] the delay at which to grow the object
|
66
|
+
# @note Using this animation multiple times in conjunction with multiple `shrink` animations can end up preventing animations from completing, leaving the target Entity in a state where it is not animatable via growth or shrinkage.
|
67
|
+
def grow(factor: 1.0, delay: 100, entity: self)
|
68
|
+
if entity.resource.is_a?(Ruby2D::Text)
|
69
|
+
grow_text(factor: factor, delay: delay, entity: entity)
|
70
|
+
else
|
71
|
+
grow_entity(factor: factor, delay: delay, entity: entity)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Grows an Animatable Entity object. This is accomplished by changing the width and height of the Entity.
|
76
|
+
# @param factor [Float] the factor at which to grow the object
|
77
|
+
# @param entity [OR2D::Entity] the entity to grow
|
78
|
+
# @param delay [Integer] the delay at which to grow the object
|
79
|
+
# @note Using this animation multiple times in conjunction with multiple `shrink` animations can end up preventing animations from completing, leaving the target Entity in a state where it is not animatable via growth or shrinkage.
|
80
|
+
def grow_entity(factor: 1.0, delay: 100, entity: self)
|
81
|
+
OR2D.game.animate(entity.id) do |animation|
|
82
|
+
animation.cache[:delay] ||= delay
|
83
|
+
animation.cache[:end_width] ||= entity.resource.width + (entity.resource.width * factor)
|
84
|
+
animation.cache[:end_height] ||= entity.resource.height + (entity.resource.height * factor)
|
85
|
+
animation.cache[:increment_width] ||= ((animation.cache[:end_width] - entity.resource.width) / animation.cache[:delay]).round(3)
|
86
|
+
animation.cache[:increment_height] ||= ((animation.cache[:end_height] - entity.resource.height) / animation.cache[:delay]).round(3)
|
87
|
+
|
88
|
+
if animation.cache[:delay].positive?
|
89
|
+
if entity.resource.width >= animation.cache[:end_width] &&
|
90
|
+
entity.resource.height >= animation.cache[:end_height]
|
91
|
+
animation.complete
|
92
|
+
else
|
93
|
+
entity.resource.width += animation.cache[:increment_width] if entity.resource.width != animation.cache[:end_width]
|
94
|
+
entity.resource.height += animation.cache[:increment_height] if entity.resource.height != animation.cache[:end_height]
|
95
|
+
end
|
96
|
+
else
|
97
|
+
entity.resource.width = animation.cache[:end_width]
|
98
|
+
entity.resource.height = animation.cache[:end_height]
|
99
|
+
animation.complete
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Grows an Animatable Text object. This is accomplished by changing the size of the Text.
|
105
|
+
# @param factor [Float] the factor at which to grow the object
|
106
|
+
# @param entity [OR2D::Entity] the entity to grow
|
107
|
+
# @param delay [Integer] the delay at which to grow the object
|
108
|
+
# @note Using this animation multiple times in conjunction with multiple `shrink_text` animations can end up preventing animations from completing, leaving the target Entity in a state where it is not animatable via growth or shrinkage.
|
109
|
+
def grow_text(factor: 1.0, delay: 100, entity: self)
|
110
|
+
OR2D.game.animate(entity.id) do |animation|
|
111
|
+
animation.cache[:end_size] ||= entity.resource.size + (entity.resource.size * factor)
|
112
|
+
animation.cache[:delay] ||= delay
|
113
|
+
animation.cache[:increment] ||= ((animation.cache[:end_size] - entity.resource.size) / animation.cache[:delay]).round(3)
|
114
|
+
|
115
|
+
|
116
|
+
if animation.cache[:delay].positive?
|
117
|
+
if entity.resource.size >= animation.cache[:end_size]
|
118
|
+
animation.complete
|
119
|
+
else
|
120
|
+
entity.resource.size += animation.cache[:increment]
|
121
|
+
end
|
122
|
+
else
|
123
|
+
entity.resource.size = animation.cache[:end_size]
|
124
|
+
animation.complete
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Shrinks an Animatable object.
|
130
|
+
# @param factor [Float] the factor at which to shrink the object
|
131
|
+
# @param entity [OR2D::Entity] the entity to shrink
|
132
|
+
# @param delay [Integer] the delay at which to shrink the object
|
133
|
+
# @note Using this animation multiple times in conjunction with multiple `grow` animations can end up preventing animations from completing, leaving the target Entity in a state where it is not animatable via growth or shrinkage.
|
134
|
+
def shrink(factor: 1.0, delay: 100, entity: self)
|
135
|
+
if entity.resource.is_a?(Ruby2D::Text)
|
136
|
+
shrink_text(factor: factor, delay: delay, entity: entity)
|
137
|
+
else
|
138
|
+
shrink_entity(factor: factor, delay: delay, entity: entity)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Shrinks an Animatable Entity object. This is accomplished by changing the width and height of the Entity.
|
143
|
+
# @note Using this animation multiple times in conjunction with multiple `grow_entity` animations can end up preventing animations from completing, leaving the target Entity in a state where it is not animatable via growth or shrinkage.
|
144
|
+
# @param factor [Float] the factor at which to shrink the object
|
145
|
+
# @param entity [OR2D::Entity] the entity to shrink
|
146
|
+
def shrink_entity(factor: 1.0, delay: 100, entity: self)
|
147
|
+
OR2D.game.animate(entity.id) do |animation|
|
148
|
+
animation.cache[:delay] ||= delay
|
149
|
+
animation.cache[:end_width] ||= entity.resource.width - (entity.resource.width * factor)
|
150
|
+
animation.cache[:end_height] ||= entity.resource.height - (entity.resource.height * factor)
|
151
|
+
animation.cache[:increment_width] ||= ((entity.resource.width - animation.cache[:end_width]) / delay).round(3)
|
152
|
+
animation.cache[:increment_height] ||= ((entity.resource.height - animation.cache[:end_height]) / delay).round(3)
|
153
|
+
|
154
|
+
|
155
|
+
if animation.cache[:delay].positive?
|
156
|
+
if entity.resource.width <= animation.cache[:end_width] &&
|
157
|
+
entity.resource.height <= animation.cache[:end_height]
|
158
|
+
animation.complete
|
159
|
+
else
|
160
|
+
entity.resource.width -= animation.cache[:increment_width] if entity.resource.width != animation.cache[:end_width]
|
161
|
+
entity.resource.height -= animation.cache[:increment_height] if entity.resource.height != animation.cache[:end_height]
|
162
|
+
end
|
163
|
+
else
|
164
|
+
entity.resource.width = animation.cache[:end_width]
|
165
|
+
entity.resource.height = animation.cache[:end_height]
|
166
|
+
animation.complete
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
# Shrinks an Animatable shape object. This is accomplished by changing the size of the text.
|
173
|
+
# @note Using this animation multiple times in conjunction with multiple `grow_text` animations can end up preventing animations from completing, leaving the target Entity in a state where it is not animatable via growth or shrinkage.
|
174
|
+
# @param factor [Float] the factor at which to shrink the object
|
175
|
+
# @param entity [OR2D::Entity] the entity to shrink
|
176
|
+
def shrink_text(factor: 1.0, delay: 100, entity: self)
|
177
|
+
OR2D.game.animate(entity.id) do |animation|
|
178
|
+
animation.cache[:end_size] ||= entity.resource.size - (entity.resource.size * factor)
|
179
|
+
animation.cache[:delay] ||= delay
|
180
|
+
animation.cache[:increment] ||= ((entity.resource.size - animation.cache[:end_size]) / animation.cache[:delay]).round(3)
|
181
|
+
|
182
|
+
if animation.cache[:delay].positive?
|
183
|
+
if entity.resource.size <= animation.cache[:end_size]
|
184
|
+
animation.complete
|
185
|
+
else
|
186
|
+
entity.resource.size -= animation.cache[:increment]
|
187
|
+
animation.cache[:delay] -= 1
|
188
|
+
end
|
189
|
+
else
|
190
|
+
entity.resource.size = animation.cache[:end_size]
|
191
|
+
animation.complete
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Shakes an Animatable object. This is accomplished by changing the x and y coordinates of the object.
|
197
|
+
# @param duration [Integer] the duration of the shake
|
198
|
+
# @param magnitude [Integer] the magnitude of the shake
|
199
|
+
# @param entity [OR2D::Entity] the entity to shake
|
200
|
+
def shake(duration: 100, magnitude: 10, entity: self)
|
201
|
+
OR2D.game.animate(entity.id) do |animation|
|
202
|
+
animation.cache[:duration] ||= duration
|
203
|
+
animation.cache[:magnitude] ||= magnitude
|
204
|
+
animation.cache[:x] ||= entity.x
|
205
|
+
animation.cache[:y] ||= entity.y
|
206
|
+
animation.cache[:increment] ||= ((animation.cache[:magnitude] / animation.cache[:duration]) * 0.001).round(3)
|
207
|
+
jitter = rand(-animation.cache[:magnitude]..animation.cache[:magnitude])
|
208
|
+
if animation.cache[:duration].positive?
|
209
|
+
entity.x = animation.cache[:x] + animation.cache[:magnitude] + jitter
|
210
|
+
entity.y = animation.cache[:y] + animation.cache[:magnitude] + jitter
|
211
|
+
animation.cache[:duration] -= 1
|
212
|
+
animation.cache[:magnitude] -= animation.cache[:increment]
|
213
|
+
else
|
214
|
+
entity.x = animation.cache[:x]
|
215
|
+
entity.y = animation.cache[:y]
|
216
|
+
animation.complete
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module OR2D
|
2
|
+
# A Composite object behaves like a collection of Entity objects.
|
3
|
+
class Composite
|
4
|
+
|
5
|
+
# @!attribute [r] layers
|
6
|
+
# @return [Hash] the layers of the Composite object
|
7
|
+
attr_reader :layers
|
8
|
+
|
9
|
+
# @!attribute [r] id
|
10
|
+
# @return [String] the identifier of the Composite object
|
11
|
+
attr_reader :id
|
12
|
+
|
13
|
+
# Constructs a new Composite object.
|
14
|
+
def initialize(id = "Composite_#{SecureRandom.uuid}")
|
15
|
+
@id = id
|
16
|
+
@layers = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Add a layer to the Composite object.
|
20
|
+
# @param type [Symbol] the type of layer to add
|
21
|
+
# @param options [Hash] the options used to construct the layer
|
22
|
+
# @param entity [OR2D::Entity] an optional Entity object to add if the layer type is :entity
|
23
|
+
def add_layer(type, options, entity: nil)
|
24
|
+
entity = if type == :entity
|
25
|
+
entity
|
26
|
+
else
|
27
|
+
OR2D::Entity.new(type, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
@layers[entity.id] = { show: options[:show].nil? ? true : options[:show] }
|
31
|
+
entity.id
|
32
|
+
end
|
33
|
+
|
34
|
+
# Remove a layer from the Composite object.
|
35
|
+
# @param id [String] the id of the Entity object to remove
|
36
|
+
def remove_layer(id)
|
37
|
+
@layers.delete(id)
|
38
|
+
OR2D.game.entities[id]&.destroy
|
39
|
+
OR2D.game.remove_entity(id)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Show the Composite object.
|
43
|
+
def show
|
44
|
+
@layers.each do |id, properties|
|
45
|
+
OR2D.game.entities[id].show if properties[:show]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Hide the Composite object.
|
50
|
+
def hide
|
51
|
+
@layers.each_key do |id|
|
52
|
+
OR2D.game.entities[id].hide
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Toggle the visibility of a specific layer.
|
57
|
+
# @param id [String] the id of the layer to toggle
|
58
|
+
def toggle(id)
|
59
|
+
@layers[id][:show] = !@layers[id][:show]
|
60
|
+
@layers[id][:show] ? OR2D.game.entities[id].show : OR2D.game.entities[id].hide
|
61
|
+
end
|
62
|
+
|
63
|
+
# Destroys the Composite object and all of its Entity objects.
|
64
|
+
def destroy
|
65
|
+
@layers.each_key do |id|
|
66
|
+
next if OR2D.game.entities[id].nil?
|
67
|
+
|
68
|
+
OR2D.game.entities[id].destroy
|
69
|
+
OR2D.game.remove_entity(id)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module OR2D::Composites
|
2
|
+
# The Composite Projectile class is used to create a composite projectile object.
|
3
|
+
class Projectile < OR2D::Composite
|
4
|
+
|
5
|
+
# Construct a new Projectile object.
|
6
|
+
# @param options [Hash] the options used to construct the Projectile object
|
7
|
+
# @option options [Hash] :asset the options used to construct the Asset object
|
8
|
+
# @option options [Float] :angle the angle of the Projectile object
|
9
|
+
# @option options [Hash] :direction the direction of the Projectile object
|
10
|
+
# @option options [Float] :radius the radius of the Projectile object
|
11
|
+
# @option options [Float] :velocity the velocity of the Projectile object
|
12
|
+
# @option options [Float] :time_step the time step of the Projectile object
|
13
|
+
# @option options [Float] :stepping the time step of the Projectile object
|
14
|
+
# @option options [Array] :gravity_points the gravity points of the Projectile object
|
15
|
+
def initialize(options)
|
16
|
+
super(options[:id] || "ProjectileComposite_#{SecureRandom.uuid}")
|
17
|
+
@asset_id = add_layer(options[:asset][:type], options[:asset][:options].merge(show: true)) if options.key?(:asset)
|
18
|
+
@angle = options[:angle] || 45
|
19
|
+
@direction = { x: Math.cos(@angle * Math::PI / 180),
|
20
|
+
y: Math.sin(@angle * Math::PI / 180) }
|
21
|
+
@radius = options[:radius] || 360
|
22
|
+
@velocity = options[:velocity] || 15
|
23
|
+
@velocity_y = @velocity * @direction[:y]
|
24
|
+
@time_step = options[:time_step] || options[:stepping] || 0.1
|
25
|
+
@elapsed = 0
|
26
|
+
@points = { line: {}, gravity: options[:gravity_points] || [] }
|
27
|
+
@gravity = @points[:gravity].first[:value] || 0
|
28
|
+
end
|
29
|
+
|
30
|
+
# Update the Projectile object.
|
31
|
+
def update
|
32
|
+
@elapsed += @time_step
|
33
|
+
update_gravity
|
34
|
+
|
35
|
+
@layers.each_key do |id|
|
36
|
+
OR2D.game.entities[id].x += Math.cos(@angle * Math::PI / 180) * @velocity * @direction[:x] * @time_step
|
37
|
+
OR2D.game.entities[id].y -= Math.sin(@angle * Math::PI / 180) * @velocity * @direction[:y] * @time_step - 0.5 * @gravity * @time_step**2
|
38
|
+
@velocity_y -= @gravity * @time_step
|
39
|
+
@points[:line][id] ||= []
|
40
|
+
@points[:line][id] << [OR2D.game.entities[id].x, OR2D.game.entities[id].y]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Generate a random set of gravity points.
|
45
|
+
# @param stepping [Integer] the number of gravity points to generate
|
46
|
+
# @param gravity_minimum [Float] the minimum gravity value
|
47
|
+
# @param gravity_maximum [Float] the maximum gravity value
|
48
|
+
# @param interval [Float] the interval between gravity points
|
49
|
+
# @return [Array] the generated gravity points
|
50
|
+
def self.gravity_points(stepping: 3, gravity_minimum: 5, gravity_maximum: 100, interval: 0.5)
|
51
|
+
gravity_points = []
|
52
|
+
stepping.times do |i|
|
53
|
+
gravity_points << { time: i * interval, value: gravity_minimum + rand * (gravity_maximum - gravity_minimum) }
|
54
|
+
end
|
55
|
+
|
56
|
+
gravity_points
|
57
|
+
end
|
58
|
+
|
59
|
+
# Convert radians to degrees.
|
60
|
+
# @param radians [Float] the radians to convert
|
61
|
+
# @return [Float] the converted radians
|
62
|
+
def self.rad_to_deg(radians)
|
63
|
+
radians * 360.0 / Math::PI
|
64
|
+
end
|
65
|
+
|
66
|
+
# Destroy the Projectile object.
|
67
|
+
def destroy
|
68
|
+
@layers.each_key do |id|
|
69
|
+
OR2D.game.entities[id].destroy
|
70
|
+
OR2D.game.remove_entity(id)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Is the Projectile object out of bounds?
|
75
|
+
# @return [Boolean] whether the Projectile object is out of bounds
|
76
|
+
def out_of_bounds?
|
77
|
+
if @layers.any? do |id, _|
|
78
|
+
OR2D.game.entities[id].x.negative? ||
|
79
|
+
OR2D.game.entities[id].x > OR2D.game.window.get(:width) ||
|
80
|
+
OR2D.game.entities[id].y.negative? ||
|
81
|
+
OR2D.game.entities[id].y > OR2D.game.window.get(:height)
|
82
|
+
end
|
83
|
+
true
|
84
|
+
else
|
85
|
+
false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def update_gravity
|
92
|
+
@points[:gravity].each do |point|
|
93
|
+
@gravity = point[:value] if @elapsed >= point[:time]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|