Added hp and attack actions, and labels
This commit is contained in:
parent
393ebcd831
commit
44cc0fba67
@ -2,7 +2,7 @@
|
|||||||
"npcs": [
|
"npcs": [
|
||||||
{
|
{
|
||||||
"id": "npc_01_default",
|
"id": "npc_01_default",
|
||||||
"name": "NPC Default Guard",
|
"name": "Студент",
|
||||||
"animationIdlePath": "resources/w/jam/man_stand_idle002.anim",
|
"animationIdlePath": "resources/w/jam/man_stand_idle002.anim",
|
||||||
"animationWalkPath": "resources/w/jam/man_walk002.anim",
|
"animationWalkPath": "resources/w/jam/man_walk002.anim",
|
||||||
"meshTextures": {
|
"meshTextures": {
|
||||||
@ -35,7 +35,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "npc_02_woman",
|
"id": "npc_02_woman",
|
||||||
"name": "NPC woman",
|
"name": "Студентка",
|
||||||
"animationIdlePath": "resources/w/jam/woman_idle002.anim",
|
"animationIdlePath": "resources/w/jam/woman_idle002.anim",
|
||||||
"animationWalkPath": "resources/w/jam/woman_walk002.anim",
|
"animationWalkPath": "resources/w/jam/woman_walk002.anim",
|
||||||
"meshTextures": {
|
"meshTextures": {
|
||||||
@ -60,7 +60,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "npc_03_salesman",
|
"id": "npc_03_salesman",
|
||||||
"name": "NPC salesman",
|
"name": "Мухтар Байке",
|
||||||
"animationIdlePath": "resources/w/jam/salesperson_stand_idle003.anim",
|
"animationIdlePath": "resources/w/jam/salesperson_stand_idle003.anim",
|
||||||
"animationWalkPath": "resources/w/jam/salesperson_walk001.anim",
|
"animationWalkPath": "resources/w/jam/salesperson_walk001.anim",
|
||||||
"meshTextures": {
|
"meshTextures": {
|
||||||
@ -86,7 +86,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "npc_04_ghost",
|
"id": "npc_04_ghost",
|
||||||
"name": "NPC Floating Ghost",
|
"name": "Добрый Призрак",
|
||||||
"texturePath": "resources/w/ghost_skin001.png",
|
"texturePath": "resources/w/ghost_skin001.png",
|
||||||
"animationIdlePath": "resources/w/default_float001.anim",
|
"animationIdlePath": "resources/w/default_float001.anim",
|
||||||
"animationWalkPath": "resources/w/default_float001.anim",
|
"animationWalkPath": "resources/w/default_float001.anim",
|
||||||
|
|||||||
@ -3,7 +3,5 @@ varying vec3 color;
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
//gl_FragColor = vec4(color, 1.0);
|
gl_FragColor = vec4(color, 1.0);
|
||||||
gl_FragColor = vec4(1.0, 1.0, 0.5, 1.0);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,7 +1,9 @@
|
|||||||
#include "Character.h"
|
#include "Character.h"
|
||||||
|
#include "render/TextRenderer.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <array>
|
||||||
#include "GameConstants.h"
|
#include "GameConstants.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
|
|
||||||
@ -104,6 +106,8 @@ AnimationState Character::resolveActiveState() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Character::update(int64_t deltaMs) {
|
void Character::update(int64_t deltaMs) {
|
||||||
|
if (initialHp <= 0.f) initialHp = hp;
|
||||||
|
|
||||||
|
|
||||||
//weaponInitialRotation = Eigen::AngleAxisf(x/180.0, Eigen::Vector3f::UnitZ()).toRotationMatrix();
|
//weaponInitialRotation = Eigen::AngleAxisf(x/180.0, Eigen::Vector3f::UnitZ()).toRotationMatrix();
|
||||||
//weaponInitialRotation = Eigen::AngleAxisf(-M_PI*0.5, Eigen::Vector3f::UnitZ()).toRotationMatrix();
|
//weaponInitialRotation = Eigen::AngleAxisf(-M_PI*0.5, Eigen::Vector3f::UnitZ()).toRotationMatrix();
|
||||||
@ -820,4 +824,95 @@ void Character::prepareHitSparksForDraw(const Eigen::Matrix4f& cameraViewMatrix)
|
|||||||
hitSparkEmitter.prepareForDraw(cameraViewMatrix);
|
hitSparkEmitter.prepareForDraw(cameraViewMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Character::drawName(TextRenderer& textRenderer,
|
||||||
|
const Eigen::Matrix4f& cameraViewMatrix,
|
||||||
|
const Eigen::Matrix4f& projectionMatrix)
|
||||||
|
{
|
||||||
|
if (isPlayer) return;
|
||||||
|
if (hp <= 0.f) return;
|
||||||
|
if (npcName.empty()) return;
|
||||||
|
|
||||||
|
Eigen::Vector4f worldPos(position.x(), position.y() + 1.83f, position.z(), 1.f);
|
||||||
|
Eigen::Vector4f clip = projectionMatrix * cameraViewMatrix * worldPos;
|
||||||
|
if (clip.w() <= 0.f) return; // behind the camera
|
||||||
|
|
||||||
|
float ndcX = clip.x() / clip.w();
|
||||||
|
float ndcY = clip.y() / clip.w();
|
||||||
|
if (ndcX < -1.f || ndcX > 1.f || ndcY < -1.f || ndcY > 1.f) return; // off-screen
|
||||||
|
|
||||||
|
float screenX = (ndcX * 0.5f + 0.5f) * Environment::projectionWidth;
|
||||||
|
float screenY = (ndcY * 0.5f + 0.5f) * Environment::projectionHeight;
|
||||||
|
|
||||||
|
std::array<float, 4> color = canAttack
|
||||||
|
? std::array<float, 4>{ 1.f, 0.f, 0.f, 1.f }
|
||||||
|
: std::array<float, 4>{ 0.f, 1.f, 0.f, 1.f };
|
||||||
|
|
||||||
|
textRenderer.drawText(npcName, screenX, screenY, 1.0f, true, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Character::drawHealthBar(Renderer& renderer,
|
||||||
|
const Eigen::Matrix4f& cameraViewMatrix,
|
||||||
|
const Eigen::Matrix4f& projectionMatrix)
|
||||||
|
{
|
||||||
|
if (!isPlayer && !canAttack) return;
|
||||||
|
if (hp <= 0.f) return;
|
||||||
|
if (initialHp <= 0.f) return;
|
||||||
|
|
||||||
|
Eigen::Vector4f worldPos(position.x(), position.y() + 1.75f, position.z(), 1.f);
|
||||||
|
Eigen::Vector4f clip = projectionMatrix * cameraViewMatrix * worldPos;
|
||||||
|
if (clip.w() <= 0.f) return;
|
||||||
|
float ndcX = clip.x() / clip.w();
|
||||||
|
float ndcY = clip.y() / clip.w();
|
||||||
|
if (ndcX < -1.2f || ndcX > 1.2f || ndcY < -1.2f || ndcY > 1.2f) return;
|
||||||
|
|
||||||
|
const float sx = (ndcX * 0.5f + 0.5f) * Environment::projectionWidth;
|
||||||
|
const float sy = (ndcY * 0.5f + 0.5f) * Environment::projectionHeight;
|
||||||
|
|
||||||
|
const float barW = 60.f;
|
||||||
|
const float barH = 6.f;
|
||||||
|
|
||||||
|
const float left = sx - barW * 0.5f;
|
||||||
|
const float right = sx + barW * 0.5f;
|
||||||
|
const float bottom = sy - barH * 0.5f;
|
||||||
|
const float top = sy + barH * 0.5f;
|
||||||
|
|
||||||
|
float frac = hp / initialHp;
|
||||||
|
if (frac < 0.f) frac = 0.f;
|
||||||
|
if (frac > 1.f) frac = 1.f;
|
||||||
|
const float split = left + barW * frac;
|
||||||
|
|
||||||
|
VertexDataStruct data;
|
||||||
|
const Eigen::Vector3f green(0.f, 1.f, 0.f);
|
||||||
|
const Eigen::Vector3f red (1.f, 0.f, 0.f);
|
||||||
|
|
||||||
|
auto pushQuad = [&](float x0, float x1, const Eigen::Vector3f& col) {
|
||||||
|
data.PositionData.push_back({ x0, bottom, 0.f });
|
||||||
|
data.PositionData.push_back({ x1, bottom, 0.f });
|
||||||
|
data.PositionData.push_back({ x1, top, 0.f });
|
||||||
|
data.PositionData.push_back({ x0, bottom, 0.f });
|
||||||
|
data.PositionData.push_back({ x1, top, 0.f });
|
||||||
|
data.PositionData.push_back({ x0, top, 0.f });
|
||||||
|
for (int i = 0; i < 6; ++i) data.ColorData.push_back(col);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (frac > 0.f) pushQuad(left, split, green);
|
||||||
|
if (frac < 1.f) pushQuad(split, right, red);
|
||||||
|
|
||||||
|
healthBarMesh.AssignFrom(data);
|
||||||
|
healthBarMesh.RefreshVBO();
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader("defaultColor");
|
||||||
|
renderer.PushProjectionMatrix(0.f, Environment::projectionWidth,
|
||||||
|
0.f, Environment::projectionHeight,
|
||||||
|
-1.f, 1.f);
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
|
||||||
|
renderer.DrawVertexRenderStruct(healthBarMesh);
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
|
|||||||
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
|
class TextRenderer;
|
||||||
|
|
||||||
enum class AnimationState {
|
enum class AnimationState {
|
||||||
STAND = 0,
|
STAND = 0,
|
||||||
WALK = 1,
|
WALK = 1,
|
||||||
@ -66,6 +68,21 @@ public:
|
|||||||
// particles against that camera before its VBO is uploaded.
|
// particles against that camera before its VBO is uploaded.
|
||||||
void prepareHitSparksForDraw(const Eigen::Matrix4f& cameraViewMatrix);
|
void prepareHitSparksForDraw(const Eigen::Matrix4f& cameraViewMatrix);
|
||||||
|
|
||||||
|
// Draws the NPC name floating above this character in 2D screen space.
|
||||||
|
// No-op for the player, for dead characters, or if npcName is empty.
|
||||||
|
// The text is green for peaceful (canAttack == false) NPCs, red otherwise.
|
||||||
|
void drawName(TextRenderer& textRenderer,
|
||||||
|
const Eigen::Matrix4f& cameraViewMatrix,
|
||||||
|
const Eigen::Matrix4f& projectionMatrix);
|
||||||
|
|
||||||
|
// Draws a horizontal health bar above this character in 2D screen space.
|
||||||
|
// Visible only for the player and hostile NPCs (canAttack == true), and
|
||||||
|
// only while hp > 0. The left portion is green (hp / initialHp) and the
|
||||||
|
// remainder is red.
|
||||||
|
void drawHealthBar(Renderer& renderer,
|
||||||
|
const Eigen::Matrix4f& cameraViewMatrix,
|
||||||
|
const Eigen::Matrix4f& projectionMatrix);
|
||||||
|
|
||||||
// Public: read by Game for camera tracking and ray-cast origin
|
// Public: read by Game for camera tracking and ray-cast origin
|
||||||
Eigen::Vector3f position = Eigen::Vector3f(0.f, 0.f, 0.f);
|
Eigen::Vector3f position = Eigen::Vector3f(0.f, 0.f, 0.f);
|
||||||
float facingAngle = 0.0f;
|
float facingAngle = 0.0f;
|
||||||
@ -83,6 +100,9 @@ public:
|
|||||||
std::string npcName;
|
std::string npcName;
|
||||||
bool giftReceived = false;
|
bool giftReceived = false;
|
||||||
float hp = 100.f;
|
float hp = 100.f;
|
||||||
|
// Captured lazily from `hp` on the first update() tick if left at zero;
|
||||||
|
// set explicitly if you need a different reference for the health bar.
|
||||||
|
float initialHp = 0.f;
|
||||||
|
|
||||||
|
|
||||||
int battle_state = 0;
|
int battle_state = 0;
|
||||||
@ -112,6 +132,7 @@ private:
|
|||||||
|
|
||||||
std::map<AnimationState, BoneAnimationDataNew> animations;
|
std::map<AnimationState, BoneAnimationDataNew> animations;
|
||||||
VertexRenderStruct modelMutable;
|
VertexRenderStruct modelMutable;
|
||||||
|
VertexRenderStruct healthBarMesh;
|
||||||
std::unordered_map<std::string, std::shared_ptr<Texture>> meshTextures;
|
std::unordered_map<std::string, std::shared_ptr<Texture>> meshTextures;
|
||||||
|
|
||||||
Eigen::Vector3f walkTarget = Eigen::Vector3f(0.f, 0.f, 0.f);
|
Eigen::Vector3f walkTarget = Eigen::Vector3f(0.f, 0.f, 0.f);
|
||||||
|
|||||||
@ -119,6 +119,7 @@ namespace ZL
|
|||||||
npc02->loadBinaryAnimation(AnimationState::DEATH_IDLE, "resources/w/default_float001_cut.anim", CONST_ZIP_FILE);
|
npc02->loadBinaryAnimation(AnimationState::DEATH_IDLE, "resources/w/default_float001_cut.anim", CONST_ZIP_FILE);
|
||||||
|
|
||||||
npc02->npcId = "ghost_01x";
|
npc02->npcId = "ghost_01x";
|
||||||
|
npc02->npcName = "Evil Ghost";
|
||||||
npc02->setTexture(ghostTexture);
|
npc02->setTexture(ghostTexture);
|
||||||
npc02->walkSpeed = 1.5f;
|
npc02->walkSpeed = 1.5f;
|
||||||
npc02->rotationSpeed = 8.0f;
|
npc02->rotationSpeed = 8.0f;
|
||||||
@ -147,6 +148,12 @@ namespace ZL
|
|||||||
|
|
||||||
dialogueSystem.init(renderer, CONST_ZIP_FILE);
|
dialogueSystem.init(renderer, CONST_ZIP_FILE);
|
||||||
dialogueSystem.loadDatabase("resources/dialogue/sample_dialogues.json");
|
dialogueSystem.loadDatabase("resources/dialogue/sample_dialogues.json");
|
||||||
|
|
||||||
|
npcNameText = std::make_unique<TextRenderer>();
|
||||||
|
if (!npcNameText->init(renderer, "resources/fonts/DroidSans.ttf", 24, CONST_ZIP_FILE)) {
|
||||||
|
std::cerr << "Failed to init NPC name TextRenderer" << std::endl;
|
||||||
|
npcNameText.reset();
|
||||||
|
}
|
||||||
/*dialogueSystem.addTriggerZone({
|
/*dialogueSystem.addTriggerZone({
|
||||||
"ghost_room_trigger",
|
"ghost_room_trigger",
|
||||||
"test_line_dialogue",
|
"test_line_dialogue",
|
||||||
@ -362,6 +369,18 @@ namespace ZL
|
|||||||
|
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
|
if (npcNameText) {
|
||||||
|
Eigen::Matrix4f proj = MakePerspectiveMatrix(1.0f / 1.5f,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
for (auto& npc : npcs) {
|
||||||
|
if (npc) npc->drawName(*npcNameText, currentView, proj);
|
||||||
|
}
|
||||||
|
if (player) player->drawHealthBar(renderer, currentView, proj);
|
||||||
|
for (auto& npc : npcs) {
|
||||||
|
if (npc) npc->drawHealthBar(renderer, currentView, proj);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Location::drawShadowDepthPass()
|
void Location::drawShadowDepthPass()
|
||||||
@ -534,6 +553,19 @@ namespace ZL
|
|||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
|
if (npcNameText) {
|
||||||
|
Eigen::Matrix4f proj = MakePerspectiveMatrix(1.0f / 1.5f,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
for (auto& npc : npcs) {
|
||||||
|
if (npc) npc->drawName(*npcNameText, cameraViewMatrix, proj);
|
||||||
|
}
|
||||||
|
if (player) player->drawHealthBar(renderer, cameraViewMatrix, proj);
|
||||||
|
for (auto& npc : npcs) {
|
||||||
|
if (npc) npc->drawHealthBar(renderer, cameraViewMatrix, proj);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Location::setNavigationAreaAvailable(const std::string& areaName, bool available)
|
bool Location::setNavigationAreaAvailable(const std::string& areaName, bool available)
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "render/Renderer.h"
|
#include "render/Renderer.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
#include "render/TextureManager.h"
|
#include "render/TextureManager.h"
|
||||||
|
#include "render/TextRenderer.h"
|
||||||
#include "items/GameObjectLoader.h"
|
#include "items/GameObjectLoader.h"
|
||||||
#include "items/InteractiveObject.h"
|
#include "items/InteractiveObject.h"
|
||||||
#include "navigation/PathFinder.h"
|
#include "navigation/PathFinder.h"
|
||||||
@ -39,6 +40,8 @@ namespace ZL
|
|||||||
Eigen::Matrix4f cameraViewMatrix = Eigen::Matrix4f::Identity();
|
Eigen::Matrix4f cameraViewMatrix = Eigen::Matrix4f::Identity();
|
||||||
InteractiveObject* targetInteractiveObject = nullptr;
|
InteractiveObject* targetInteractiveObject = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<TextRenderer> npcNameText;
|
||||||
|
|
||||||
ScriptEngine scriptEngine;
|
ScriptEngine scriptEngine;
|
||||||
Dialogue::DialogueSystem dialogueSystem;
|
Dialogue::DialogueSystem dialogueSystem;
|
||||||
|
|
||||||
|
|||||||
@ -175,7 +175,7 @@ extern "C" int SDL_main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
|
|
||||||
ZL::Environment::window = SDL_CreateWindow(
|
ZL::Environment::window = SDL_CreateWindow(
|
||||||
"Space Ship Game",
|
"Bishkek Witcher Game",
|
||||||
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||||
ZL::Environment::width, ZL::Environment::height,
|
ZL::Environment::width, ZL::Environment::height,
|
||||||
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
||||||
@ -250,7 +250,7 @@ int main(int argc, char *argv[]) {
|
|||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
|
||||||
ZL::Environment::window = SDL_CreateWindow(
|
ZL::Environment::window = SDL_CreateWindow(
|
||||||
"Space Ship Game",
|
"Bishkek Witcher Game",
|
||||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
CONST_WIDTH, CONST_HEIGHT,
|
CONST_WIDTH, CONST_HEIGHT,
|
||||||
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
|
||||||
|
|||||||
@ -461,6 +461,11 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca
|
|||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, atlasTexture->getTexID());
|
glBindTexture(GL_TEXTURE_2D, atlasTexture->getTexID());
|
||||||
|
|
||||||
|
// The R8 atlas is sampled as alpha; without blending the non-glyph area
|
||||||
|
// of every quad writes opaque black and hides whatever is behind it.
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
//for (size_t i = 0; i < text.length(); ++i) {
|
//for (size_t i = 0; i < text.length(); ++i) {
|
||||||
// auto it = glyphs.find(text[i]);
|
// auto it = glyphs.find(text[i]);
|
||||||
// if (it == glyphs.end()) continue;
|
// if (it == glyphs.end()) continue;
|
||||||
@ -479,6 +484,9 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca
|
|||||||
//}
|
//}
|
||||||
r->DrawVertexRenderStruct(cached.mesh);
|
r->DrawVertexRenderStruct(cached.mesh);
|
||||||
//r->PopMatrix();
|
//r->PopMatrix();
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
r->shaderManager.PopShader();
|
r->shaderManager.PopShader();
|
||||||
|
|
||||||
// Сброс бинда текстуры не обязателен, но можно для чистоты
|
// Сброс бинда текстуры не обязателен, но можно для чистоты
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user