Fixes for platform snapping.

This commit is contained in:
genxium 2022-12-10 12:30:44 +08:00
parent 9917a62526
commit 66dfcaa0f5
3 changed files with 103 additions and 84 deletions

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="128" height="128" tilewidth="16" tileheight="16" infinite="0" nextlayerid="3" nextobjectid="49"> <map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="128" height="128" tilewidth="16" tileheight="16" infinite="0" nextlayerid="3" nextobjectid="53">
<tileset firstgid="1" source="tiles0.tsx"/> <tileset firstgid="1" source="tiles0.tsx"/>
<tileset firstgid="65" source="tiles1.tsx"/> <tileset firstgid="65" source="tiles1.tsx"/>
<tileset firstgid="129" source="tiles2.tsx"/> <tileset firstgid="129" source="tiles2.tsx"/>
<layer id="2" name="Ground" width="128" height="128"> <layer id="2" name="Ground" width="128" height="128">
<data encoding="base64" compression="zlib"> <data encoding="base64" compression="zlib">
eJzt2qFu21AUgOEo1UhBtYJOKh/bmxRMRYNFfZPxwcGi7j3nSInkXTmx47k+1/d84EOJIuf+PtZ14pvdbncDAAAAAAAAAAAAAAAAAAAz3B5FHwfree059X9NKLpDZP/90an/S+fpjH2D9P+3/zn6t6ff/2mk/20FrfT/uP5D9G/b4bs/HA2tTXlNiG6l/7r9M9Bf/+gOkf0/zRDdTH/99ddf/5j+NdBff/31119//bfV/9fE990f6d9W//fO25nXDv8//+l81z+8/9w1Pf2m+PM/6a+//vofjuWxoH/7/R+L/uZff/3j+38esWT/Pv1j+491H+r/u/PjSqf+9n/19J/a/nln/78VU/tPbb/Xf1PG+g81/ta5O9O+7F96vpL+cf2H2t/1lN0/ov+Xzlf9q+l/6brf7780/evtP2ePeC391+8/5Rwo13LJvmOW7L+voEWN/Zda40vmtNe/nf7R9M99Duivv/76R7eI6h+9/tGy3/9Fr380/XPTPzf9c9M/N/1z0z83/XPTPzf9c9M/N/1z0z83/XPTPzf9c9N/vvtCdEv9t9e//IxL9G+vfzT9l5vV6Jb6rzv/LdB/XbVdOzz/Pb1V9Kzqv/35r43+80Xdsy3dP7rDVvu3QP/tzaz+5l//bfSvfU+g//r959B/vf5b3s/rX9f8107/3PTPLXt/4jsAAAAAAAAAAAAAAAAA6/sLjbyILg== eJzt2zFv2kAYgGFElCVD1AytlL1b/0mGKlPHTvkn3Tt27NT+zxoJJHqysXGMv/N9z/BMRsjc6zsOMHe73e4OAAAAAAAAAAAAAAAAAABmeDiKPg/W83bm1P8toegOkf33R6f+3zsvA/YN0v///kP0b895/5eR/g8VtNL/dv376N+2w2v/eNQ3NuWaEN1K/3X7Z6C//tEdIvvfzxDdTH/99ddf/5j+NdBff/31119//bfV/+fExz0d6d9W/z+d3wPHDr8//+181T+8/9wxPX2n+OOd9Ndff/0P5/Jc0L/9/s9Ff/Nff/3j+38YsWT/c/rH9h/r3tf/V+fblU797f/q6T+1/evO/n8rpvaf2n6v/6aM9e9r/KXzONC+7F96vZL+cf372j+eKbvfov+nzmf9q+l/ad0/7780/evtP2ePeC391+8/5Roox3LJvmOW7L+voEWN/Zca40vmtNe/nf7R9M99Deivv/76R7eI6h89/tGyf/6LHv9o+uemf27656Z/bvrnpn9u+uemf27656Z/bvrnpn9u+uemf27656b/fE+F6Jb6b7t/+XylW9yjpn89/c3/uvuPzc/olvqvO/9boP+6als73P89ruX/BOifm/7jc3/o2Nh+cAt7Qu//l9u3tt7rf938b132/hn/86n/evO/9j2B/uv3n0P/9fpveT+vf13zv3b656Z/btn7E98BAAAAAAAAAAAAAAAAWN8/Hh2Hvw==
</data> </data>
</layer> </layer>
<objectgroup id="1" name="PlayerStartingPos"> <objectgroup id="1" name="PlayerStartingPos">
@ -170,23 +170,23 @@
</properties> </properties>
<polyline points="0,0 -65,0 -64,58 -2,61"/> <polyline points="0,0 -65,0 -64,58 -2,61"/>
</object> </object>
<object id="40" x="735" y="1486"> <object id="40" x="735" y="1503">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
<polyline points="0,0 -63,1 -62,14 0,16 1,16 0,14"/> <polyline points="0.333333,0.666667 -79,0.333333 -79.6667,18.6667 1.66667,16.3333"/>
</object> </object>
<object id="41" x="832" y="1375.33"> <object id="41" x="832" y="1375.33">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
<polyline points="0,0 -0.666667,15.3333 128.667,15.3333 130,0"/> <polyline points="0,0 -0.666667,15.3333 128.667,15.3333 129.333,0"/>
</object> </object>
<object id="42" x="832.667" y="1424"> <object id="42" x="865.667" y="1424">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
<polyline points="0,0 -66,0 -65.3333,15.3333 2,16"/> <polyline points="-2.33333,-0.333333 -66,0 -65.3333,15.3333 -1.33333,16.3333"/>
</object> </object>
<object id="43" x="850" y="1552.67"> <object id="43" x="850" y="1552.67">
<properties> <properties>
@ -198,19 +198,19 @@
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
<polyline points="0,0 -148.667,0.666667 -148.667,15.3333 0,16.6667"/> <polyline points="0,0 -146.334,0.666667 -146,16.6666 0,16.6667"/>
</object> </object>
<object id="45" x="1345.33" y="1343.33"> <object id="45" x="1442" y="1343.33">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
<polyline points="0,0 -178,0 -178,14 -0.666667,15.3333"/> <polyline points="0,0 -226.667,0 -226.667,14 -0.848939,15.3333"/>
</object> </object>
<object id="46" x="1200" y="1406.67"> <object id="46" x="1200" y="1406.67">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
<polyline points="0,0 -96.6667,0 -96.6667,15.3333 0,16.6667"/> <polyline points="0,0 -97.3334,0 -97,17.3333 0,16.6667"/>
</object> </object>
<object id="47" x="1120" y="1520.67"> <object id="47" x="1120" y="1520.67">
<properties> <properties>
@ -222,7 +222,19 @@
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
<polyline points="77,-0.333333 9.10906,14.6667 299.775,14.6667 298.84,-2"/> <polyline points="90.3333,-4.66667 9.10906,14.6667 299.775,14.6667 300.173,1.33333"/>
</object>
<object id="51" x="783.333" y="1455">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
<polyline points="0,0 -0.333333,31.6667 15.3333,32 15.3333,0"/>
</object>
<object id="52" x="768.333" y="1471.67">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
<polyline points="0,0 0,15.3333 31,15.3333 31.6667,-0.333333"/>
</object> </object>
</objectgroup> </objectgroup>
</map> </map>

View File

@ -10,6 +10,28 @@ window.ATK_CHARACTER_STATE = {
InAirAtked1: [6, "Atked1"], InAirAtked1: [6, "Atked1"],
}; };
window.toInAirConjugate = function(foo) {
switch (foo) {
case window.ATK_CHARACTER_STATE.Idle1[0]:
case window.ATK_CHARACTER_STATE.Walking[0]:
return window.ATK_CHARACTER_STATE.InAirIdle1[0];
case window.ATK_CHARACTER_STATE.Atk1[0]:
return window.ATK_CHARACTER_STATE.InAirAtk1[0];
case window.ATK_CHARACTER_STATE.Atked1[0]:
return window.ATK_CHARACTER_STATE.InAirAtked1[0];
case window.ATK_CHARACTER_STATE.InAirIdle1[0]:
return window.ATK_CHARACTER_STATE.Idle1[0];
case window.ATK_CHARACTER_STATE.InAirAtk1[0]:
return window.ATK_CHARACTER_STATE.Atk1[0];
case window.ATK_CHARACTER_STATE.InAirAtked1[0]:
return window.ATK_CHARACTER_STATE.Atked1[0];
default:
console.warn(`Invalid characterState ${foo} received, no in air conjugate is available!`);
return null;
}
}
window.ATK_CHARACTER_STATE_ARR = []; window.ATK_CHARACTER_STATE_ARR = [];
for (let k in window.ATK_CHARACTER_STATE) { for (let k in window.ATK_CHARACTER_STATE) {
window.ATK_CHARACTER_STATE_ARR.push(window.ATK_CHARACTER_STATE[k]); window.ATK_CHARACTER_STATE_ARR.push(window.ATK_CHARACTER_STATE[k]);

View File

@ -2,6 +2,12 @@ const i18n = require('LanguageData');
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
const OnlineMap = require('./Map'); const OnlineMap = require('./Map');
/*
[WARNING] As when a character is standing on a barrier, if not carefully curated there MIGHT BE a bouncing sequence of "[(inAir -> dropIntoBarrier ->), (notInAir -> pushedOutOfBarrier ->)], [(inAir -> ..."
Moreover, this "snapIntoPlatformOverlap" should be small enough such that the jumping initial "velY" can escape from it by 1 renderFrame (when jumping is triggered, the character is waived from snappig for 1 renderFrame).
*/
const snapIntoPlatformOverlap = 0.1;
cc.Class({ cc.Class({
extends: OnlineMap, extends: OnlineMap,
@ -238,13 +244,16 @@ cc.Class({
const nextRenderFrameMeleeBullets = []; const nextRenderFrameMeleeBullets = [];
const movements = new Array(self.playerRichInfoArr.length); // Guaranteed determinism regardless of traversal order // Guaranteed determinism regardless of traversal order
const bulletPushbacks = new Array(self.playerRichInfoArr.length); // Guaranteed determinism regardless of traversal order const jumpTriggered = new Array(self.playerRichInfoArr.length);
const effPushbacks = new Array(self.playerRichInfoArr.length); // Guaranteed determinism regardless of traversal order const movements = new Array(self.playerRichInfoArr.length);
const bulletPushbacks = new Array(self.playerRichInfoArr.length);
const effPushbacks = new Array(self.playerRichInfoArr.length);
// Reset playerCollider position from the "virtual grid position" // Reset playerCollider position from the "virtual grid position"
for (let j in self.playerRichInfoArr) { for (let j in self.playerRichInfoArr) {
const joinIndex = parseInt(j) + 1; const joinIndex = parseInt(j) + 1;
jumpTriggered[joinIndex - 1] = false;
movements[joinIndex - 1] = [0.0, 0.0]; movements[joinIndex - 1] = [0.0, 0.0];
bulletPushbacks[joinIndex - 1] = [0.0, 0.0]; bulletPushbacks[joinIndex - 1] = [0.0, 0.0];
effPushbacks[joinIndex - 1] = [0.0, 0.0]; effPushbacks[joinIndex - 1] = [0.0, 0.0];
@ -259,7 +268,7 @@ cc.Class({
const newVy = currPlayerDownsync.virtualGridY; const newVy = currPlayerDownsync.virtualGridY;
[playerCollider.x, playerCollider.y] = self.virtualGridToPolygonColliderAnchorPos(newVx, newVy, self.playerRichInfoArr[joinIndex - 1].colliderRadius, self.playerRichInfoArr[joinIndex - 1].colliderRadius); [playerCollider.x, playerCollider.y] = self.virtualGridToPolygonColliderAnchorPos(newVx, newVy, self.playerRichInfoArr[joinIndex - 1].colliderRadius, self.playerRichInfoArr[joinIndex - 1].colliderRadius);
// Process gravity before anyother interaction // Process gravity before anyother interaction, by now "currPlayerDownsync.velX & velY" are properly snapped to be parallel to the edge of its standing platform if necessary
[movements[joinIndex - 1][0], movements[joinIndex - 1][1]] = self.virtualGridToWorldPos(currPlayerDownsync.velX, currPlayerDownsync.velY); [movements[joinIndex - 1][0], movements[joinIndex - 1][1]] = self.virtualGridToWorldPos(currPlayerDownsync.velX, currPlayerDownsync.velY);
playerCollider.x += movements[joinIndex - 1][0]; playerCollider.x += movements[joinIndex - 1][0];
playerCollider.y += movements[joinIndex - 1][1]; playerCollider.y += movements[joinIndex - 1][1];
@ -375,6 +384,22 @@ cc.Class({
const prevDecodedInput = (null == delayedInputFrameForPrevRenderFrame ? null : self.ctrl.decodeInput(delayedInputFrameForPrevRenderFrame.inputList[joinIndex - 1])); const prevDecodedInput = (null == delayedInputFrameForPrevRenderFrame ? null : self.ctrl.decodeInput(delayedInputFrameForPrevRenderFrame.inputList[joinIndex - 1]));
const prevBtnALevel = (null == prevDecodedInput ? 0 : prevDecodedInput.btnALevel); const prevBtnALevel = (null == prevDecodedInput ? 0 : prevDecodedInput.btnALevel);
const prevBtnBLevel = (null == prevDecodedInput ? 0 : prevDecodedInput.btnBLevel); const prevBtnBLevel = (null == prevDecodedInput ? 0 : prevDecodedInput.btnBLevel);
/*
[WARNING] Player input alone WOULD NOT take "characterState" into any "ATK_CHARACTER_STATE_IN_AIR_SET", only after the calculation of "effPushbacks" do we know exactly whether or not a player is "inAir", the finalize the transition of "thatPlayerInNextFrame.characterState".
*/
if (1 == decodedInput.btnBLevel && 0 == prevBtnBLevel) {
const characStateAlreadyInAir = window.ATK_CHARACTER_STATE_IN_AIR_SET.has(thatPlayerInNextFrame.characterState);
const characStateIsInterruptWaivable = window.ATK_CHARACTER_STATE_INTERRUPT_WAIVE_SET.has(thatPlayerInNextFrame.characterState);
if (
!characStateAlreadyInAir
&&
characStateIsInterruptWaivable
) {
thatPlayerInNextFrame.velY = currPlayerDownsync.speed * 4.5;
jumpTriggered[joinIndex - 1] = true;
console.log(`playerId=${playerId}, joinIndex=${joinIndex} triggered a rising-edge of btnB at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}, nextVelY=${thatPlayerInNextFrame.velY}, characStateAlreadyInAir=${characStateAlreadyInAir}, characStateIsInterruptWaivable=${characStateIsInterruptWaivable}`);
}
}
if (1 == decodedInput.btnALevel && 0 == prevBtnALevel) { if (1 == decodedInput.btnALevel && 0 == prevBtnALevel) {
// console.log(`playerId=${playerId} triggered a rising-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`); // console.log(`playerId=${playerId} triggered a rising-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
@ -390,61 +415,21 @@ cc.Class({
// console.log(`A rising-edge of meleeBullet is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}: ${self._stringifyRecentInputCache(true)}`); // console.log(`A rising-edge of meleeBullet is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}: ${self._stringifyRecentInputCache(true)}`);
// console.log(`A rising-edge of meleeBullet is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`); // console.log(`A rising-edge of meleeBullet is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
if (!window.ATK_CHARACTER_STATE_IN_AIR_SET.has(currPlayerDownsync.characterState)) {
thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Atk1[0]; thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Atk1[0];
} else {
thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.InAirAtk1[0];
}
} }
} else if (0 == decodedInput.btnALevel && 1 == prevBtnALevel) { } else if (0 == decodedInput.btnALevel && 1 == prevBtnALevel) {
// console.log(`playerId=${playerId} triggered a falling-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`); // console.log(`playerId=${playerId} triggered a falling-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
} else { } else {
// No bullet trigger, process movement inputs // No bullet trigger, process joystick movement inputs (except for jumping).
if (1 == decodedInput.btnBLevel && 0 == prevBtnBLevel) {
const characStateAlreadyInAir = window.ATK_CHARACTER_STATE_IN_AIR_SET.has(thatPlayerInNextFrame.characterState);
const characStateIsInterruptWaivable = window.ATK_CHARACTER_STATE_INTERRUPT_WAIVE_SET.has(thatPlayerInNextFrame.characterState);
console.log(`playerId=${playerId} triggered a rising-edge of btnB at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}, characStateAlreadyInAir=${characStateAlreadyInAir}, characStateIsInterruptWaivable=${characStateIsInterruptWaivable}`);
if (
!characStateAlreadyInAir
&&
characStateIsInterruptWaivable
) {
thatPlayerInNextFrame.velY = currPlayerDownsync.speed * 4;
thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.InAirIdle1[0];
if (window.ATK_CHARACTER_STATE.Walking[0] == currPlayerDownsync.characterState) {
console.warn(`curRenderFrameId=${currRenderFrame.id}, playerId=${playerId}, joinIndex=${joinIndex} characterState set to AirIdle1 by jumping`);
}
}
} else {
if (0 != decodedInput.dx || 0 != decodedInput.dy) { if (0 != decodedInput.dx || 0 != decodedInput.dy) {
// Update directions and thus would eventually update moving animation accordingly // Update directions and thus would eventually update moving animation accordingly
thatPlayerInNextFrame.dirX = decodedInput.dx; thatPlayerInNextFrame.dirX = decodedInput.dx;
thatPlayerInNextFrame.dirY = decodedInput.dy; thatPlayerInNextFrame.dirY = decodedInput.dy;
if (!window.ATK_CHARACTER_STATE_IN_AIR_SET.has(thatPlayerInNextFrame.characterState)) {
thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Walking[0]; thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Walking[0];
thatPlayerInNextFrame.velX = currPlayerDownsync.speed * decodedInput.dx; thatPlayerInNextFrame.velX = decodedInput.dx * currPlayerDownsync.speed;
if (window.ATK_CHARACTER_STATE.Idle1[0] == currPlayerDownsync.characterState || window.ATK_CHARACTER_STATE.InAirIdle1[0] == currPlayerDownsync.characterState) {
console.warn(`curRenderFrameId=${currRenderFrame.id}, playerId=${playerId}, joinIndex=${joinIndex} characterState set to Walking by dir input`);
}
} else { } else {
// There's no characterState of "InAirWalking" :)
thatPlayerInNextFrame.velX = currPlayerDownsync.speed * decodedInput.dx;
}
} else {
if (!window.ATK_CHARACTER_STATE_IN_AIR_SET.has(thatPlayerInNextFrame.characterState)) {
thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Idle1[0]; thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Idle1[0];
thatPlayerInNextFrame.velX = 0; thatPlayerInNextFrame.velX = 0;
if (window.ATK_CHARACTER_STATE.Walking[0] == currPlayerDownsync.characterState) {
console.warn(`curRenderFrameId=${currRenderFrame.id}, playerId=${playerId}, joinIndex=${joinIndex} characterState set to Idle1 by no dir input`);
}
} else {
thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.InAirIdle1[0];
if (window.ATK_CHARACTER_STATE.Walking[0] == currPlayerDownsync.characterState) {
console.warn(`curRenderFrameId=${currRenderFrame.id}, playerId=${playerId}, joinIndex=${joinIndex} characterState set to AirIdle1 by no dir input but already in air`);
}
// let inertia carry "velX" when in air
}
}
} }
} }
} }
@ -462,7 +447,7 @@ cc.Class({
const currPlayerDownsync = currRenderFrame.players[playerId]; const currPlayerDownsync = currRenderFrame.players[playerId];
const thatPlayerInNextFrame = nextRenderFramePlayers[playerId]; const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
let fallStopping = false; let fallStopping = false;
let remainsNotInAir = false; let [snappedIntoPlatformEx, snappedIntoPlatformEy] = [null, null];
for (const potential of potentials) { for (const potential of potentials) {
// Test if the player collides with the wall // Test if the player collides with the wall
if (!playerCollider.collides(potential, result2)) continue; if (!playerCollider.collides(potential, result2)) continue;
@ -470,33 +455,33 @@ cc.Class({
let [pushbackX, pushbackY] = [result2.overlap * result2.overlap_x, result2.overlap * result2.overlap_y]; let [pushbackX, pushbackY] = [result2.overlap * result2.overlap_x, result2.overlap * result2.overlap_y];
if (null == potential.data) { if (null == potential.data) {
// "null == potential.data" implies a barrier // "null == potential.data" implies a barrier
const remainsNotInAir = (!currPlayerDownsync.inAir);
const localFallStopping = (currPlayerDownsync.inAir && 0 > pushbackY); // prevents false fall-stopping on the lateral sides const localFallStopping = (currPlayerDownsync.inAir && 0 > pushbackY); // prevents false fall-stopping on the lateral sides
const localRemainsNotInAir = (!currPlayerDownsync.inAir); if (remainsNotInAir || localFallStopping) {
// [WARNING] As when a character is standing on a barrier, if not carefully curated there MIGHT BE a bouncing sequence of "[(inAir -> dropIntoBarrier ->), (notInAir -> pushedOutOfBarrier ->)], [(inAir -> ..." fallStopping |= localFallStopping;
if (localFallStopping) { [pushbackX, pushbackY] = [(result2.overlap - snapIntoPlatformOverlap) * result2.overlap_x, (result2.overlap - snapIntoPlatformOverlap) * result2.overlap_y]
pushbackY = 0.95 * pushbackY; // [overlay_x, overlap_y] is the unit vector that points into the platform; FIXME: Should only assign to [snappedIntoPlatformEx, snappedIntoPlatformEy] at most once!
fallStopping = true; snappedIntoPlatformEx = -result2.overlap_y;
snappedIntoPlatformEy = result2.overlap_x;
if (snappedIntoPlatformEx * currPlayerDownsync.dirX + snappedIntoPlatformEy * currPlayerDownsync.dirY) {
[snappedIntoPlatformEx, snappedIntoPlatformEy] = [-snappedIntoPlatformEx, -snappedIntoPlatformEy];
} }
if (localRemainsNotInAir) {
pushbackY = 0;
remainsNotInAir = true;
} }
} }
// What if we're on the edge of 2 barriers? Would adding up make an unexpected bounce? // What if we're on the edge of 2 barriers? Would adding up make an unexpected bounce?
effPushbacks[joinIndex - 1][0] += pushbackX; effPushbacks[joinIndex - 1][0] += pushbackX;
effPushbacks[joinIndex - 1][1] += pushbackY; effPushbacks[joinIndex - 1][1] += pushbackY;
} }
if (false == jumpTriggered[joinIndex-1] && null != snappedIntoPlatformEx && null != snappedIntoPlatformEy) {
thatPlayerInNextFrame.inAir = false;
if (fallStopping) { if (fallStopping) {
thatPlayerInNextFrame.velX = 0; thatPlayerInNextFrame.velY = 0; // shuts off the velocity component introduced by gravity, otherwise the character will slip down along a slope
thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Idle1[0];
thatPlayerInNextFrame.velY = 0;
thatPlayerInNextFrame.inAir = false;
if (window.ATK_CHARACTER_STATE.Walking[0] == currPlayerDownsync.characterState) {
console.warn(`curRenderFrameId=${currRenderFrame.id}, playerId=${playerId}, joinIndex=${joinIndex} characterState set to Idle1 by fallStopping`);
} }
const dotProd = thatPlayerInNextFrame.velX * snappedIntoPlatformEx + thatPlayerInNextFrame.velY * snappedIntoPlatformEy;
[thatPlayerInNextFrame.velX, thatPlayerInNextFrame.velY] = [dotProd * snappedIntoPlatformEx, dotProd * snappedIntoPlatformEy];
} }
if (remainsNotInAir) { if (currPlayerDownsync.inAir != thatPlayerInNextFrame.inAir) {
thatPlayerInNextFrame.inAir = false; thatPlayerInNextFrame.characterState = window.toInAirConjugate(thatPlayerInNextFrame.characterState);
} }
} }