Get animation working with cutscenes and get switch object workings

This commit is contained in:
James Lambert 2023-01-02 20:10:29 -07:00
parent 7f965d28f3
commit 8d0be1c12a
14 changed files with 124 additions and 28 deletions

Binary file not shown.

View file

@ -53,6 +53,12 @@ local function raw(value)
return setmetatable({ value = value}, RawType)
end
RawType.__index = RawType;
function RawType.__tostring(raw)
return 'raw(' .. raw.value .. ')'
end
--- renders a string directly in the ouptut instead of wrapping the output in quotes
---@function raw
---@tparam string value

View file

@ -42,6 +42,24 @@ local function quaternion(x, y, z, w)
return setmetatable({ x = x, y = y, z = z, w = w }, Quaternion)
end
--- creates a new quaternion with an axis and an angle in radians
--- @function quaternion
--- @tparam Vector3 axis
--- @tparam number angle
--- @treturn Quaternion
local function axis_angle(axis, angle)
local normalized_axis = axis:normalized()
local cos_angle = math.cos(angle * 0.5)
local sin_angle = math.sin(angle * 0.5)
return quaternion(
normalized_axis.x * sin_angle,
normalized_axis.y * sin_angle,
normalized_axis.z * sin_angle,
cos_angle
)
end
--- determines if the input is a Quaternion
--- @function isQuaternion
--- @tparam any obj
@ -406,5 +424,6 @@ return {
Box3 = Box3,
Quaternion = Quaternion,
quaternion = quaternion,
axis_angle = axis_angle,
isQuaternion = isQuaternion,
}

View file

@ -14,6 +14,7 @@
#define COLLISION_OBJECT_HAS_CONTACTS (1 << 0)
#define COLLISION_OBJECT_PLAYER_STANDING (1 << 1)
#define COLLISION_OBJECT_INTERACTED (1 << 2)
typedef void (*TriggerCallback)(void* data, struct CollisionObject* objectEnteringTrigger);

View file

@ -197,13 +197,17 @@ void playerUpdateGrabbedObject(struct Player* player) {
player->collisionObject.collisionLayers = 0;
if (collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_GRABBABLE | COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, &hit) && hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable)) {
player->grabbing = hit.object;
if (collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_GRABBABLE | COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, &hit)) {
hit.object->flags |= COLLISION_OBJECT_INTERACTED;
if (hit.throughPortal) {
player->grabbingThroughPortal = hit.throughPortal == gCollisionScene.portalTransforms[0] ? 0 : 1;
} else {
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
if (hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable)) {
player->grabbing = hit.object;
if (hit.throughPortal) {
player->grabbingThroughPortal = hit.throughPortal == gCollisionScene.portalTransforms[0] ? 0 : 1;
} else {
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
}
}
}

View file

@ -21,7 +21,7 @@ struct Vector2 gButtonCylinderEdgeVectors[] = {
struct CollisionQuad gButtonCylinderFaces[8];
struct CollisionCylinder gButtonCylinder = {
0.1f,
0.5f,
0.3f,
gButtonCylinderEdgeVectors,
sizeof(gButtonCylinderEdgeVectors) / sizeof(*gButtonCylinderEdgeVectors),

View file

@ -55,7 +55,7 @@ void signalsSend(unsigned signalIndex) {
return;
}
gSignals[bin] = (gSignals[bin] & ~mask) | (gDefaultSignals[bin] ^ mask);
gSignals[bin] = (gSignals[bin] & ~mask) | ((gDefaultSignals[bin] ^ mask) & mask);
}
void signalsSetDefault(unsigned signalIndex, int value) {

View file

@ -10,7 +10,7 @@
#include "../util/time.h"
#define COLLIDER_HEIGHT 7.0f
#define COLLIDER_HEIGHT 0.7f
struct Vector2 gSwitchCylinderEdgeVectors[] = {
{0.0f, 1.0f},
@ -22,7 +22,7 @@ struct Vector2 gSwitchCylinderEdgeVectors[] = {
struct CollisionQuad gSwitchCylinderFaces[8];
struct CollisionCylinder gSwitchCylinder = {
0.5f,
0.1f,
COLLIDER_HEIGHT * 0.5f,
gSwitchCylinderEdgeVectors,
sizeof(gSwitchCylinderEdgeVectors) / sizeof(*gSwitchCylinderEdgeVectors),
@ -94,7 +94,25 @@ void switchInit(struct Switch* switchObj, struct SwitchDefinition* definition) {
switchObj->timeLeft = 0.0f;
}
void switchActivate(struct Switch* switchObj) {
if (switchObj->timeLeft > 0.0f) {
return;
}
switchObj->flags |= SwitchFlagsDepressed;
switchObj->timeLeft = switchObj->duration;
signalsSend(switchObj->signalIndex);
skAnimatorRunClip(&switchObj->animator, &props_switch001_Armature_down_clip, 0.0f, 0);
}
void switchUpdate(struct Switch* switchObj) {
skAnimatorUpdate(&switchObj->animator, switchObj->armature.pose, FIXED_DELTA_TIME);
if (switchObj->collisionObject.flags & COLLISION_OBJECT_INTERACTED) {
switchActivate(switchObj);
switchObj->collisionObject.flags &= ~COLLISION_OBJECT_INTERACTED;
}
if (switchObj->timeLeft <= 0.0f) {
if ((switchObj->flags & SwitchFlagsDepressed) != 0 &&
!skAnimatorIsRunning(&switchObj->animator)) {
@ -112,15 +130,4 @@ void switchUpdate(struct Switch* switchObj) {
} else {
signalsSend(switchObj->signalIndex);
}
}
void switchActivate(struct Switch* switchObj) {
if (switchObj->timeLeft > 0.0f) {
return;
}
switchObj->flags |= SwitchFlagsDepressed;
switchObj->timeLeft = switchObj->duration;
signalsSend(switchObj->signalIndex);
skAnimatorRunClip(&switchObj->animator, &props_switch001_Armature_down_clip, 0.0f, 0);
}

View file

@ -58,6 +58,10 @@ void skAnimatorRequestFrame(struct SKAnimator* animator, int nextFrame) {
return;
}
if (nextFrame < 0 || nextFrame >= currentClip->nFrames) {
return;
}
if (animator->nextFrameStateIndex == -1) {
animator->nextFrameStateIndex = 0;
}
@ -163,6 +167,18 @@ int skAnimatorBoneStateIndexOfFrame(struct SKAnimator* animator, int frame) {
return -1;
}
int skAnimatorClampFrame(struct SKAnimator* animator, int frame) {
if (frame < animator->currentClip->nFrames) {
return frame;
}
if (animator->flags & SKAnimatorFlagsLoop) {
return frame - animator->currentClip->nFrames;
}
return animator->currentClip->nFrames - 1;
}
void skAnimatorStep(struct SKAnimator* animator, float deltaTime) {
struct SKAnimationClip* currentClip = animator->currentClip;
@ -175,7 +191,12 @@ void skAnimatorStep(struct SKAnimator* animator, float deltaTime) {
float duration = currentClip->nFrames / currentClip->fps;
if (animator->currentTime >= duration || animator->currentTime < 0.0f) {
animator->currentTime = mathfMod(animator->currentTime, duration);
if (animator->flags & SKAnimatorFlagsLoop) {
animator->currentTime = mathfMod(animator->currentTime, duration);
} else {
animator->currentTime = minf(duration, maxf(0.0f, animator->currentTime));
animator->flags |= SKAnimatorFlagsDone;
}
}
float currentFrameFractional = animator->currentTime * currentClip->fps;
@ -183,9 +204,8 @@ void skAnimatorStep(struct SKAnimator* animator, float deltaTime) {
int nextFrame = (int)ceilf(currentFrameFractional);
float lerpValue = currentFrameFractional - prevFrame;
if (nextFrame >= currentClip->nFrames) {
nextFrame -= currentClip->nFrames;
}
prevFrame = skAnimatorClampFrame(animator, prevFrame);
nextFrame = skAnimatorClampFrame(animator, nextFrame);
if (nextFrame == prevFrame) {
lerpValue = 1.0f;
@ -244,6 +264,11 @@ void skAnimatorUpdate(struct SKAnimator* animator, struct Transform* transforms,
skAnimatorReadTransform(animator, transforms);
if (animator->flags & SKAnimatorFlagsDone) {
animator->currentClip = NULL;
return;
}
skAnimatorStep(animator, deltaTime);
}

View file

@ -6,6 +6,7 @@
enum SKAnimatorFlags {
SKAnimatorFlagsLoop = (1 << 0),
SKAnimatorFlagsDone = (1 << 1),
};
struct SKAnimator {

View file

@ -49,4 +49,6 @@ sk_definition_writer.add_definition("level", "struct LevelDefinition", "_geo", {
signalOperatorCount = #signals.operators,
animations = sk_definition_writer.reference_to(animation.animated_nodes, 1),
animationInfoCount = #animation.animated_nodes,
switches = sk_definition_writer.reference_to(entities.switches, 1),
switchCount = #entities.switches,
})

View file

@ -33,6 +33,16 @@ table.sort(armatures, function(a, b)
return a.name < b.name
end)
local function parse_animation_name(name)
local _, str_end = string.find(name, '|')
if str_end then
return string.sub(name, str_end + 1)
end
return name
end
local animated_nodes = {}
for index, armature in pairs(armatures) do
@ -58,7 +68,7 @@ for index, armature in pairs(armatures) do
sk_definition_writer.add_macro(armature.name .. '_' .. animation.name, tostring(#animation_clips))
table.insert(animation_clips, clip)
animation_names[animation.name] = sk_definition_writer.raw(sk_definition_writer.add_macro(armature.name .. '_ANIMATION_' .. animation.name, animation_index - 1))
animation_names[parse_animation_name(animation.name)] = sk_definition_writer.raw(sk_definition_writer.add_macro(armature.name .. '_ANIMATION_' .. animation.name, animation_index - 1))
end
sk_definition_writer.add_definition(armature.name .. '_clips', 'struct SKAnimationClip[]', '_geo', animation_clips)
@ -87,7 +97,7 @@ end
local function get_animation_with_name(armature_name, animation_name)
local armature = animation_indices_by_name[armature_name]
if not armature then
return nil
end

View file

@ -1,6 +1,7 @@
local sk_definition_writer = require('sk_definition_writer')
local sk_scene = require('sk_scene')
local sk_math = require('sk_math')
local room_export = require('tools.level_scripts.room_export')
local trigger = require('tools.level_scripts.trigger')
local world = require('tools.level_scripts.world')
@ -154,6 +155,25 @@ end
sk_definition_writer.add_definition('signage', 'struct SignageDefinition[]', '_geo', signage)
local switches = {}
for _, switch_element in pairs(sk_scene.nodes_for_type('@switch')) do
local position, rotation = switch_element.node.full_transformation:decompose()
local room_index = room_export.node_nearest_room_index(switch_element.node)
table.insert(switches, {
position,
rotation * sk_math.axis_angle(sk_math.vector3(1, 0, 0), math.pi * 0.5),
room_index,
signals.signal_index_for_name(switch_element.arguments[1]),
switch_element.arguments[2] and tonumber(switch_element.arguments[2]) or 0,
})
end
sk_definition_writer.add_definition('switches', 'struct SwitchDefinition[]', '_geo', switches)
return {
box_droppers = box_droppers,
buttons = buttons,
@ -163,4 +183,5 @@ return {
fizzlers = fizzlers,
pedestals = pedestals,
signage = signage,
switches = switches,
}

View file

@ -159,7 +159,7 @@ local function generate_cutscene_step(step, step_index, label_locations, cutscen
elseif step.command == "goto" and #step.args >= 1 then
result.type = sk_definition_writer.raw('CutsceneStepTypeGoto')
result.gotoStep = {
label_locations[step.args[1]] - step_index - 1,
label_locations[step.args[1]] - step_index,
}
elseif step.command == "start_cutscene" and #step.args >= 1 then
result.type = sk_definition_writer.raw('CutsceneStepTypeStartCutscene')