NPC code
This commit is contained in:
parent
2e4a7ab467
commit
995e2c8e5b
@ -14,6 +14,8 @@ add_executable(space-game001
|
|||||||
../src/main.cpp
|
../src/main.cpp
|
||||||
../src/Game.cpp
|
../src/Game.cpp
|
||||||
../src/Game.h
|
../src/Game.h
|
||||||
|
../src/Character.cpp
|
||||||
|
../src/Character.h
|
||||||
../src/Environment.cpp
|
../src/Environment.cpp
|
||||||
../src/Environment.h
|
../src/Environment.h
|
||||||
../src/render/Renderer.cpp
|
../src/render/Renderer.cpp
|
||||||
|
|||||||
489481
resources/w/default_idle001.txt
Normal file
489481
resources/w/default_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
434020
resources/w/default_idle002.txt
Normal file
434020
resources/w/default_idle002.txt
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resources/w/default_skin001.png
(Stored with Git LFS)
Normal file
BIN
resources/w/default_skin001.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -450,6 +450,11 @@ namespace ZL
|
|||||||
throw std::runtime_error("No number found in the input string.");
|
throw std::runtime_error("No number found in the input string.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
startingFrame == numberFrame;
|
||||||
|
}
|
||||||
|
|
||||||
animations[0].keyFrames[i].frame = numberFrame;
|
animations[0].keyFrames[i].frame = numberFrame;
|
||||||
|
|
||||||
animations[0].keyFrames[i].bones.resize(numberBones);
|
animations[0].keyFrames[i].bones.resize(numberBones);
|
||||||
@ -609,35 +614,11 @@ namespace ZL
|
|||||||
Matrix3f oneFrameBonesMatrix;
|
Matrix3f oneFrameBonesMatrix;
|
||||||
|
|
||||||
oneFrameBonesMatrix = oneFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
oneFrameBonesMatrix = oneFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
/*
|
|
||||||
oneFrameBonesMatrix.data()[0] = oneFrameBones[i].boneMatrixWorld.m[0];
|
|
||||||
oneFrameBonesMatrix.data()[1] = oneFrameBones[i].boneMatrixWorld.m[1];
|
|
||||||
oneFrameBonesMatrix.data()[2] = oneFrameBones[i].boneMatrixWorld.m[2];
|
|
||||||
|
|
||||||
oneFrameBonesMatrix.data()[3] = oneFrameBones[i].boneMatrixWorld.m[0 + 1*4];
|
|
||||||
oneFrameBonesMatrix.data()[4] = oneFrameBones[i].boneMatrixWorld.m[1 + 1*4];
|
|
||||||
oneFrameBonesMatrix.data()[5] = oneFrameBones[i].boneMatrixWorld.m[2 + 1*4];
|
|
||||||
|
|
||||||
oneFrameBonesMatrix.data()[6] = oneFrameBones[i].boneMatrixWorld.m[0 + 2*4];
|
|
||||||
oneFrameBonesMatrix.data()[7] = oneFrameBones[i].boneMatrixWorld.m[1 + 2*4];
|
|
||||||
oneFrameBonesMatrix.data()[8] = oneFrameBones[i].boneMatrixWorld.m[2 + 2*4];
|
|
||||||
*/
|
|
||||||
Matrix3f nextFrameBonesMatrix;
|
Matrix3f nextFrameBonesMatrix;
|
||||||
|
|
||||||
nextFrameBonesMatrix = nextFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
nextFrameBonesMatrix = nextFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
/*
|
|
||||||
nextFrameBonesMatrix.data()[0] = nextFrameBones[i].boneMatrixWorld.m[0];
|
|
||||||
nextFrameBonesMatrix.data()[1] = nextFrameBones[i].boneMatrixWorld.m[1];
|
|
||||||
nextFrameBonesMatrix.data()[2] = nextFrameBones[i].boneMatrixWorld.m[2];
|
|
||||||
|
|
||||||
nextFrameBonesMatrix.data()[3] = nextFrameBones[i].boneMatrixWorld.m[0 + 1 * 4];
|
|
||||||
nextFrameBonesMatrix.data()[4] = nextFrameBones[i].boneMatrixWorld.m[1 + 1 * 4];
|
|
||||||
nextFrameBonesMatrix.data()[5] = nextFrameBones[i].boneMatrixWorld.m[2 + 1 * 4];
|
|
||||||
|
|
||||||
nextFrameBonesMatrix.data()[6] = nextFrameBones[i].boneMatrixWorld.m[0 + 2 * 4];
|
|
||||||
nextFrameBonesMatrix.data()[7] = nextFrameBones[i].boneMatrixWorld.m[1 + 2 * 4];
|
|
||||||
nextFrameBonesMatrix.data()[8] = nextFrameBones[i].boneMatrixWorld.m[2 + 2 * 4];
|
|
||||||
*/
|
|
||||||
Eigen::Quaternionf q1 = Eigen::Quaternionf(oneFrameBonesMatrix).normalized();
|
Eigen::Quaternionf q1 = Eigen::Quaternionf(oneFrameBonesMatrix).normalized();
|
||||||
Eigen::Quaternionf q2 = Eigen::Quaternionf(nextFrameBonesMatrix).normalized();
|
Eigen::Quaternionf q2 = Eigen::Quaternionf(nextFrameBonesMatrix).normalized();
|
||||||
Eigen::Quaternionf q1_norm = q1.normalized();
|
Eigen::Quaternionf q1_norm = q1.normalized();
|
||||||
|
|||||||
@ -47,6 +47,7 @@ namespace ZL
|
|||||||
std::vector<Bone> currentBones;
|
std::vector<Bone> currentBones;
|
||||||
|
|
||||||
std::vector<Animation> animations;
|
std::vector<Animation> animations;
|
||||||
|
int startingFrame = 0;
|
||||||
|
|
||||||
void LoadFromFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
void LoadFromFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||||
|
|
||||||
|
|||||||
97
src/Character.cpp
Normal file
97
src/Character.cpp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#include "Character.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
void Character::loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile) {
|
||||||
|
auto& data = animations[state];
|
||||||
|
data.model.LoadFromFile(filename, zipFile);
|
||||||
|
if (!data.model.animations.empty() && !data.model.animations[0].keyFrames.empty()) {
|
||||||
|
data.totalFrames = data.model.animations[0].keyFrames.back().frame + 1;
|
||||||
|
} else {
|
||||||
|
data.totalFrames = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Character::setTexture(std::shared_ptr<Texture> tex) {
|
||||||
|
texture = tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Character::setTarget(const Eigen::Vector3f& target) {
|
||||||
|
walkTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationState Character::resolveActiveState() const {
|
||||||
|
if (animations.count(currentState)) return currentState;
|
||||||
|
return AnimationState::IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Character::update(int64_t deltaMs) {
|
||||||
|
// Move toward walk target on the XZ plane
|
||||||
|
Eigen::Vector3f toTarget = walkTarget - position;
|
||||||
|
toTarget.y() = 0.f;
|
||||||
|
float dist = toTarget.norm();
|
||||||
|
|
||||||
|
if (dist > WALK_THRESHOLD) {
|
||||||
|
Eigen::Vector3f dir = toTarget / dist;
|
||||||
|
float moveAmount = walkSpeed * static_cast<float>(deltaMs) / 1000.f;
|
||||||
|
if (moveAmount >= dist) {
|
||||||
|
position = walkTarget;
|
||||||
|
position.y() = 0.f;
|
||||||
|
} else {
|
||||||
|
position += dir * moveAmount;
|
||||||
|
}
|
||||||
|
targetFacingAngle = atan2(dir.x(), -dir.z());
|
||||||
|
currentState = AnimationState::WALK;
|
||||||
|
} else {
|
||||||
|
currentState = AnimationState::IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate toward target facing angle at constant angular speed
|
||||||
|
float angleDiff = targetFacingAngle - facingAngle;
|
||||||
|
while (angleDiff > static_cast<float>(M_PI)) angleDiff -= 2.f * static_cast<float>(M_PI);
|
||||||
|
while (angleDiff < -static_cast<float>(M_PI)) angleDiff += 2.f * static_cast<float>(M_PI);
|
||||||
|
float rotStep = rotationSpeed * static_cast<float>(deltaMs) / 1000.f;
|
||||||
|
if (std::fabs(angleDiff) <= rotStep) {
|
||||||
|
facingAngle = targetFacingAngle;
|
||||||
|
} else {
|
||||||
|
facingAngle += (angleDiff > 0.f ? rotStep : -rotStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance active animation frame
|
||||||
|
AnimationState animState = resolveActiveState();
|
||||||
|
auto it = animations.find(animState);
|
||||||
|
if (it == animations.end()) return;
|
||||||
|
|
||||||
|
auto& anim = it->second;
|
||||||
|
anim.currentFrame += static_cast<float>(deltaMs) / 24.f;
|
||||||
|
if (static_cast<int>(anim.currentFrame) >= anim.totalFrames-1) {
|
||||||
|
anim.currentFrame = anim.model.startingFrame;
|
||||||
|
}
|
||||||
|
if (static_cast<int>(anim.currentFrame) != anim.lastFrame) {
|
||||||
|
anim.model.Interpolate(static_cast<int>(anim.currentFrame));
|
||||||
|
anim.lastFrame = static_cast<int>(anim.currentFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Character::draw(Renderer& renderer) {
|
||||||
|
AnimationState drawState = resolveActiveState();
|
||||||
|
auto it = animations.find(drawState);
|
||||||
|
if (it == animations.end() || !texture) return;
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
||||||
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
|
renderer.ScaleMatrix(modelScale);
|
||||||
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
||||||
|
|
||||||
|
auto& anim = it->second;
|
||||||
|
anim.modelMutable.AssignFrom(anim.model.mesh);
|
||||||
|
anim.modelMutable.RefreshVBO();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
||||||
|
renderer.DrawVertexRenderStruct(anim.modelMutable);
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
59
src/Character.h
Normal file
59
src/Character.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "BoneAnimatedModel.h"
|
||||||
|
#include "render/Renderer.h"
|
||||||
|
#include "render/TextureManager.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
enum class AnimationState {
|
||||||
|
IDLE = 0,
|
||||||
|
WALK = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
class Character {
|
||||||
|
public:
|
||||||
|
void loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = "");
|
||||||
|
void setTexture(std::shared_ptr<Texture> texture);
|
||||||
|
void update(int64_t deltaMs);
|
||||||
|
void setTarget(const Eigen::Vector3f& target);
|
||||||
|
void draw(Renderer& renderer);
|
||||||
|
|
||||||
|
// Public: read by Game for camera tracking and ray-cast origin
|
||||||
|
Eigen::Vector3f position = Eigen::Vector3f(0.f, 0.f, 0.f);
|
||||||
|
float facingAngle = 0.0f;
|
||||||
|
|
||||||
|
// Per-character tuning — set after construction, before first update
|
||||||
|
float walkSpeed = 3.0f;
|
||||||
|
float rotationSpeed = 4.0f;
|
||||||
|
float modelScale = 0.12f;
|
||||||
|
// Applied after scale, fixes model-space orientation (e.g. Blender Z-up exports)
|
||||||
|
Eigen::Quaternionf modelCorrectionRotation = Eigen::Quaternionf::Identity();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct AnimationData {
|
||||||
|
BoneSystem model;
|
||||||
|
VertexRenderStruct modelMutable;
|
||||||
|
float currentFrame = 0.f;
|
||||||
|
int lastFrame = -1;
|
||||||
|
int totalFrames = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<AnimationState, AnimationData> animations;
|
||||||
|
AnimationState currentState = AnimationState::IDLE;
|
||||||
|
std::shared_ptr<Texture> texture;
|
||||||
|
|
||||||
|
Eigen::Vector3f walkTarget = Eigen::Vector3f(0.f, 0.f, 0.f);
|
||||||
|
float targetFacingAngle = 0.0f;
|
||||||
|
|
||||||
|
static constexpr float WALK_THRESHOLD = 0.05f;
|
||||||
|
|
||||||
|
// Returns the animation state to actually play/draw, falling back to IDLE
|
||||||
|
// if the requested state has no loaded animation.
|
||||||
|
AnimationState resolveActiveState() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
144
src/Game.cpp
144
src/Game.cpp
@ -162,12 +162,31 @@ namespace ZL
|
|||||||
benchMesh.data.Move({ -2.1, 0.5, -7.9 });
|
benchMesh.data.Move({ -2.1, 0.5, -7.9 });
|
||||||
benchMesh.RefreshVBO();
|
benchMesh.RefreshVBO();
|
||||||
|
|
||||||
violaIdleModel.LoadFromFile("resources/idleviola_uv010.txt", CONST_ZIP_FILE);
|
auto violaTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/viola.png", CONST_ZIP_FILE));
|
||||||
violaWalkModel.LoadFromFile("resources/walkviola_uv010.txt", CONST_ZIP_FILE);
|
|
||||||
|
|
||||||
zombieModel.LoadFromFile("resources/w/zombie002.txt", CONST_ZIP_FILE);
|
// Player (Viola)
|
||||||
|
player = std::make_unique<Character>();
|
||||||
|
player->loadAnimation(AnimationState::IDLE, "resources/idleviola_uv010.txt", CONST_ZIP_FILE);
|
||||||
|
player->loadAnimation(AnimationState::WALK, "resources/walkviola_uv010.txt", CONST_ZIP_FILE);
|
||||||
|
player->setTexture(violaTexture);
|
||||||
|
player->walkSpeed = 3.0f;
|
||||||
|
player->rotationSpeed = 8.0f;
|
||||||
|
player->modelScale = 0.12f;
|
||||||
|
player->modelCorrectionRotation =
|
||||||
|
Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5f, Eigen::Vector3f::UnitX())) *
|
||||||
|
Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitZ()));
|
||||||
|
|
||||||
violaTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/viola.png", CONST_ZIP_FILE));
|
auto defaultTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/default_skin001.png", CONST_ZIP_FILE));
|
||||||
|
|
||||||
|
auto zombie = std::make_unique<Character>();
|
||||||
|
zombie->loadAnimation(AnimationState::IDLE, "resources/w/default_idle002.txt", CONST_ZIP_FILE);
|
||||||
|
zombie->setTexture(defaultTexture);
|
||||||
|
zombie->walkSpeed = 1.5f;
|
||||||
|
zombie->rotationSpeed = 2.0f;
|
||||||
|
zombie->modelScale = 0.01f;
|
||||||
|
zombie->position = Eigen::Vector3f(0.f, 0.f, -15.f);
|
||||||
|
zombie->setTarget(zombie->position);
|
||||||
|
npcs.push_back(std::move(zombie));
|
||||||
|
|
||||||
loadingCompleted = true;
|
loadingCompleted = true;
|
||||||
}
|
}
|
||||||
@ -206,7 +225,8 @@ namespace ZL
|
|||||||
|
|
||||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
renderer.TranslateMatrix({ -violaPosition.x(), -violaPosition.y(), -violaPosition.z() });
|
const Eigen::Vector3f& camTarget = player ? player->position : Eigen::Vector3f::Zero();
|
||||||
|
renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() });
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, roomTexture->getTexID());
|
glBindTexture(GL_TEXTURE_2D, roomTexture->getTexID());
|
||||||
renderer.DrawVertexRenderStruct(roomMesh);
|
renderer.DrawVertexRenderStruct(roomMesh);
|
||||||
@ -219,41 +239,8 @@ namespace ZL
|
|||||||
renderer.DrawVertexRenderStruct(benchMesh);
|
renderer.DrawVertexRenderStruct(benchMesh);
|
||||||
|
|
||||||
|
|
||||||
renderer.PushMatrix();
|
if (player) player->draw(renderer);
|
||||||
renderer.TranslateMatrix({ 0,0,-15 });
|
for (auto& npc : npcs) npc->draw(renderer);
|
||||||
renderer.ScaleMatrix(0.01);
|
|
||||||
zombieModelMutable.AssignFrom(zombieModel.mesh);
|
|
||||||
zombieModelMutable.RefreshVBO();
|
|
||||||
glBindTexture(GL_TEXTURE_2D, violaTexture->getTexID());
|
|
||||||
renderer.DrawVertexRenderStruct(zombieModelMutable);
|
|
||||||
renderer.PopMatrix();
|
|
||||||
|
|
||||||
renderer.PushMatrix();
|
|
||||||
|
|
||||||
renderer.TranslateMatrix({ violaPosition.x(), violaPosition.y(), violaPosition.z() });
|
|
||||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-violaFacingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
||||||
renderer.ScaleMatrix(0.12);
|
|
||||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5f, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
|
||||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitZ())).toRotationMatrix());
|
|
||||||
|
|
||||||
//renderer.RotateMatrix(QuatFromRotateAroundX(-M_PI / 2.0));
|
|
||||||
//renderer.RotateMatrix(QuatFromRotateAroundZ(M_PI));
|
|
||||||
|
|
||||||
if (violaCurrentAnimation == 0) {
|
|
||||||
|
|
||||||
violaIdleModelMutable.AssignFrom(violaIdleModel.mesh);
|
|
||||||
violaIdleModelMutable.RefreshVBO();
|
|
||||||
glBindTexture(GL_TEXTURE_2D, violaTexture->getTexID());
|
|
||||||
renderer.DrawVertexRenderStruct(violaIdleModelMutable);
|
|
||||||
}
|
|
||||||
else if (violaCurrentAnimation == 1) {
|
|
||||||
violaWalkModelMutable.AssignFrom(violaWalkModel.mesh);
|
|
||||||
violaWalkModelMutable.RefreshVBO();
|
|
||||||
glBindTexture(GL_TEXTURE_2D, violaTexture->getTexID());
|
|
||||||
renderer.DrawVertexRenderStruct(violaWalkModelMutable);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderer.PopMatrix();
|
|
||||||
|
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
@ -332,74 +319,8 @@ namespace ZL
|
|||||||
|
|
||||||
lastTickCount = newTickCount;
|
lastTickCount = newTickCount;
|
||||||
|
|
||||||
// Move Viola toward target
|
if (player) player->update(delta);
|
||||||
Eigen::Vector3f toTarget = violaTarget - violaPosition;
|
for (auto& npc : npcs) npc->update(delta);
|
||||||
toTarget.y() = 0.f;
|
|
||||||
float dist = toTarget.norm();
|
|
||||||
if (dist > VIOLA_WALK_THRESHOLD) {
|
|
||||||
Eigen::Vector3f dir = toTarget / dist;
|
|
||||||
float moveAmount = VIOLA_WALK_SPEED * delta / 1000.f;
|
|
||||||
if (moveAmount >= dist) {
|
|
||||||
violaPosition = violaTarget;
|
|
||||||
violaPosition.y() = 0.f;
|
|
||||||
} else {
|
|
||||||
violaPosition += dir * moveAmount;
|
|
||||||
}
|
|
||||||
violaTargetFacingAngle = atan2(dir.x(), -dir.z());
|
|
||||||
violaCurrentAnimation = 1;
|
|
||||||
} else {
|
|
||||||
violaCurrentAnimation = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rotate Viola toward target facing angle at constant angular speed
|
|
||||||
float angleDiff = violaTargetFacingAngle - violaFacingAngle;
|
|
||||||
while (angleDiff > M_PI) angleDiff -= 2.f * static_cast<float>(M_PI);
|
|
||||||
while (angleDiff < -M_PI) angleDiff += 2.f * static_cast<float>(M_PI);
|
|
||||||
float rotStep = VIOLA_ROTATION_SPEED * delta / 1000.f;
|
|
||||||
if (std::fabs(angleDiff) <= rotStep) {
|
|
||||||
violaFacingAngle = violaTargetFacingAngle;
|
|
||||||
} else {
|
|
||||||
violaFacingAngle += (angleDiff > 0.f ? rotStep : -rotStep);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (violaCurrentAnimation == 0) {
|
|
||||||
|
|
||||||
violaCurrentIdleFrame += delta / 24.f;
|
|
||||||
|
|
||||||
while (violaCurrentIdleFrame >= 40) {
|
|
||||||
violaCurrentIdleFrame -= 40;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int(violaCurrentIdleFrame) != violaLastIdleFrame) {
|
|
||||||
violaIdleModel.Interpolate(int(violaCurrentIdleFrame));
|
|
||||||
violaLastIdleFrame = int(violaCurrentIdleFrame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (violaCurrentAnimation == 1) {
|
|
||||||
|
|
||||||
violaCurrentWalkFrame += delta / 24.f;
|
|
||||||
|
|
||||||
while (violaCurrentWalkFrame >= 30) {
|
|
||||||
violaCurrentWalkFrame -= 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int(violaCurrentWalkFrame) != violaLastWalkFrame) {
|
|
||||||
violaWalkModel.Interpolate(int(violaCurrentWalkFrame));
|
|
||||||
violaLastWalkFrame = int(violaCurrentWalkFrame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
zombieCurrentIdleFrame += delta / 24.f;
|
|
||||||
|
|
||||||
while (zombieCurrentIdleFrame >= 90) {
|
|
||||||
zombieCurrentIdleFrame -= 90;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int(zombieCurrentIdleFrame) != zombieLastIdleFrame) {
|
|
||||||
zombieModel.Interpolate(int(zombieCurrentIdleFrame));
|
|
||||||
zombieLastIdleFrame = int(zombieCurrentIdleFrame);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -500,14 +421,15 @@ namespace ZL
|
|||||||
Eigen::Vector3f camRight(cosAzim, 0.f, sinAzim);
|
Eigen::Vector3f camRight(cosAzim, 0.f, sinAzim);
|
||||||
Eigen::Vector3f camForward(sinAzim * cosIncl, -sinIncl, -cosAzim * cosIncl);
|
Eigen::Vector3f camForward(sinAzim * cosIncl, -sinIncl, -cosAzim * cosIncl);
|
||||||
Eigen::Vector3f camUp(sinAzim * sinIncl, cosIncl, -cosAzim * sinIncl);
|
Eigen::Vector3f camUp(sinAzim * sinIncl, cosIncl, -cosAzim * sinIncl);
|
||||||
Eigen::Vector3f camPos = violaPosition + Eigen::Vector3f(-sinAzim * cosIncl, sinIncl, cosAzim * cosIncl) * Environment::zoom;
|
const Eigen::Vector3f& playerPos = player ? player->position : Eigen::Vector3f::Zero();
|
||||||
|
Eigen::Vector3f camPos = playerPos + Eigen::Vector3f(-sinAzim * cosIncl, sinIncl, cosAzim * cosIncl) * Environment::zoom;
|
||||||
|
|
||||||
Eigen::Vector3f rayDir = (camForward + camRight * (ndcX * aspect * tanHalfFov) + camUp * (ndcY * tanHalfFov)).normalized();
|
Eigen::Vector3f rayDir = (camForward + camRight * (ndcX * aspect * tanHalfFov) + camUp * (ndcY * tanHalfFov)).normalized();
|
||||||
|
|
||||||
if (rayDir.y() < -0.001f) {
|
if (rayDir.y() < -0.001f && player) {
|
||||||
float t = -camPos.y() / rayDir.y();
|
float t = -camPos.y() / rayDir.y();
|
||||||
Eigen::Vector3f hit = camPos + rayDir * t;
|
Eigen::Vector3f hit = camPos + rayDir * t;
|
||||||
violaTarget = Eigen::Vector3f(hit.x(), 0.f, hit.z());
|
player->setTarget(Eigen::Vector3f(hit.x(), 0.f, hit.z()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleUp(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
|
handleUp(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
|
||||||
|
|||||||
33
src/Game.h
33
src/Game.h
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "Character.h"
|
||||||
#include "BoneAnimatedModel.h"
|
#include "BoneAnimatedModel.h"
|
||||||
#include "render/Renderer.h"
|
#include "render/Renderer.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
@ -55,45 +56,17 @@ namespace ZL {
|
|||||||
std::shared_ptr<Texture> benchTexture;
|
std::shared_ptr<Texture> benchTexture;
|
||||||
VertexRenderStruct benchMesh;
|
VertexRenderStruct benchMesh;
|
||||||
|
|
||||||
BoneSystem violaIdleModel;
|
std::unique_ptr<Character> player;
|
||||||
VertexRenderStruct violaIdleModelMutable;
|
std::vector<std::unique_ptr<Character>> npcs;
|
||||||
|
|
||||||
BoneSystem violaWalkModel;
|
|
||||||
VertexRenderStruct violaWalkModelMutable;
|
|
||||||
|
|
||||||
BoneSystem zombieModel;
|
|
||||||
VertexRenderStruct zombieModelMutable;
|
|
||||||
|
|
||||||
std::shared_ptr<Texture> violaTexture;
|
|
||||||
|
|
||||||
float zombieCurrentIdleFrame = 0;
|
|
||||||
int zombieLastIdleFrame = 0;
|
|
||||||
|
|
||||||
float violaCurrentIdleFrame = 0;
|
|
||||||
float violaCurrentWalkFrame = 0;
|
|
||||||
|
|
||||||
int violaLastIdleFrame = 0;
|
|
||||||
int violaLastWalkFrame = 0;
|
|
||||||
|
|
||||||
int violaCurrentAnimation = 0;
|
|
||||||
|
|
||||||
float cameraAzimuth = 0.0f;
|
float cameraAzimuth = 0.0f;
|
||||||
float cameraInclination = M_PI * 30.f / 180.f;
|
float cameraInclination = M_PI * 30.f / 180.f;
|
||||||
|
|
||||||
Eigen::Vector3f violaPosition = Eigen::Vector3f(0.f, 0.f, 0.f);
|
|
||||||
Eigen::Vector3f violaTarget = Eigen::Vector3f(0.f, 0.f, 0.f);
|
|
||||||
float violaFacingAngle = 0.0f;
|
|
||||||
private:
|
private:
|
||||||
bool rightMouseDown = false;
|
bool rightMouseDown = false;
|
||||||
int lastMouseX = 0;
|
int lastMouseX = 0;
|
||||||
int lastMouseY = 0;
|
int lastMouseY = 0;
|
||||||
|
|
||||||
static constexpr float CAMERA_FOV_Y = 1.0f / 1.5f;
|
static constexpr float CAMERA_FOV_Y = 1.0f / 1.5f;
|
||||||
static constexpr float VIOLA_WALK_SPEED = 3.0f;
|
|
||||||
static constexpr float VIOLA_WALK_THRESHOLD = 0.05f;
|
|
||||||
static constexpr float VIOLA_ROTATION_SPEED = 8.0f; // radians per second
|
|
||||||
|
|
||||||
float violaTargetFacingAngle = 0.0f;
|
|
||||||
|
|
||||||
int64_t getSyncTimeMs();
|
int64_t getSyncTimeMs();
|
||||||
void processTickCount();
|
void processTickCount();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user