First round of animation improvements
This commit is contained in:
@@ -6,5 +6,7 @@
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
easing.c
|
||||
keyframe.c
|
||||
keyframeset.c
|
||||
animation.c
|
||||
)
|
||||
|
||||
@@ -5,48 +5,43 @@
|
||||
|
||||
#include "animation.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/math.h"
|
||||
#include "time/time.h"
|
||||
|
||||
void animationInit(
|
||||
animation_t *anim,
|
||||
keyframe_t *keyframes,
|
||||
uint16_t keyframeCount
|
||||
keyframe_t **tracks,
|
||||
uint16_t *trackCounts,
|
||||
uint16_t trackCount
|
||||
) {
|
||||
assertNotNull(anim, "Animation pointer cannot be null.");
|
||||
assertNotNull(keyframes, "Keyframes pointer cannot be null.");
|
||||
assertTrue(keyframeCount > 0, "Keyframe count must be more than 0.");
|
||||
|
||||
anim->keyframes = keyframes;
|
||||
anim->keyframeCount = keyframeCount;
|
||||
keyframeSetInit(&anim->keyframes, tracks, trackCounts, trackCount);
|
||||
anim->time = 0.0f;
|
||||
anim->speed = 1.0f;
|
||||
anim->loop = false;
|
||||
anim->playing = false;
|
||||
}
|
||||
|
||||
float_t animationGetValue(animation_t *anim, const float_t time) {
|
||||
void animationUpdate(animation_t *anim) {
|
||||
assertNotNull(anim, "Animation pointer cannot be null.");
|
||||
assertNotNull(anim->keyframes, "Keyframes pointer cannot be null.");
|
||||
assertTrue(anim->keyframeCount > 0, "Keyframe count invalid.");
|
||||
assertTrue(time >= 0, "Time must be non-negative.");
|
||||
|
||||
keyframe_t *start;
|
||||
keyframe_t *end;
|
||||
keyframe_t *last = anim->keyframes + anim->keyframeCount - 1;
|
||||
keyframe_t *current = anim->keyframes;
|
||||
start = current;
|
||||
if(!anim->playing) return;
|
||||
|
||||
do {
|
||||
if(current->time > time) {
|
||||
end = current;
|
||||
break;
|
||||
}
|
||||
start = current;
|
||||
current++;
|
||||
float_t duration = keyframeSetGetDuration(&anim->keyframes);
|
||||
anim->time += TIME.delta * anim->speed;
|
||||
|
||||
if(current > last) {
|
||||
end = start;
|
||||
break;
|
||||
}
|
||||
} while(true);
|
||||
if(anim->loop) {
|
||||
if(duration > 0.0f) anim->time = mathModFloat(anim->time, duration);
|
||||
return;
|
||||
}
|
||||
|
||||
float_t t = (time - start->time) / (end->time - start->time);
|
||||
return mathLerp(start->value, end->value, easingApply(start->easing, t));
|
||||
}
|
||||
if(anim->time >= duration) {
|
||||
anim->time = duration;
|
||||
anim->playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
float_t animationGetValue(animation_t *anim, const uint16_t trackIndex) {
|
||||
assertNotNull(anim, "Animation pointer cannot be null.");
|
||||
return keyframeSetGetValue(&anim->keyframes, trackIndex, anim->time);
|
||||
}
|
||||
|
||||
@@ -4,31 +4,60 @@
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "keyframe.h"
|
||||
#include "keyframeset.h"
|
||||
|
||||
typedef struct {
|
||||
keyframe_t *keyframes;
|
||||
uint16_t keyframeCount;
|
||||
/** The animation's tracks/channels and their raw keyframe data. */
|
||||
keyframeset_t keyframes;
|
||||
|
||||
/** Current playback position, in seconds. */
|
||||
float_t time;
|
||||
|
||||
/** Playback rate multiplier; 1.0 = normal speed. */
|
||||
float_t speed;
|
||||
|
||||
/** True if animationUpdate() should wrap time back to 0 on reaching the
|
||||
* final keyframe, rather than holding there and clearing playing. */
|
||||
bool_t loop;
|
||||
|
||||
/** True while animationUpdate() should advance time each call. */
|
||||
bool_t playing;
|
||||
} animation_t;
|
||||
|
||||
/**
|
||||
* Initializes an animation.
|
||||
*
|
||||
* Initializes an animation: time 0, speed 1.0, not looping, not playing.
|
||||
* See keyframeSetInit() -- tracks/trackCounts and the keyframe_t arrays
|
||||
* they point to are not copied, and must outlive this animation.
|
||||
*
|
||||
* @param anim The animation to initialize.
|
||||
* @param keyframes The keyframes to use for the animation.
|
||||
* @param keyframeCount The number of keyframes in the animation.
|
||||
* @param tracks Array of trackCount keyframe_t arrays.
|
||||
* @param trackCounts Array of trackCount keyframe counts, matching tracks.
|
||||
* @param trackCount The number of tracks/channels in this animation.
|
||||
*/
|
||||
void animationInit(
|
||||
animation_t *anim,
|
||||
keyframe_t *keyframes,
|
||||
uint16_t keyframeCount
|
||||
keyframe_t **tracks,
|
||||
uint16_t *trackCounts,
|
||||
uint16_t trackCount
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the value of the animation at a given time.
|
||||
*
|
||||
* @param anim The animation to get the value from.
|
||||
* @param time The time at which to get the value, in seconds.
|
||||
* @return The value of the animation at the given time.
|
||||
* Advances an animation's time by TIME.delta * speed. No-op if not
|
||||
* playing. Duration is the latest of every track's final keyframe time
|
||||
* (see keyframeSetGetDuration()). If loop is set, time wraps back into
|
||||
* [0, duration) on reaching it; otherwise time is clamped there and
|
||||
* playing is cleared.
|
||||
*
|
||||
* @param anim The animation to update.
|
||||
*/
|
||||
float_t animationGetValue(animation_t *anim, const float_t time);
|
||||
void animationUpdate(animation_t *anim);
|
||||
|
||||
/**
|
||||
* Gets the value of one of the animation's tracks at its current
|
||||
* playback time.
|
||||
*
|
||||
* @param anim The animation to get the value from.
|
||||
* @param trackIndex The track to evaluate, in [0, trackCount).
|
||||
* @return The interpolated value of that track at the current time.
|
||||
*/
|
||||
float_t animationGetValue(animation_t *anim, const uint16_t trackIndex);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2026 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "keyframe.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/math.h"
|
||||
|
||||
float_t keyframeGetValue(
|
||||
keyframe_t *keyframes,
|
||||
const uint16_t keyframeCount,
|
||||
const float_t time
|
||||
) {
|
||||
assertNotNull(keyframes, "Keyframes pointer cannot be null.");
|
||||
assertTrue(keyframeCount > 0, "Keyframe count must be more than 0.");
|
||||
assertTrue(time >= 0, "Time must be non-negative.");
|
||||
|
||||
keyframe_t *first = keyframes;
|
||||
keyframe_t *last = keyframes + keyframeCount - 1;
|
||||
|
||||
// Clamp to the boundary keyframes' values directly rather than
|
||||
// interpolating -- start == end at either boundary would otherwise
|
||||
// divide by zero.
|
||||
if(time <= first->time) return first->value;
|
||||
if(time >= last->time) return last->value;
|
||||
|
||||
keyframe_t *start = first;
|
||||
keyframe_t *end;
|
||||
keyframe_t *current = first;
|
||||
|
||||
do {
|
||||
if(current->time > time) {
|
||||
end = current;
|
||||
break;
|
||||
}
|
||||
start = current;
|
||||
current++;
|
||||
} while(true);
|
||||
|
||||
float_t t = (time - start->time) / (end->time - start->time);
|
||||
return mathLerp(start->value, end->value, easingApply(start->easing, t));
|
||||
}
|
||||
@@ -10,4 +10,18 @@ typedef struct {
|
||||
float_t time;
|
||||
float_t value;
|
||||
easingtype_t easing;
|
||||
} keyframe_t;
|
||||
} keyframe_t;
|
||||
|
||||
/**
|
||||
* Gets the eased, interpolated value of a keyframe array at a given time.
|
||||
*
|
||||
* @param keyframes The keyframes to evaluate, ascending by time.
|
||||
* @param keyframeCount The number of keyframes.
|
||||
* @param time The time at which to get the value, in seconds.
|
||||
* @return The interpolated value at the given time.
|
||||
*/
|
||||
float_t keyframeGetValue(
|
||||
keyframe_t *keyframes,
|
||||
const uint16_t keyframeCount,
|
||||
const float_t time
|
||||
);
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2026 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "keyframeset.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
void keyframeSetInit(
|
||||
keyframeset_t *set,
|
||||
keyframe_t **tracks,
|
||||
uint16_t *trackCounts,
|
||||
uint16_t trackCount
|
||||
) {
|
||||
assertNotNull(set, "Keyframe set pointer cannot be null.");
|
||||
assertNotNull(tracks, "Tracks pointer cannot be null.");
|
||||
assertNotNull(trackCounts, "Track counts pointer cannot be null.");
|
||||
assertTrue(trackCount > 0, "Track count must be more than 0.");
|
||||
|
||||
set->tracks = tracks;
|
||||
set->trackCounts = trackCounts;
|
||||
set->trackCount = trackCount;
|
||||
}
|
||||
|
||||
float_t keyframeSetGetValue(
|
||||
keyframeset_t *set,
|
||||
const uint16_t trackIndex,
|
||||
const float_t time
|
||||
) {
|
||||
assertNotNull(set, "Keyframe set pointer cannot be null.");
|
||||
assertTrue(trackIndex < set->trackCount, "Track index out of bounds.");
|
||||
|
||||
return keyframeGetValue(
|
||||
set->tracks[trackIndex], set->trackCounts[trackIndex], time
|
||||
);
|
||||
}
|
||||
|
||||
void keyframeSetGetValues(
|
||||
keyframeset_t *set,
|
||||
const float_t time,
|
||||
float_t *outValues
|
||||
) {
|
||||
assertNotNull(set, "Keyframe set pointer cannot be null.");
|
||||
assertNotNull(outValues, "Output values pointer cannot be null.");
|
||||
|
||||
for(uint16_t i = 0; i < set->trackCount; i++) {
|
||||
outValues[i] = keyframeGetValue(set->tracks[i], set->trackCounts[i], time);
|
||||
}
|
||||
}
|
||||
|
||||
float_t keyframeSetGetDuration(keyframeset_t *set) {
|
||||
assertNotNull(set, "Keyframe set pointer cannot be null.");
|
||||
|
||||
float_t duration = 0.0f;
|
||||
for(uint16_t i = 0; i < set->trackCount; i++) {
|
||||
float_t trackDuration = set->tracks[i][set->trackCounts[i] - 1].time;
|
||||
if(trackDuration > duration) duration = trackDuration;
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2026 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "keyframe.h"
|
||||
|
||||
/**
|
||||
* A group of N parallel keyframe tracks (e.g. one per animated channel --
|
||||
* position.x/y/z, bone rotations, etc.) sharing a single timeline. Each
|
||||
* track is independent: its own keyframe array and count, evaluated at
|
||||
* whatever time is asked for.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Caller-owned array of trackCount keyframe_t arrays. */
|
||||
keyframe_t **tracks;
|
||||
/** Caller-owned array of trackCount counts, one per entry in tracks. */
|
||||
uint16_t *trackCounts;
|
||||
uint16_t trackCount;
|
||||
} keyframeset_t;
|
||||
|
||||
/**
|
||||
* Initializes a keyframe set. Neither tracks, trackCounts, nor the
|
||||
* keyframe_t arrays they point to are copied -- they must outlive this
|
||||
* keyframeset_t.
|
||||
*
|
||||
* @param set The keyframe set to initialize.
|
||||
* @param tracks Array of trackCount keyframe_t arrays.
|
||||
* @param trackCounts Array of trackCount keyframe counts, matching tracks.
|
||||
* @param trackCount The number of tracks.
|
||||
*/
|
||||
void keyframeSetInit(
|
||||
keyframeset_t *set,
|
||||
keyframe_t **tracks,
|
||||
uint16_t *trackCounts,
|
||||
uint16_t trackCount
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the value of a single track at a given time.
|
||||
*
|
||||
* @param set The keyframe set to evaluate.
|
||||
* @param trackIndex The track to evaluate, in [0, set->trackCount).
|
||||
* @param time The time at which to get the value, in seconds.
|
||||
* @return The interpolated value of that track at the given time.
|
||||
*/
|
||||
float_t keyframeSetGetValue(
|
||||
keyframeset_t *set,
|
||||
const uint16_t trackIndex,
|
||||
const float_t time
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the value of every track at a given time.
|
||||
*
|
||||
* @param set The keyframe set to evaluate.
|
||||
* @param time The time at which to get the values, in seconds.
|
||||
* @param outValues Destination array of at least set->trackCount floats.
|
||||
*/
|
||||
void keyframeSetGetValues(
|
||||
keyframeset_t *set,
|
||||
const float_t time,
|
||||
float_t *outValues
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the set's duration: the latest final-keyframe time across every
|
||||
* track, i.e. how long it takes for every track to finish.
|
||||
*
|
||||
* @param set The keyframe set to measure.
|
||||
* @return The set's duration, in seconds.
|
||||
*/
|
||||
float_t keyframeSetGetDuration(keyframeset_t *set);
|
||||
@@ -7,3 +7,4 @@
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(physics)
|
||||
add_subdirectory(trigger)
|
||||
add_subdirectory(animation)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
entityanimation.c
|
||||
)
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entityanimation.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
void entityAnimationInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
|
||||
memoryZero(animComp, sizeof(entityanimation_t));
|
||||
|
||||
entityUpdateAdd(mgr, entityId, entityAnimationUpdate, componentId, NULL);
|
||||
}
|
||||
|
||||
entityanimation_t *entityAnimationGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
return componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_ANIMATION
|
||||
);
|
||||
}
|
||||
|
||||
void entityAnimationSetKeyframes(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
keyframe_t **channelTracks,
|
||||
uint16_t *channelTrackCounts,
|
||||
const uint16_t channelCount
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
animationInit(
|
||||
&animComp->anim, channelTracks, channelTrackCounts, channelCount
|
||||
);
|
||||
}
|
||||
|
||||
void entityAnimationPlay(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
animComp->anim.time = 0.0f;
|
||||
animComp->anim.playing = true;
|
||||
}
|
||||
|
||||
void entityAnimationStop(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
animComp->anim.playing = false;
|
||||
}
|
||||
|
||||
bool_t entityAnimationIsPlaying(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
return animComp->anim.playing;
|
||||
}
|
||||
|
||||
void entityAnimationSetLoop(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const bool_t loop
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
animComp->anim.loop = loop;
|
||||
}
|
||||
|
||||
void entityAnimationSetSpeed(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const float_t speed
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
animComp->anim.speed = speed;
|
||||
}
|
||||
|
||||
float_t entityAnimationGetValue(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint16_t channelIndex
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
return animationGetValue(&animComp->anim, channelIndex);
|
||||
}
|
||||
|
||||
void entityAnimationUpdate(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
animationUpdate(&animComp->anim);
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity/entitybase.h"
|
||||
#include "animation/animation.h"
|
||||
|
||||
typedef struct {
|
||||
animation_t anim;
|
||||
} entityanimation_t;
|
||||
|
||||
/**
|
||||
* Initializes the animation component: no keyframes set, and registers
|
||||
* entityAnimationUpdate as an update callback. Call
|
||||
* entityAnimationSetKeyframes() before entityAnimationPlay().
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityAnimationInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the underlying animation structure (temporarily) for the given
|
||||
* entity. Prefer the dedicated getters/setters where possible.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The animation component data for the given entity and
|
||||
* component ID.
|
||||
*/
|
||||
entityanimation_t *entityAnimationGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the entity's keyframes, stopped, at speed 1.0, non-looping. See
|
||||
* keyframeSetInit() -- channelTracks/channelTrackCounts and the
|
||||
* keyframe_t arrays they point to are not copied, and must outlive this
|
||||
* component (e.g. static/const arrays owned by the caller).
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param channelTracks Array of channelCount keyframe_t arrays -- one per
|
||||
* animated channel (e.g. position.x/y/z), sharing this animation's
|
||||
* timeline.
|
||||
* @param channelTrackCounts Array of channelCount keyframe counts,
|
||||
* matching channelTracks.
|
||||
* @param channelCount The number of channels.
|
||||
*/
|
||||
void entityAnimationSetKeyframes(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
keyframe_t **channelTracks,
|
||||
uint16_t *channelTrackCounts,
|
||||
const uint16_t channelCount
|
||||
);
|
||||
|
||||
/**
|
||||
* Starts (or restarts) playback from time 0.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityAnimationPlay(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Stops playback without resetting the current time.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityAnimationStop(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Checks whether the animation is currently playing.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return True if playing.
|
||||
*/
|
||||
bool_t entityAnimationIsPlaying(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets whether the animation loops on reaching its final keyframe, rather
|
||||
* than stopping there.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param loop True to loop, false to stop at the end.
|
||||
*/
|
||||
void entityAnimationSetLoop(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const bool_t loop
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the animation's playback rate multiplier.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param speed The new playback rate; 1.0 = normal speed.
|
||||
*/
|
||||
void entityAnimationSetSpeed(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const float_t speed
|
||||
);
|
||||
|
||||
/**
|
||||
* Evaluates one of the animation's channels at its current playback
|
||||
* time, regardless of whether it's currently playing.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param channelIndex The channel to evaluate, in [0, channelCount) as
|
||||
* passed to entityAnimationSetKeyframes().
|
||||
* @return That channel's value at the current time.
|
||||
*/
|
||||
float_t entityAnimationGetValue(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint16_t channelIndex
|
||||
);
|
||||
|
||||
/**
|
||||
* Per-tick update for the animation component: calls animationUpdate()
|
||||
* (a no-op if not playing). Registered automatically as an update
|
||||
* callback by entityAnimationInit.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param user Unused.
|
||||
*/
|
||||
void entityAnimationUpdate(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
);
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
#include "entity/component/physics/entityphysics.h"
|
||||
#include "entity/component/trigger/entitytrigger.h"
|
||||
#include "entity/component/animation/entityanimation.h"
|
||||
|
||||
// Name (Uppercase)
|
||||
// Structure
|
||||
@@ -31,6 +32,11 @@ X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, NULL, NULL,
|
||||
entityPhysicsSerialize, entityPhysicsDeserialize)
|
||||
X(TRIGGER, entitytrigger_t, trigger, entityTriggerInit, NULL, NULL,
|
||||
entityTriggerSerialize, entityTriggerDeserialize)
|
||||
// No serialize/deserialize: the animation's keyframes are caller-owned
|
||||
// (see animationInit()), not data this component owns, so there's
|
||||
// nothing meaningful to persist to/from JSON.
|
||||
X(ANIMATION, entityanimation_t, animation, entityAnimationInit, NULL, NULL,
|
||||
NULL, NULL)
|
||||
|
||||
// Game-specific components
|
||||
#include "entity/gamecomponentlist.h"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#define ENTITY_PLAYER_MOVE_SPEED_DEFAULT 4.0f
|
||||
#define ENTITY_PLAYER_JUMP_IMPULSE_DEFAULT 6.0f
|
||||
#define ENTITY_PLAYER_TURN_SPEED_DEFAULT 10.0f
|
||||
#define ENTITY_PLAYER_TURN_SPEED_DEFAULT 15.0f
|
||||
|
||||
// Below this squared magnitude, movement input is treated as "not moving"
|
||||
// and the player keeps facing whichever way it last faced, rather than
|
||||
|
||||
Reference in New Issue
Block a user