Platform Displacement 2.1 (#776)

This commit is contained in:
arthurtilly
2024-04-22 09:14:12 +12:00
committed by GitHub
parent 2ae3426957
commit f852ff4359
7 changed files with 69 additions and 237 deletions

View File

@@ -2694,7 +2694,7 @@ const BehaviorScript bhvSushiShark[] = {
const BehaviorScript bhvJrbSlidingBox[] = { const BehaviorScript bhvJrbSlidingBox[] = {
BEGIN(OBJ_LIST_SURFACE), BEGIN(OBJ_LIST_SURFACE),
OR_INT(oFlags, OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE), OR_INT(oFlags, OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE | OBJ_FLAG_NO_AUTO_DISPLACEMENT),
LOAD_COLLISION_DATA(jrb_seg7_collision_floating_box), LOAD_COLLISION_DATA(jrb_seg7_collision_floating_box),
SET_HOME(), SET_HOME(),
BEGIN_LOOP(), BEGIN_LOOP(),
@@ -5437,11 +5437,7 @@ const BehaviorScript bhvTTCPendulum[] = {
const BehaviorScript bhvTTCTreadmill[] = { const BehaviorScript bhvTTCTreadmill[] = {
BEGIN(OBJ_LIST_SURFACE), BEGIN(OBJ_LIST_SURFACE),
#ifdef PLATFORM_DISPLACEMENT_2 OR_INT(oFlags, (OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE | OBJ_FLAG_NO_AUTO_DISPLACEMENT)),
OR_INT(oFlags, (OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE | OBJ_FLAG_VELOCITY_PLATFORM)),
#else
OR_INT(oFlags, (OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)),
#endif
SET_FLOAT(oCollisionDistance, 750), SET_FLOAT(oCollisionDistance, 750),
CALL_NATIVE(bhv_ttc_treadmill_init), CALL_NATIVE(bhv_ttc_treadmill_init),
DELAY(1), DELAY(1),

View File

@@ -136,14 +136,8 @@
*/ */
#define BUGFIX_DIALOG_TIME_STOP #define BUGFIX_DIALOG_TIME_STOP
/**
* Enables Platform Displacement 2, an upgrade to the physics involving moving platforms and how Mario interacts with them.
*/
#define PLATFORM_DISPLACEMENT_2
/** /**
* Inertia defines; allow Mario to preserve his momemtum when leaving moving platforms. * Inertia defines; allow Mario to preserve his momemtum when leaving moving platforms.
* These require Platform Displacement 2 to be enabled.
*/ */
#define MARIO_INERTIA_UPWARD #define MARIO_INERTIA_UPWARD
// #define MARIO_INERTIA_LATERAL // #define MARIO_INERTIA_LATERAL

View File

@@ -47,7 +47,7 @@ enum ObjFlags {
OBJ_FLAG_1000 = (1 << 12), // 0x00001000 OBJ_FLAG_1000 = (1 << 12), // 0x00001000
OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO = (1 << 13), // 0x00002000 OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO = (1 << 13), // 0x00002000
OBJ_FLAG_PERSISTENT_RESPAWN = (1 << 14), // 0x00004000 OBJ_FLAG_PERSISTENT_RESPAWN = (1 << 14), // 0x00004000
OBJ_FLAG_VELOCITY_PLATFORM = (1 << 15), // 0x00008000 OBJ_FLAG_NO_AUTO_DISPLACEMENT = (1 << 15), // 0x00008000
OBJ_FLAG_DONT_CALC_COLL_DIST = (1 << 16), // 0x00010000 OBJ_FLAG_DONT_CALC_COLL_DIST = (1 << 16), // 0x00010000
OBJ_FLAG_SILHOUETTE = (1 << 19), // 0x00080000 OBJ_FLAG_SILHOUETTE = (1 << 19), // 0x00080000
OBJ_FLAG_OCCLUDE_SILHOUETTE = (1 << 20), // 0x00100000 OBJ_FLAG_OCCLUDE_SILHOUETTE = (1 << 20), // 0x00100000

View File

@@ -1435,9 +1435,7 @@ s32 bowser_check_fallen_off_stage(void) {
return FALSE; return FALSE;
} }
#ifdef PLATFORM_DISPLACEMENT_2
struct PlatformDisplacementInfo sBowserDisplacementInfo; struct PlatformDisplacementInfo sBowserDisplacementInfo;
#endif
/** /**
* Set Bowser's actions * Set Bowser's actions
@@ -1513,18 +1511,13 @@ s8 sBowserHealth[] = { 1, 1, 3 };
*/ */
void bowser_free_update(void) { void bowser_free_update(void) {
struct Object *platform = o->platform; struct Object *platform = o->platform;
#ifdef PLATFORM_DISPLACEMENT_2
s16 tmpOFaceAngleYaw = (s16) o->oFaceAngleYaw;
if (platform != NULL) { if (platform != NULL) {
// NOTE: This function was at one point using '&o->oFaceAngleYaw', which is a s32 address. Should tmpOFaceAngleYaw be using the first 16 bits instead, or was that a bug? s16 tempYaw = (s16) o->oFaceAngleYaw;
apply_platform_displacement(&sBowserDisplacementInfo, &o->oPosVec, &tmpOFaceAngleYaw, platform); apply_platform_displacement(&sBowserDisplacementInfo, &o->oPosVec, &tempYaw, platform);
o->oFaceAngleYaw = tmpOFaceAngleYaw; o->oFaceAngleYaw = tempYaw;
} }
#else
if (platform != NULL) {
apply_platform_displacement(FALSE, platform);
}
#endif
// Reset grabbed status // Reset grabbed status
o->oBowserGrabbedStatus = BOWSER_GRAB_STATUS_NONE; o->oBowserGrabbedStatus = BOWSER_GRAB_STATUS_NONE;
// Update positions and actions (default action) // Update positions and actions (default action)

View File

@@ -17,29 +17,13 @@ void bhv_platform_normals_init(void) {
* then gradually tilt back moving Mario with them. * then gradually tilt back moving Mario with them.
*/ */
void bhv_tilting_inverted_pyramid_loop(void) { void bhv_tilting_inverted_pyramid_loop(void) {
#ifndef PLATFORM_DISPLACEMENT_2
Vec3f posBeforeRotation, posAfterRotation;
Vec3f marioPos, dist;
#endif
Vec3f targetNormal; Vec3f targetNormal;
Mat4 *transform = &o->transform; Mat4 *transform = &o->transform;
s32 marioOnPlatform = (gMarioObject->platform == o); s32 marioOnPlatform = (gMarioObject->platform == o);
if (marioOnPlatform) { if (marioOnPlatform) {
#ifndef PLATFORM_DISPLACEMENT_2
// Target the normal in Mario's direction
vec3_diff(dist, gMarioStates[0].pos, &o->oPosVec);
// Get Mario's position before the rotation
vec3f_copy(marioPos, gMarioStates[0].pos);
linear_mtxf_mul_vec3f(*transform, posBeforeRotation, dist);
targetNormal[0] = dist[0];
targetNormal[2] = dist[2];
#else // PLATFORM_DISPLACEMENT_2
targetNormal[0] = gMarioStates[0].pos[0] - o->oPosX; targetNormal[0] = gMarioStates[0].pos[0] - o->oPosX;
targetNormal[2] = gMarioStates[0].pos[2] - o->oPosZ; targetNormal[2] = gMarioStates[0].pos[2] - o->oPosZ;
#endif
targetNormal[1] = 500.0f; targetNormal[1] = 500.0f;
vec3f_normalize(targetNormal); vec3f_normalize(targetNormal);
} else { } else {
@@ -54,16 +38,5 @@ void bhv_tilting_inverted_pyramid_loop(void) {
approach_f32_symmetric_bool(&o->oTiltingPyramidNormalZ, targetNormal[2], 0.01f); approach_f32_symmetric_bool(&o->oTiltingPyramidNormalZ, targetNormal[2], 0.01f);
mtxf_align_terrain_normal(*transform, &o->oTiltingPyramidNormalVec, &o->oPosVec, 0x0); mtxf_align_terrain_normal(*transform, &o->oTiltingPyramidNormalVec, &o->oPosVec, 0x0);
#ifndef PLATFORM_DISPLACEMENT_2
// If Mario is on the platform, adjust his position for the platform tilt.
if (marioOnPlatform) {
linear_mtxf_mul_vec3f(*transform, posAfterRotation, dist);
marioPos[0] += posAfterRotation[0] - posBeforeRotation[0];
marioPos[1] += posAfterRotation[1] - posBeforeRotation[1];
marioPos[2] += posAfterRotation[2] - posBeforeRotation[2];
vec3f_copy(gMarioStates[0].pos, marioPos);
}
#endif
o->header.gfx.throwMatrix = transform; o->header.gfx.throwMatrix = transform;
} }

View File

@@ -10,10 +10,13 @@
#include "types.h" #include "types.h"
#include "sm64.h" #include "sm64.h"
#include "behavior_data.h" #include "behavior_data.h"
#include "game_init.h"
#include "config.h" #include "config.h"
struct Object *gMarioPlatform = NULL; struct Object *gMarioPlatform = NULL;
static struct PlatformDisplacementInfo sMarioDisplacementInfo;
static Vec3f sMarioAmountDisplaced;
/** /**
* Determine if Mario is standing on a platform object, meaning that he is * Determine if Mario is standing on a platform object, meaning that he is
@@ -48,6 +51,11 @@ void update_mario_platform(void) {
if (floor != NULL && floor->object != NULL) { if (floor != NULL && floor->object != NULL) {
gMarioPlatform = floor->object; gMarioPlatform = floor->object;
gMarioObject->platform = floor->object; gMarioObject->platform = floor->object;
// If this is the first frame of Mario standing on the platform,
// then initialise his platform displacement info struct
if ((floor->object != sMarioDisplacementInfo.prevPlatform) || (gGlobalTimer != sMarioDisplacementInfo.prevTimer)) {
update_platform_displacement_info(&sMarioDisplacementInfo, gMarioState->pos, gMarioState->faceAngle[1], floor->object);
}
} else { } else {
gMarioPlatform = NULL; gMarioPlatform = NULL;
gMarioObject->platform = NULL; gMarioObject->platform = NULL;
@@ -56,42 +64,28 @@ void update_mario_platform(void) {
} }
/** /**
* Get Mario's position and store it in x, y, and z. * Set the values in the platform displacement struct for use next frame
*/ */
void get_mario_pos(f32 *x, f32 *y, f32 *z) { void update_platform_displacement_info(struct PlatformDisplacementInfo *displaceInfo, Vec3f pos, s16 yaw, struct Object *platform) {
*x = gMarioStates[0].pos[0]; Vec3f scaledPos, yawVec, localPos;
*y = gMarioStates[0].pos[1];
*z = gMarioStates[0].pos[2];
}
/** // Avoid a crash if the platform unloaded its collision while stood on or is static
* Set Mario's position. if (platform->header.gfx.throwMatrix == NULL) return;
*/
void set_mario_pos(f32 x, f32 y, f32 z) {
gMarioStates[0].pos[0] = x;
gMarioStates[0].pos[1] = y;
gMarioStates[0].pos[2] = z;
}
#ifdef PLATFORM_DISPLACEMENT_2 // Update position
static struct PlatformDisplacementInfo sMarioDisplacementInfo; vec3_diff(localPos, pos, (*platform->header.gfx.throwMatrix)[3]);
static Vec3f sMarioAmountDisplaced; linear_mtxf_transpose_mul_vec3(*platform->header.gfx.throwMatrix, scaledPos, localPos);
vec3_quot(displaceInfo->prevTransformedPos, scaledPos, platform->header.gfx.scale);
vec3_copy(displaceInfo->prevPos, pos);
extern s32 gGlobalTimer; // Update yaw
vec3_set(yawVec, sins(yaw), 0, coss(yaw));
linear_mtxf_transpose_mul_vec3(*platform->header.gfx.throwMatrix, displaceInfo->prevTransformedYawVec, yawVec);
displaceInfo->prevYaw = yaw;
/** // Update platform and timer
* Upscale or downscale a vector by another vector. displaceInfo->prevPlatform = platform;
*/ displaceInfo->prevTimer = gGlobalTimer;
static void scale_vec3f(Vec3f dst, Vec3f src, Vec3f scale, u32 doInverted) {
if (doInverted) {
dst[0] = src[0] / scale[0];
dst[1] = src[1] / scale[1];
dst[2] = src[2] / scale[2];
} else {
dst[0] = src[0] * scale[0];
dst[1] = src[1] * scale[1];
dst[2] = src[2] * scale[2];
}
} }
/** /**
@@ -99,74 +93,48 @@ static void scale_vec3f(Vec3f dst, Vec3f src, Vec3f scale, u32 doInverted) {
* platform. * platform.
*/ */
void apply_platform_displacement(struct PlatformDisplacementInfo *displaceInfo, Vec3f pos, s16 *yaw, struct Object *platform) { void apply_platform_displacement(struct PlatformDisplacementInfo *displaceInfo, Vec3f pos, s16 *yaw, struct Object *platform) {
Vec3f platformPos;
Vec3f posDifference; Vec3f posDifference;
Vec3f yawVec; Vec3f yawVec;
Vec3f scaledPos; Vec3f scaledPos;
// Determine how much Mario turned on his own since last frame // Determine how much Mario turned on his own since last frame
s16 yawDifference = *yaw - displaceInfo->prevYaw; s16 yawDifference = *yaw - displaceInfo->prevYaw;
// Avoid a crash if the platform unloaded its collision while stood on // Avoid a crash if the platform unloaded its collision while stood on or is static
if (platform->header.gfx.throwMatrix == NULL) return; if (platform->header.gfx.throwMatrix == NULL) return;
vec3f_copy(platformPos, (*platform->header.gfx.throwMatrix)[3]);
// Determine how far Mario moved on his own since last frame // Determine how far Mario moved on his own since last frame
vec3f_copy(posDifference, pos); vec3_diff(posDifference, pos, displaceInfo->prevPos);
vec3f_sub(posDifference, displaceInfo->prevPos);
if ((platform == displaceInfo->prevPlatform) && (gGlobalTimer == displaceInfo->prevTimer + 1)) { if ((platform == displaceInfo->prevPlatform) && (gGlobalTimer == displaceInfo->prevTimer + 1)) {
// Transform from relative positions to world positions // For certain objects, only use velocity for displacement rather than the transform
scale_vec3f(scaledPos, displaceInfo->prevTransformedPos, platform->header.gfx.scale, FALSE); // E.g. TTC treadmills
linear_mtxf_mul_vec3f(*platform->header.gfx.throwMatrix, pos, scaledPos); if (platform->oFlags & OBJ_FLAG_NO_AUTO_DISPLACEMENT) {
pos[0] += platform->oVelX;
pos[1] += platform->oVelY;
pos[2] += platform->oVelZ;
} else {
// Transform from relative positions to world positions
vec3_prod(scaledPos, displaceInfo->prevTransformedPos, platform->header.gfx.scale);
linear_mtxf_mul_vec3(*platform->header.gfx.throwMatrix, pos, scaledPos);
vec3_add(pos, (*platform->header.gfx.throwMatrix)[3]);
// Add on how much Mario moved in the previous frame // Add on how much Mario moved in the previous frame
vec3f_add(pos, posDifference); vec3_add(pos, posDifference);
// Calculate new yaw // Calculate new yaw
linear_mtxf_mul_vec3f(*platform->header.gfx.throwMatrix, yawVec, displaceInfo->prevTransformedYawVec); linear_mtxf_mul_vec3(*platform->header.gfx.throwMatrix, yawVec, displaceInfo->prevTransformedYawVec);
*yaw = atan2s(yawVec[2], yawVec[0]) + yawDifference; *yaw = atan2s(yawVec[2], yawVec[0]) + yawDifference;
} else {
// First frame of standing on the platform, don't calculate a new position
vec3f_sub(pos, platformPos);
}
// Apply velocity-based displacement for certain objects (like the TTC Treadmills)
if (platform->oFlags & OBJ_FLAG_VELOCITY_PLATFORM) {
pos[0] += platform->oVelX;
pos[1] += platform->oVelY;
pos[2] += platform->oVelZ;
}
// Transform from world positions to relative positions for use next frame
linear_mtxf_transpose_mul_vec3f(*platform->header.gfx.throwMatrix, scaledPos, pos);
scale_vec3f(displaceInfo->prevTransformedPos, scaledPos, platform->header.gfx.scale, TRUE);
vec3f_add(pos, platformPos);
// If the object is Mario, set inertia
if (pos == gMarioState->pos) {
vec3f_copy(sMarioAmountDisplaced, pos);
vec3f_sub(sMarioAmountDisplaced, displaceInfo->prevPos);
vec3f_sub(sMarioAmountDisplaced, posDifference);
// Make sure inertia isn't set on the first frame otherwise the previous value isn't cleared
if ((platform != displaceInfo->prevPlatform) || (gGlobalTimer != displaceInfo->prevTimer + 1)) {
vec3_zero(sMarioAmountDisplaced);
} }
} }
// Update info for next frame Vec3f oldPos;
// Update position vec3_sum(oldPos, displaceInfo->prevPos, posDifference);
vec3f_copy(displaceInfo->prevPos, pos); update_platform_displacement_info(displaceInfo, pos, *yaw, platform);
// Set yaw info // If the object is Mario, set inertia
vec3f_set(yawVec, sins(*yaw), 0, coss(*yaw)); if (pos == gMarioState->pos) {
linear_mtxf_transpose_mul_vec3f(*platform->header.gfx.throwMatrix, displaceInfo->prevTransformedYawVec, yawVec); vec3_diff(sMarioAmountDisplaced, pos, oldPos);
displaceInfo->prevYaw = *yaw; }
// Update platform and timer
displaceInfo->prevPlatform = platform;
displaceInfo->prevTimer = gGlobalTimer;
} }
// Doesn't change in the code, set this to FALSE if you don't want inertia // Doesn't change in the code, set this to FALSE if you don't want inertia
@@ -223,93 +191,6 @@ void apply_mario_platform_displacement(void) {
} }
} }
#else
/**
* Apply one frame of platform rotation to Mario or an object using the given
* platform. If isMario is false, use gCurrentObject.
*/
void apply_platform_displacement(u32 isMario, struct Object *platform) {
f32 x, y, z;
f32 platformPosX, platformPosY, platformPosZ;
Vec3f currentObjectOffset;
Vec3f relativeOffset;
Vec3f newObjectOffset;
Vec3s rotation;
Mat4 displaceMatrix;
rotation[0] = platform->oAngleVelPitch;
rotation[1] = platform->oAngleVelYaw;
rotation[2] = platform->oAngleVelRoll;
if (isMario) {
get_mario_pos(&x, &y, &z);
} else {
x = gCurrentObject->oPosX;
y = gCurrentObject->oPosY;
z = gCurrentObject->oPosZ;
}
x += platform->oVelX;
z += platform->oVelZ;
if (rotation[0] != 0 || rotation[1] != 0 || rotation[2] != 0) {
// unusedPitch = rotation[0];
// unusedRoll = rotation[2];
// unusedYaw = platform->oFaceAngleYaw;
if (isMario) {
gMarioStates[0].faceAngle[1] += rotation[1];
}
platformPosX = platform->oPosX;
platformPosY = platform->oPosY;
platformPosZ = platform->oPosZ;
currentObjectOffset[0] = x - platformPosX;
currentObjectOffset[1] = y - platformPosY;
currentObjectOffset[2] = z - platformPosZ;
rotation[0] = platform->oFaceAnglePitch - platform->oAngleVelPitch;
rotation[1] = platform->oFaceAngleYaw - platform->oAngleVelYaw;
rotation[2] = platform->oFaceAngleRoll - platform->oAngleVelRoll;
mtxf_rotate_zxy_and_translate(displaceMatrix, currentObjectOffset, rotation);
linear_mtxf_transpose_mul_vec3f(displaceMatrix, relativeOffset, currentObjectOffset);
rotation[0] = platform->oFaceAnglePitch;
rotation[1] = platform->oFaceAngleYaw;
rotation[2] = platform->oFaceAngleRoll;
mtxf_rotate_zxy_and_translate(displaceMatrix, currentObjectOffset, rotation);
linear_mtxf_mul_vec3f(displaceMatrix, newObjectOffset, relativeOffset);
x = platformPosX + newObjectOffset[0];
y = platformPosY + newObjectOffset[1];
z = platformPosZ + newObjectOffset[2];
}
if (isMario) {
set_mario_pos(x, y, z);
} else {
gCurrentObject->oPosX = x;
gCurrentObject->oPosY = y;
gCurrentObject->oPosZ = z;
}
}
/**
* If Mario's platform is not null, apply platform displacement.
*/
void apply_mario_platform_displacement(void) {
struct Object *platform = gMarioPlatform;
if (!(gTimeStopState & TIME_STOP_ACTIVE) && gMarioObject != NULL && platform != NULL) {
apply_platform_displacement(TRUE, platform);
}
}
#endif
/** /**
* Set Mario's platform to NULL. * Set Mario's platform to NULL.
*/ */

View File

@@ -6,24 +6,19 @@
#include "types.h" #include "types.h"
#include "config.h" #include "config.h"
#ifdef PLATFORM_DISPLACEMENT_2
struct PlatformDisplacementInfo { struct PlatformDisplacementInfo {
Vec3f prevPos; Vec3f prevPos;
Vec3f prevTransformedPos; Vec3f prevTransformedPos;
Vec3f prevTransformedYawVec; Vec3f prevTransformedYawVec;
s16 prevYaw; s16 prevYaw;
struct Object *prevPlatform; struct Object *prevPlatform;
s32 prevTimer; u32 prevTimer;
}; };
#endif
void update_mario_platform(void); void update_mario_platform(void);
void get_mario_pos(f32 *x, f32 *y, f32 *z); void update_platform_displacement_info(struct PlatformDisplacementInfo *displaceInfo, Vec3f pos, s16 yaw, struct Object *platform);
void set_mario_pos(f32 x, f32 y, f32 z);
#ifdef PLATFORM_DISPLACEMENT_2
void apply_platform_displacement(struct PlatformDisplacementInfo *displaceInfo, Vec3f pos, s16 *yaw, struct Object *platform); void apply_platform_displacement(struct PlatformDisplacementInfo *displaceInfo, Vec3f pos, s16 *yaw, struct Object *platform);
#else
void apply_platform_displacement(u32 isMario, struct Object *platform);
#endif
void apply_mario_platform_displacement(void); void apply_mario_platform_displacement(void);
void clear_mario_platform(void); void clear_mario_platform(void);