mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 13:23:56 -07:00
Refs2eac4af3a4, refs56bb858802,91ad17c685,72bd886f80. Differential Revision: https://code.wildfiregames.com/D5110 This was SVN commit r27818.
135 lines
4.3 KiB
C++
135 lines
4.3 KiB
C++
/* Copyright (C) 2023 Wildfire Games.
|
||
* This file is part of 0 A.D.
|
||
*
|
||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation, either version 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* 0 A.D. is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#ifndef INCLUDED_UNITANIMATION
|
||
#define INCLUDED_UNITANIMATION
|
||
|
||
#include "ps/CStr.h"
|
||
#include "simulation2/system/Entity.h"
|
||
|
||
#include <vector>
|
||
|
||
class CUnit;
|
||
class CModel;
|
||
class CSkeletonAnim;
|
||
class CObjectEntry;
|
||
|
||
/**
|
||
* Deals with synchronisation issues between raw animation data (CModel, CSkeletonAnim)
|
||
* and the simulation system (via CUnit), providing a simple fire-and-forget API to play animations.
|
||
* (This is really just a component of CUnit and could probably be merged back into that class.)
|
||
*/
|
||
class CUnitAnimation
|
||
{
|
||
NONCOPYABLE(CUnitAnimation);
|
||
public:
|
||
/**
|
||
* Construct for a given unit, defaulting to the "idle" animation.
|
||
*/
|
||
CUnitAnimation(entity_id_t ent, CModel* model, CObjectEntry* object);
|
||
|
||
/**
|
||
* Start playing an animation.
|
||
* The unit's actor defines the available animations, and if more than one is available
|
||
* then one is picked at random (with a new random choice each loop).
|
||
* By default, animations start immediately and run at the given speed with no syncing.
|
||
* Use SetAnimationSync after this to force a specific timing, if it needs to match the
|
||
* simulation timing.
|
||
* Alternatively, set @p desync to a non-zero value (e.g. 0.05) to slightly randomise the
|
||
* offset and speed, so units don't all move in lockstep.
|
||
* @param name animation's name ("idle", "walk", etc)
|
||
* @param once if true then the animation freezes on its last frame; otherwise it loops
|
||
* @param speed fraction of actor-defined speed to play back at (should typically be 1.0)
|
||
* @param desync maximum fraction of length/speed to randomly adjust timings (or 0.0 for no desyncing)
|
||
* @param actionSound sound group name to be played at the 'action' point in the animation, or empty string
|
||
*/
|
||
void SetAnimationState(const CStr& name, bool once, float speed, float desync, const CStrW& actionSound);
|
||
|
||
/**
|
||
* Adjust the speed of the current animation, so that Update(repeatTime) will do a
|
||
* complete animation loop.
|
||
* @param repeatTime time for complete loop of animation, in msec
|
||
*/
|
||
void SetAnimationSyncRepeat(float repeatTime);
|
||
|
||
/**
|
||
* Adjust the offset of the current animation, so that Update(actionTime) will advance it
|
||
* to the 'action' point defined in the actor.
|
||
* This must be called after SetAnimationSyncRepeat sets the speed.
|
||
* @param actionTime time between now and when the action should occur, in msec
|
||
*/
|
||
void SetAnimationSyncOffset(float actionTime);
|
||
|
||
/**
|
||
* Advance the animation state.
|
||
* @param time advance time in msec
|
||
*/
|
||
void Update(float time);
|
||
|
||
/**
|
||
* Regenerate internal animation state from the models in the current unit.
|
||
* This should be called whenever the unit is changed externally, to keep this in sync.
|
||
*/
|
||
void ReloadUnit(CModel* model, const CObjectEntry* object);
|
||
|
||
/**
|
||
* Reload animation so any changes take immediate effect.
|
||
*/
|
||
void ReloadAnimation();
|
||
|
||
private:
|
||
|
||
/**
|
||
* Picks a new animation ID from our current state
|
||
*/
|
||
void PickAnimationID();
|
||
|
||
struct SModelAnimState
|
||
{
|
||
CModel* model;
|
||
CSkeletonAnim* anim;
|
||
const CObjectEntry* object;
|
||
float time;
|
||
bool pastLoadPos;
|
||
bool pastActionPos;
|
||
bool pastSoundPos;
|
||
};
|
||
|
||
std::vector<SModelAnimState> m_AnimStates;
|
||
|
||
/**
|
||
* True if all the current AnimStates are static, so Update() doesn't need
|
||
* to do any work at all
|
||
*/
|
||
bool m_AnimStatesAreStatic;
|
||
|
||
void AddModel(CModel* model, const CObjectEntry* object);
|
||
|
||
entity_id_t m_Entity;
|
||
CModel* m_Model;
|
||
const CObjectEntry* m_Object;
|
||
CStr m_State;
|
||
CStr m_AnimationID = "";
|
||
bool m_Looping;
|
||
float m_OriginalSpeed;
|
||
float m_Speed;
|
||
float m_SyncRepeatTime;
|
||
float m_Desync;
|
||
CStrW m_ActionSound;
|
||
};
|
||
|
||
#endif // INCLUDED_UNITANIMATION
|