added projectile

This commit is contained in:
Vlad 2025-12-30 16:47:32 +06:00
parent d57112be35
commit ff3946a019
7 changed files with 221 additions and 9 deletions

View File

@ -442,6 +442,8 @@ add_executable(space-game001
PlanetObject.h
UiManager.cpp
UiManager.h
Projectile.h
Projectile.cpp
)
# Установка проекта по умолчанию для Visual Studio

View File

@ -123,11 +123,10 @@ namespace ZL
, newTickCount(0)
, lastTickCount(0)
{
std::vector<Vector3f> emissionPoints = {
Vector3f{-2.1f, 0.9f, 5.0f},
Vector3f{2.1f, 0.9f, 5.0f}
};
sparkEmitter = SparkEmitter(emissionPoints, 100.0f);
projectiles.reserve(maxProjectiles);
for (int i = 0; i < maxProjectiles; ++i) {
projectiles.emplace_back(std::make_unique<Projectile>());
}
}
Game::~Game() {
@ -163,6 +162,8 @@ namespace ZL
#endif
bool cfgLoaded = sparkEmitter.loadFromJsonFile("../config/spark_config.json", renderer, CONST_ZIP_FILE);
bool projCfgLoaded = projectileEmitter.loadFromJsonFile("../config/spark_projectile_config.json", renderer, CONST_ZIP_FILE);
projectileEmitter.setEmissionPoints(std::vector<Vector3f>());
uiManager.loadFromFile("../config/ui.json", renderer, CONST_ZIP_FILE);
uiManager.setButtonCallback("playButton", [this](const std::string& name) {
@ -364,10 +365,18 @@ namespace ZL
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
renderer.TranslateMatrix({ 0, -Environment::zoom * 0.03f, 0 });
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
renderer.DrawVertexRenderStruct(spaceship);
for (const auto& p : projectiles) {
if (p && p->isActive()) {
p->draw(renderer);
}
}
sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
@ -584,14 +593,74 @@ namespace ZL
{
Vector3f velocityDirection = { 0,0, -Environment::shipVelocity * delta / 1000.f };
Vector3f velocityDirectionAdjusted = MultMatrixVector(Environment::shipMatrix, velocityDirection);
Environment::shipPosition = Environment::shipPosition + velocityDirectionAdjusted;
}
for (auto& p : projectiles) {
if (p && p->isActive()) {
p->update(static_cast<float>(delta), renderer);
}
}
std::vector<Vector3f> projCameraPoints;
for (const auto& p : projectiles) {
if (p && p->isActive()) {
Vector3f worldPos = p->getPosition();
Vector3f rel = worldPos - Environment::shipPosition;
Vector3f camPos = MultMatrixVector(Environment::inverseShipMatrix, rel);
projCameraPoints.push_back(camPos);
}
}
if (!projCameraPoints.empty()) {
projectileEmitter.setEmissionPoints(projCameraPoints);
projectileEmitter.emit();
}
else {
projectileEmitter.setEmissionPoints(std::vector<Vector3f>());
}
std::vector<Vector3f> shipCameraPoints;
for (const auto& lp : shipLocalEmissionPoints) {
Vector3f adjusted = lp + Vector3f{ 0.0f, -Environment::zoom * 0.03f, 0.0f };
shipCameraPoints.push_back(adjusted);
}
if (!shipCameraPoints.empty()) {
sparkEmitter.setEmissionPoints(shipCameraPoints);
}
sparkEmitter.update(static_cast<float>(delta));
projectileEmitter.update(static_cast<float>(delta));
lastTickCount = newTickCount;
}
}
void Game::fireProjectiles() {
std::vector<Vector3f> localOffsets = {
Vector3f{ -1.5f, 0.9f, 5.0f },
Vector3f{ 1.5f, 0.9f, 5.0f }
};
const float projectileSpeed = 60.0f;
const float lifeMs = 5000.0f;
const float size = 0.5f;
Vector3f localForward = { 0,0,-1 };
Vector3f worldForward = MultMatrixVector(Environment::shipMatrix, localForward).normalized();
for (const auto& lo : localOffsets) {
Vector3f worldPos = Environment::shipPosition + MultMatrixVector(Environment::shipMatrix, lo);
Vector3f worldVel = worldForward * projectileSpeed;
for (auto& p : projectiles) {
if (!p->isActive()) {
p->init(worldPos, worldVel, lifeMs, size, projectileTexture, renderer);
break;
}
}
}
}
void Game::render() {
SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
ZL::CheckGlError();
@ -622,6 +691,14 @@ namespace ZL
bool uiHandled = false;
if (event.button.button == SDL_BUTTON_LEFT && !uiManager.isUiInteraction()) {
uint64_t now = SDL_GetTicks64();
if (now - lastProjectileFireTime >= static_cast<uint64_t>(projectileCooldownMs)) {
lastProjectileFireTime = now;
fireProjectiles();
}
}
for (const auto& button : uiManager.findButton("") ? std::vector<std::shared_ptr<UiButton>>{} : std::vector<std::shared_ptr<UiButton>>{}) {
(void)button;
}

11
Game.h
View File

@ -7,6 +7,7 @@
#include "SparkEmitter.h"
#include "PlanetObject.h"
#include "UiManager.h"
#include "Projectile.h"
namespace ZL {
@ -38,6 +39,8 @@ namespace ZL {
void drawBoxes();
void drawUI();
void fireProjectiles();
SDL_Window* window;
SDL_GLContext glContext;
Renderer renderer;
@ -88,8 +91,16 @@ namespace ZL {
VertexDataStruct boxBase;
SparkEmitter sparkEmitter;
SparkEmitter projectileEmitter;
PlanetObject planetObject;
UiManager uiManager;
std::vector<std::unique_ptr<Projectile>> projectiles;
std::shared_ptr<Texture> projectileTexture;
float projectileCooldownMs = 500.0f;
uint64_t lastProjectileFireTime = 0;
int maxProjectiles = 32;
std::vector<Vector3f> shipLocalEmissionPoints;
};

71
Projectile.cpp Normal file
View File

@ -0,0 +1,71 @@
#include "Projectile.h"
namespace ZL {
Projectile::Projectile()
: pos({ 0,0,0 })
, vel({ 0,0,0 })
, life(0.0f)
, maxLife(0.0f)
, active(false)
, size(0.5f)
, texture(nullptr)
{
}
void Projectile::init(const Vector3f& startPos, const Vector3f& startVel, float lifeMs, float s, std::shared_ptr<Texture> tex, Renderer& renderer) {
pos = startPos;
vel = startVel;
life = 0.0f;
maxLife = lifeMs;
size = s;
texture = tex;
active = true;
rebuildMesh(renderer);
mesh.RefreshVBO();
}
void Projectile::update(float deltaMs, Renderer& renderer) {
if (!active) return;
pos = pos + vel * (deltaMs / 1000.0f);
life += deltaMs;
if (life >= maxLife) {
active = false;
return;
}
rebuildMesh(renderer);
mesh.RefreshVBO();
}
void Projectile::rebuildMesh(Renderer&) {
float half = size * 0.5f;
mesh.data.PositionData.clear();
mesh.data.TexCoordData.clear();
mesh.data.PositionData.push_back({ pos.v[0] - half, pos.v[1] - half, pos.v[2] });
mesh.data.PositionData.push_back({ pos.v[0] - half, pos.v[1] + half, pos.v[2] });
mesh.data.PositionData.push_back({ pos.v[0] + half, pos.v[1] + half, pos.v[2] });
mesh.data.PositionData.push_back({ pos.v[0] - half, pos.v[1] - half, pos.v[2] });
mesh.data.PositionData.push_back({ pos.v[0] + half, pos.v[1] + half, pos.v[2] });
mesh.data.PositionData.push_back({ pos.v[0] + half, pos.v[1] - half, pos.v[2] });
mesh.data.TexCoordData.push_back({ 0.0f, 0.0f });
mesh.data.TexCoordData.push_back({ 0.0f, 1.0f });
mesh.data.TexCoordData.push_back({ 1.0f, 1.0f });
mesh.data.TexCoordData.push_back({ 0.0f, 0.0f });
mesh.data.TexCoordData.push_back({ 1.0f, 1.0f });
mesh.data.TexCoordData.push_back({ 1.0f, 0.0f });
}
void Projectile::draw(Renderer& renderer) const {
if (!active || !texture) return;
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
renderer.DrawVertexRenderStruct(mesh);
}
} // namespace ZL

36
Projectile.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include "ZLMath.h"
#include "Renderer.h"
#include "TextureManager.h"
#include <memory>
namespace ZL {
class Projectile {
public:
Projectile();
~Projectile() = default;
void init(const Vector3f& startPos, const Vector3f& startVel, float lifeMs, float size, std::shared_ptr<Texture> tex, Renderer& renderer);
void update(float deltaMs, Renderer& renderer);
void draw(Renderer& renderer) const;
bool isActive() const { return active; }
Vector3f getPosition() const { return pos; }
private:
Vector3f pos;
Vector3f vel;
float life;
float maxLife;
bool active;
float size;
VertexRenderStruct mesh;
std::shared_ptr<Texture> texture;
void rebuildMesh(Renderer& renderer);
};
} // namespace ZL

View File

@ -5,10 +5,10 @@
"biasX": 0.3,
"emissionPoints": [
{
"position": [-2.1, 0.9, 5.0]
"position": [-2.1, 0.4, 5.0]
},
{
"position": [2.1, 0.9, 5.0]
"position": [2.1, 0.4, 5.0]
}
],
"speedRange": [0.5, 2.0],

View File

@ -0,0 +1,15 @@
{
"emissionPoints": [
{ "position": [0.0, 0.0, 0.0] }
],
"texture": "./resources/sand.png",
"speedRange": [10.0, 30.0],
"zSpeedRange": [-1.0, 1.0],
"scaleRange": [0.5, 1.0],
"lifeTimeRange": [200.0, 800.0],
"emissionRate": 50.0,
"maxParticles": 10,
"particleSize": 0.09,
"biasX": 0.1,
"shaderProgramName": "default"
}