Compare commits
2 Commits
45025b6682
...
0060c2a00a
| Author | SHA1 | Date | |
|---|---|---|---|
| 0060c2a00a | |||
| b3e026af24 |
@@ -0,0 +1,105 @@
|
|||||||
|
#ifndef ANIMATOR_CLASS
|
||||||
|
#define ANIMATOR_CLASS
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
|
#include "Rig.h"
|
||||||
|
|
||||||
|
// Scale of the "Head" bone (and what hangs off it), around the neck. 1 = as authored.
|
||||||
|
inline float HeadScale = 1.0f;
|
||||||
|
|
||||||
|
struct AssimpNodeData
|
||||||
|
{
|
||||||
|
glm::mat4 transformation;
|
||||||
|
std::string name;
|
||||||
|
int childrenCount;
|
||||||
|
std::vector<AssimpNodeData> children;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Animation
|
||||||
|
// ============================================================================
|
||||||
|
class Animation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Animation() = default;
|
||||||
|
|
||||||
|
Animation(const std::string& animationPath, Rig* rig = nullptr)
|
||||||
|
{
|
||||||
|
Assimp::Importer importer;
|
||||||
|
const aiScene* scene = importer.ReadFile(animationPath, aiProcess_Triangulate);
|
||||||
|
assert(scene && scene->mRootNode);
|
||||||
|
|
||||||
|
const aiAnimation* anim = scene->mAnimations[0];
|
||||||
|
m_Duration = (float)anim->mDuration;
|
||||||
|
m_TicksPerSecond = (int)(anim->mTicksPerSecond != 0 ? anim->mTicksPerSecond : 24);
|
||||||
|
|
||||||
|
ReadHierarchyData(m_RootNode, scene->mRootNode);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < anim->mNumChannels; i++) {
|
||||||
|
const aiNodeAnim* channel = anim->mChannels[i];
|
||||||
|
m_Bones.emplace_back(channel->mNodeName.data, 0, channel);
|
||||||
|
m_BoneNames.push_back(channel->mNodeName.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rig) RegisterBonesWithRig(*rig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterBonesWithRig(Rig& rig)
|
||||||
|
{
|
||||||
|
for (const std::string& name : m_BoneNames) {
|
||||||
|
if (rig.m_BoneInfoMap.find(name) == rig.m_BoneInfoMap.end()) {
|
||||||
|
BoneInfo info;
|
||||||
|
info.id = rig.m_BoneCounter++;
|
||||||
|
info.offset = glm::mat4(1.0f);
|
||||||
|
rig.m_BoneInfoMap[name] = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bone* FindBone(const std::string& name)
|
||||||
|
{
|
||||||
|
for (Bone& b : m_Bones)
|
||||||
|
if (b.GetBoneName() == name) return &b;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetTicksPerSecond() const { return (float)m_TicksPerSecond; }
|
||||||
|
float GetDuration() const { return m_Duration; }
|
||||||
|
const AssimpNodeData& GetRootNode() const { return m_RootNode; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
float m_Duration = 0.0f;
|
||||||
|
int m_TicksPerSecond = 24;
|
||||||
|
std::vector<Bone> m_Bones;
|
||||||
|
std::vector<std::string> m_BoneNames;
|
||||||
|
AssimpNodeData m_RootNode;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ReadHierarchyData(AssimpNodeData& dest, const aiNode* src)
|
||||||
|
{
|
||||||
|
assert(src);
|
||||||
|
dest.name = src->mName.data;
|
||||||
|
dest.transformation = AssimpGLMHelpers::ConvertMatrixToGLMFormat(src->mTransformation);
|
||||||
|
dest.childrenCount = (int)src->mNumChildren;
|
||||||
|
for (unsigned int i = 0; i < src->mNumChildren; i++) {
|
||||||
|
AssimpNodeData child;
|
||||||
|
ReadHierarchyData(child, src->mChildren[i]);
|
||||||
|
dest.children.push_back(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Animator
|
||||||
|
// blendWeight ramps from 0?1 over blendDuration when PlayAnimation is called.
|
||||||
|
// CharacterBody::GetBlendedBoneMatrices() lerps all animators by blendWeight.
|
||||||
|
// ============================================================================
|
||||||
|
class Animator
|
||||||
|
{
|
||||||
|
public:
|
||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
#include "Rig.h"
|
#include "Rig.h"
|
||||||
|
|
||||||
// Scale of the "Head" bone (and what hangs off it), around the neck. 1 = as authored.
|
// Scale of the "Head" bone (and what hangs off it), around the neck. 1 = as authored.
|
||||||
inline float HeadScale = 0.25f;
|
inline float HeadScale = 1.0f;
|
||||||
|
|
||||||
struct AssimpNodeData
|
struct AssimpNodeData
|
||||||
{
|
{
|
||||||
|
|||||||
+10
-4
@@ -384,16 +384,17 @@ void Engine::Initiate()
|
|||||||
pos.z - size.z * 0.5f, pos.z + size.z * 0.5f });
|
pos.z - size.z * 0.5f, pos.z + size.z * 0.5f });
|
||||||
};
|
};
|
||||||
// Concentric stack of square tiers, widest at the bottom (stands in for dome / cone)
|
// Concentric stack of square tiers, widest at the bottom (stands in for dome / cone)
|
||||||
auto AddTiers = [&](const char* name, glm::vec2 pos, float baseWidth, float tierHeight, int tiers) {
|
// xStretch scales the stack along x only (left/right); height and depth are unchanged
|
||||||
|
auto AddTiers = [&](const char* name, glm::vec2 pos, float baseWidth, float tierHeight, int tiers, float xStretch = 1.0f) {
|
||||||
for (int i = 0; i < tiers; ++i) {
|
for (int i = 0; i < tiers; ++i) {
|
||||||
const float w = baseWidth * (1.0f - float(i) / float(tiers));
|
const float w = baseWidth * (1.0f - float(i) / float(tiers));
|
||||||
AddBlock(name, { pos.x, tierHeight * i, pos.y }, { w, tierHeight, w });
|
AddBlock(name, { pos.x, tierHeight * i, pos.y }, { w * xStretch, tierHeight, w });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Map is a rectangle: x in [-60, 60], z in [-30, 30] (authored at 1x, scaled by mapScale)
|
// Map is a rectangle: x in [-60, 60], z in [-30, 30] (authored at 1x, scaled by mapScale)
|
||||||
// Centre dome
|
// Centre dome
|
||||||
AddTiers("dome", { 0.0f, 0.0f }, 18.0f, 2.0f, 5);
|
AddTiers("dome", { 0.0f, 0.0f }, 18.0f, 2.0f, 5, 0.5f);
|
||||||
// Cones, opposite corners of the dome
|
// Cones, opposite corners of the dome
|
||||||
AddTiers("cone", { -12.0f, -13.0f }, 6.0f, 1.0f, 5);
|
AddTiers("cone", { -12.0f, -13.0f }, 6.0f, 1.0f, 5);
|
||||||
AddTiers("cone", { 12.0f, 13.0f }, 6.0f, 1.0f, 5);
|
AddTiers("cone", { 12.0f, 13.0f }, 6.0f, 1.0f, 5);
|
||||||
@@ -575,7 +576,7 @@ void Engine::Initiate()
|
|||||||
const int maxHealth = 100;
|
const int maxHealth = 100;
|
||||||
const int bodyDamage = 50;
|
const int bodyDamage = 50;
|
||||||
const int punchDamage = 25;
|
const int punchDamage = 25;
|
||||||
const float headFraction = 0.8f;
|
const float headFraction = 0.93f; // top 7% of the hitbox counts as the head
|
||||||
|
|
||||||
// Random respawn spot on the floor (NPC and player), kept clear of every map prop
|
// Random respawn spot on the floor (NPC and player), kept clear of every map prop
|
||||||
std::mt19937 respawnRng(std::random_device{}());
|
std::mt19937 respawnRng(std::random_device{}());
|
||||||
@@ -1089,6 +1090,10 @@ void Engine::Initiate()
|
|||||||
m->t.ScaleTo(1.0f);
|
m->t.ScaleTo(1.0f);
|
||||||
m->BindToRenderSystem();
|
m->BindToRenderSystem();
|
||||||
mainf->AddChild(m);
|
mainf->AddChild(m);
|
||||||
|
// Solid for the local player, but moved only by the host's stream (like the floor, never simulated here)
|
||||||
|
p* cubeBody = new p(m);
|
||||||
|
cubeBody->velocity = false;
|
||||||
|
physicsengine->AddObject(cubeBody);
|
||||||
it = puppetCubes.emplace(nc.id, PuppetCube{ m, now }).first;
|
it = puppetCubes.emplace(nc.id, PuppetCube{ m, now }).first;
|
||||||
}
|
}
|
||||||
it->second.mesh->t.TranslateTo(nc.position);
|
it->second.mesh->t.TranslateTo(nc.position);
|
||||||
@@ -1098,6 +1103,7 @@ void Engine::Initiate()
|
|||||||
for (auto it = puppetCubes.begin(); it != puppetCubes.end();) {
|
for (auto it = puppetCubes.begin(); it != puppetCubes.end();) {
|
||||||
if (now - it->second.lastSeen > 1.5) {
|
if (now - it->second.lastSeen > 1.5) {
|
||||||
rendersystem->RemoveRenderable(it->second.mesh);
|
rendersystem->RemoveRenderable(it->second.mesh);
|
||||||
|
physicsengine->RemoveObject(it->second.mesh);
|
||||||
it->second.mesh->Delete();
|
it->second.mesh->Delete();
|
||||||
it = puppetCubes.erase(it);
|
it = puppetCubes.erase(it);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,11 +129,9 @@ static void PromptSensitivity() {
|
|||||||
catch (...) {} // empty / not a number: keep the default
|
catch (...) {} // empty / not a number: keep the default
|
||||||
};
|
};
|
||||||
std::cout << "\n=== MOUSE ===\n";
|
std::cout << "\n=== MOUSE ===\n";
|
||||||
float cm = 0.0f, dpi = 800.0f;
|
float cm = 0.0f;
|
||||||
ask("Sensitivity in cm per 360 degrees [default]: ", cm);
|
ask("Sensitivity in cm per 360 degrees [default]: ", cm);
|
||||||
if (cm > 0.0f) ask("Mouse DPI [800]: ", dpi);
|
|
||||||
StartupCmPer360 = cm;
|
StartupCmPer360 = cm;
|
||||||
StartupMouseDpi = dpi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|||||||
Reference in New Issue
Block a user