Skip to content

Commit e741bb6

Browse files
committed
New 'LoopNoPause' mode and 'easing' option
1 parent 2487a67 commit e741bb6

File tree

3 files changed

+80
-21
lines changed

3 files changed

+80
-21
lines changed

Ahorn/entities/multiNodeMovingPlatform.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ module SpringCollab2020MultiNodeMovingPlatform
22

33
using ..Ahorn, Maple
44

5-
@pardef MultiNodeMovingPlatform(x::Integer, y::Integer, width::Integer=Maple.defaultBlockWidth, mode::String="Loop", texture::String="default", moveTime::Number=2.0, pauseTime::Number=0.0) =
6-
Entity("SpringCollab2020/MultiNodeMovingPlatform", x=x, y=y, nodes=Tuple{Int, Int}[], width=width, mode=mode, texture=texture, moveTime=moveTime, pauseTime=pauseTime)
5+
@pardef MultiNodeMovingPlatform(x::Integer, y::Integer, width::Integer=Maple.defaultBlockWidth, mode::String="Loop", texture::String="default", moveTime::Number=2.0, pauseTime::Number=0.0, easing::Bool=true) =
6+
Entity("SpringCollab2020/MultiNodeMovingPlatform", x=x, y=y, nodes=Tuple{Int, Int}[], width=width, mode=mode, texture=texture, moveTime=moveTime, pauseTime=pauseTime, easing=easing)
77

88
const placements = Ahorn.PlacementDict()
99

10-
const modes = ["Loop", "BackAndForth", "BackAndForthNoPause", "TeleportBack"]
10+
const modes = ["Loop", "LoopNoPause", "BackAndForth", "BackAndForthNoPause", "TeleportBack"]
1111

1212
for texture in Maple.wood_platform_textures
1313
placements["Platform (Moving, Multi-Node, $(uppercasefirst(texture))) (Spring Collab 2020)"] = Ahorn.EntityPlacement(
@@ -115,7 +115,7 @@ function Ahorn.renderAbs(ctx::Ahorn.Cairo.CairoContext, entity::MultiNodeMovingP
115115
previousNodeX, previousNodeY = nodeX, nodeY
116116
end
117117

118-
if mode == "Loop"
118+
if mode == "Loop" || mode == "LoopNoPause"
119119
renderConnection(ctx, previousNodeX, previousNodeY, firstNodeX, firstNodeY, width)
120120
end
121121

@@ -139,7 +139,7 @@ function Ahorn.renderSelectedAbs(ctx::Ahorn.Cairo.CairoContext, entity::MultiNod
139139
previousNodeX, previousNodeY = nodeX, nodeY
140140
end
141141

142-
if mode == "Loop"
142+
if mode == "Loop" || mode == "LoopNoPause"
143143
Ahorn.drawArrow(ctx, previousNodeX + width / 2, previousNodeY, firstNodeX + width / 2, firstNodeY, Ahorn.colors.selection_selected_fc, headLength=6)
144144
end
145145
end

Ahorn/lang/en_gb.lang

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,6 @@ placements.triggers.SpringCollab2020/CustomBirdTutorialTrigger.tooltips.showTuto
131131
# Multi-Node Moving Platform
132132
placements.entities.SpringCollab2020/MultiNodeMovingPlatform.tooltips.moveTime=The time the platform takes to move between two successive positions. Default is 2 seconds.
133133
placements.entities.SpringCollab2020/MultiNodeMovingPlatform.tooltips.pauseTime=The time the platform stops at each position. Default is 0 seconds.
134-
placements.entities.SpringCollab2020/MultiNodeMovingPlatform.tooltips.mode=Determines the way the platform will move between its nodes. For example, with 3 nodes A, B, C:\n- Loop: A > B > C > A\n- BackAndForth: A > B > C > B > A\n- BackAndForthNoPause: A > C > A (going through B)\n- TeleportBack: A > B > C, then the platform teleports to A upon reaching C
134+
placements.entities.SpringCollab2020/MultiNodeMovingPlatform.tooltips.mode=Determines the way the platform will move between its nodes. For example, with 3 nodes A, B, C:\n- Loop: A > B > C > A\n- LoopNoPause: A > A (going through B and C)\n- BackAndForth: A > B > C > B > A\n- BackAndForthNoPause: A > C > A (going through B)\n- TeleportBack: A > B > C, then the platform teleports to A upon reaching C
135135
placements.entities.SpringCollab2020/MultiNodeMovingPlatform.tooltips.texture=What texture to use for the platform.
136+
placements.entities.SpringCollab2020/MultiNodeMovingPlatform.tooltips.easing=Whether the platform movement should be eased (speedup/slowdown around each position).

Entities/MultiNodeMovingPlatform.cs

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Celeste.Mod.SpringCollab2020.Entities {
77
[CustomEntity("SpringCollab2020/MultiNodeMovingPlatform")]
88
class MultiNodeMovingPlatform : JumpThru {
99
private enum Mode {
10-
BackAndForth, BackAndForthNoPause, Loop, TeleportBack
10+
BackAndForth, BackAndForthNoPause, Loop, LoopNoPause, TeleportBack
1111
}
1212

1313
// settings
@@ -16,8 +16,10 @@ private enum Mode {
1616
private float pauseTime;
1717
private string overrideTexture;
1818
private Mode mode;
19+
private bool easing;
1920

2021
private MTexture[] textures;
22+
private float[] nodePercentages;
2123

2224
private string lastSfx;
2325
private SoundSource sfx;
@@ -39,8 +41,9 @@ public MultiNodeMovingPlatform(EntityData data, Vector2 offset)
3941
// read attributes
4042
moveTime = data.Float("moveTime", 2f);
4143
pauseTime = data.Float("pauseTime");
42-
overrideTexture = data.Attr("texture");
43-
mode = data.Enum<Mode>("mode");
44+
overrideTexture = data.Attr("texture", "default");
45+
mode = data.Enum("mode", Mode.Loop);
46+
easing = data.Bool("easing", true);
4447

4548
// read nodes
4649
nodes = new Vector2[data.Nodes.Length + 1];
@@ -56,6 +59,30 @@ public MultiNodeMovingPlatform(EntityData data, Vector2 offset)
5659
"event:/game/03_resort/platform_horiz_left" : "event:/game/03_resort/platform_horiz_right";
5760

5861
Add(new LightOcclude(0.2f));
62+
63+
if (mode == Mode.BackAndForthNoPause || mode == Mode.LoopNoPause) {
64+
nodePercentages = new float[mode == Mode.LoopNoPause ? nodes.Length : nodes.Length - 1];
65+
float totalDistance = 0;
66+
67+
// compute the distance between each node.
68+
for (int i = 0; i < nodes.Length - 1; i++) {
69+
float distance = Vector2.Distance(nodes[i], nodes[i + 1]);
70+
nodePercentages[i] = totalDistance + distance;
71+
totalDistance += distance;
72+
}
73+
74+
// if looping, also compute the distance between the last node and the first one.
75+
if (mode == Mode.LoopNoPause) {
76+
float distance = Vector2.Distance(nodes[nodes.Length - 1], nodes[0]);
77+
nodePercentages[nodes.Length - 1] = totalDistance + distance;
78+
totalDistance += distance;
79+
}
80+
81+
// turn them into percentages.
82+
for (int i = 0; i < nodePercentages.Length; i++) {
83+
nodePercentages[i] /= totalDistance;
84+
}
85+
}
5986
}
6087

6188
public override void Added(Scene scene) {
@@ -79,7 +106,7 @@ public override void Added(Scene scene) {
79106
scene.Add(new MovingPlatformLine(nodes[i] + lineOffset, nodes[i + 1] + lineOffset));
80107
}
81108

82-
if (mode == Mode.Loop) {
109+
if (mode == Mode.Loop || mode == Mode.LoopNoPause) {
83110
scene.Add(new MovingPlatformLine(nodes[nodes.Length - 1] + lineOffset, nodes[0] + lineOffset));
84111
}
85112
}
@@ -132,25 +159,45 @@ public override void Update() {
132159
// move forward...
133160
percent = Calc.Approach(percent, 1f, Engine.DeltaTime / moveTime);
134161

135-
if (mode == Mode.BackAndForthNoPause) {
162+
if (mode == Mode.BackAndForthNoPause || mode == Mode.LoopNoPause) {
163+
// NO PAUSE MODES: the "percentage" is the progress for the whole track, including all nodes.
164+
136165
if (percent == 1f) {
137166
// we reached the last node.
138-
prevNodeIndex = direction == 1 ? nodes.Length - 1 : 0;
139-
MoveTo(nodes[prevNodeIndex] + new Vector2(0f, addY));
140-
141-
// go the other way round now.
142-
direction = -direction;
167+
// pause, then start over.
143168
percent = 0f;
144169
pauseTimer = pauseTime;
170+
171+
if (mode == Mode.BackAndForthNoPause) {
172+
// the current node we're stopped at is either the last node, or the first one, depending on the direction.
173+
prevNodeIndex = direction == 1 ? nodes.Length - 1 : 0;
174+
175+
// go the other way round now.
176+
direction = -direction;
177+
}
178+
179+
MoveTo(nodes[prevNodeIndex] + new Vector2(0f, addY));
145180
} else {
146-
// compute global progress among all nodes, then lerp between the two right nodes.
147-
float progress = MathHelper.Lerp(0, nodes.Length - 1, Ease.SineInOut(direction == 1 ? percent : 1 - percent));
148-
int nodeIndex = (int) progress;
149-
MoveTo(Vector2.Lerp(nodes[nodeIndex], nodes[nodeIndex + 1], progress - nodeIndex) + new Vector2(0f, addY));
181+
// OTHER MODES: the "percentage" is the progress between the current node and the next one.
182+
183+
float easedPercentage = applyEase(direction == 1 ? percent : 1 - percent);
184+
185+
// for example, if node percentages are 0.2 and 1, and easedPercentage is 0.6, nextNodeIndex = 1.
186+
int nextNodeIndex = 0;
187+
while (nodePercentages[nextNodeIndex] < easedPercentage) {
188+
nextNodeIndex++;
189+
}
190+
191+
// in this case, previousNodePercentage = 0.2 and nextNodePercentage = 1. ClampedMap will remap 0.6 to 0.5 since this is halfway between 0.2 and 1.
192+
float previousNodePercentage = nextNodeIndex == 0 ? 0 : nodePercentages[nextNodeIndex - 1];
193+
float nextNodePercentage = nodePercentages[nextNodeIndex];
194+
195+
MoveTo(Vector2.Lerp(nodes[nextNodeIndex], nodes[(nextNodeIndex + 1) % nodes.Length],
196+
Calc.ClampedMap(easedPercentage, previousNodePercentage, nextNodePercentage)) + new Vector2(0f, addY));
150197
}
151198
} else {
152199
// lerp between the previous node and the next one.
153-
MoveTo(Vector2.Lerp(nodes[prevNodeIndex], nodes[nextNodeIndex], Ease.SineInOut(percent)) + new Vector2(0f, addY));
200+
MoveTo(Vector2.Lerp(nodes[prevNodeIndex], nodes[nextNodeIndex], applyEase(percent)) + new Vector2(0f, addY));
154201

155202
if (percent == 1f) {
156203
// reached the end. start waiting before moving again, and switch the target to the next node.
@@ -181,5 +228,16 @@ public override void Update() {
181228
}
182229
}
183230
}
231+
232+
/// <summary>
233+
/// Apply easing if the "easing" attribute is true, else don't modify the value.
234+
/// </summary>
235+
private float applyEase(float rawValue) {
236+
if (easing) {
237+
return Ease.SineInOut(rawValue);
238+
}
239+
240+
return rawValue;
241+
}
184242
}
185243
}

0 commit comments

Comments
 (0)