From 552faa8cea26813a1519ffa06229af33d8707e52 Mon Sep 17 00:00:00 2001 From: Matq Date: Wed, 11 Dec 2024 00:36:17 +0200 Subject: [PATCH] BLOOD, sparks (incomplete) --- CMakeLists.txt | 4 +- bin/assets/images/entity/character/blood.png | Bin 0 -> 549 bytes bin/assets/images/entity/projectile/spark.png | Bin 0 -> 119 bytes src/GameReference.cpp | 2 - src/client/Particles.cpp | 99 ++++++++++++++++++ src/client/Particles.h | 69 ++++++++++++ src/game/GameWorld.cpp | 4 + src/game/GameWorld.h | 3 + src/game/entities/Entity.cpp | 1 + src/game/entities/Projectile.cpp | 14 ++- src/game/entities/Projectile.h | 1 + .../characters/character/Character.cpp | 13 +++ .../entities/characters/character/Character.h | 1 + src/game/weapons/projectile/WeaponShotgun.cpp | 2 +- 14 files changed, 207 insertions(+), 6 deletions(-) create mode 100644 bin/assets/images/entity/character/blood.png create mode 100644 bin/assets/images/entity/projectile/spark.png create mode 100644 src/client/Particles.cpp create mode 100644 src/client/Particles.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f748e3b..d533dee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,9 @@ set(PROJECT_FILES "src/game/interface/LevelUpMenu.cpp" "src/game/interface/LevelUpMenu.h" src/game/weapons/projectile/PatersonNavy.cpp - src/game/weapons/projectile/PatersonNavy.h) + src/game/weapons/projectile/PatersonNavy.h + src/client/Particles.cpp + src/client/Particles.h) add_executable(${PROJECT_NAME} ${BUILD_OPTIONS} ${PROJECT_FILES}) diff --git a/bin/assets/images/entity/character/blood.png b/bin/assets/images/entity/character/blood.png new file mode 100644 index 0000000000000000000000000000000000000000..6545c925095a61dbe6760b1e3f90321d0b135758 GIT binary patch literal 549 zcmV+=0^0qFP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940lG;4U zB0&%aV3+~3YcMZah5%9%asq^eAms#HhdUBLfUpBV$iiN;!}9XSbg~t+s;mD;Rdsec zoqm3PzQ4cc^Z8Dvlg(!5^SSf&^)=)V4-egLx6x=^E|=@|8V?48+wJD;i1)PLGa}K{QO+0RQ{#mNkqTXC=?1VtZ@FM zp#hQs6zX4JU;F(&3fkH@pU-4IK0ao%*-BoMT*m!=|8O{be}B`U zglT$)W)*?J#4tK!5;vR8?RHC;WVKp#ZMWMmFE2Rwgg|SxnsH6F*=!4a=PZPiC-ae14NM_t4q+v%4CeF! z@nkZQ>59PpU*ebqP^j>9g_En?w?Yg-15Ex`Qjy!Hx!KZEzc(@-kAtv|1BV0xZ4<9n zD?2m;Kv0S7hZhjSz4tWnCP8q5N??4y?Z>@dPiH_HkT}cbG6F={3|phq<@WaW7O{iV n6&V2$B3x6;oGXk;k|g;7Eleig7~*ud00000NkvXXu0mjf4FU8D literal 0 HcmV?d00001 diff --git a/bin/assets/images/entity/projectile/spark.png b/bin/assets/images/entity/projectile/spark.png new file mode 100644 index 0000000000000000000000000000000000000000..77dff11c79847d37b20cbca451e56fec8a89666e GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2s6ii6yp7}lMWc?smOq&xaLGB9lH z=l+w(3gmMZctjR6Fz_7$VMb96uLhtXkEe@ch(vhukNRdt29}MCH*UXKTm=+o@O1Ta JS?83{1OTGW9Blvq literal 0 HcmV?d00001 diff --git a/src/GameReference.cpp b/src/GameReference.cpp index da49fae..c4888e4 100644 --- a/src/GameReference.cpp +++ b/src/GameReference.cpp @@ -39,8 +39,6 @@ void GameReference::UpdateDimensions(int width, int height) { m_Height = height; m_Width2 = width / 2.0; m_Height2 = height / 2.0; - - } bool GameReference::InitializeSDL() { diff --git a/src/client/Particles.cpp b/src/client/Particles.cpp new file mode 100644 index 0000000..0f90c22 --- /dev/null +++ b/src/client/Particles.cpp @@ -0,0 +1,99 @@ +// +// Created by Matq on 10/12/2024. +// + +#include "Particles.h" + +#include +#include "../technical stuff/TextManager.h" +#include "../game/GameWorld.h" + +void Particle::Tick() { + m_Vel *= m_VelDamping; + m_OrientationVel *= m_OrientationVelDamping; + m_Position += m_Vel; + m_Orientation += m_OrientationVel; + + + if (m_Lifetime == 0 || m_Vel.Length() <= 0.001) + m_Active = false; + + m_Lifetime--; +} + +void Particle::Draw(Drawing* drawing) const { + SDL_FRect asd = { + (float)m_Position.x, + (float)m_Position.y, + (float)m_Size.x, + (float)m_Size.y, + }; + + drawing->RenderTextureExFCamera(m_Texture->SDLTexture(), nullptr, asd, m_Orientation, nullptr, SDL_FLIP_NONE); +} + +Particles::Particles(GameWorld* game_world) { + m_World = game_world; + m_Drawing = game_world->GameWindow()->Render(); + m_CreateParticleIndex = 0; + + for (auto & particle : m_Particles) + particle = Particle(); +} + +bool Particles::PlayParticle(Particle particle) { + bool success = false; + for (int i = 0; i < 1024; i++) { + // Occupy space if available + if (!m_Particles[m_CreateParticleIndex].m_Active) { + m_Particles[m_CreateParticleIndex] = std::move(particle); + success = true; + } + + // Go to the next index + m_CreateParticleIndex++; + if (m_CreateParticleIndex >= 1024) + m_CreateParticleIndex = 0; + + // Leave if found a space successfully + if (success) return true; + } + + // There was no space for the particle + return false; +} + +void Particles::Tick() { + for (auto& particle : m_Particles) { + if (!particle.m_Active) + continue; + + if (particle.m_Position.x < 0) { + particle.m_Position.x = 0; + particle.m_Vel.x *= -1; + } + if (particle.m_Position.x > m_World->GetWidth()) { + particle.m_Position.x = m_World->GetWidth(); + particle.m_Vel.x *= -1; + } + if (particle.m_Position.y < 0) { + particle.m_Position.y = 0; + particle.m_Vel.y *= -1; + } + if (particle.m_Position.y > m_World->GetHeight()) { + particle.m_Position.y = m_World->GetHeight(); + particle.m_Vel.y *= -1; + } + + particle.Tick(); + } +} + +void Particles::Draw() { + for (auto& particle : m_Particles) { + if (!particle.m_Active) + continue; + + particle.Draw(m_Drawing); + } +} \ No newline at end of file diff --git a/src/client/Particles.h b/src/client/Particles.h new file mode 100644 index 0000000..62d7a7d --- /dev/null +++ b/src/client/Particles.h @@ -0,0 +1,69 @@ +// +// Created by Matq on 10/12/2024. +// + +#pragma once + +#include "../technical stuff/Drawing.h" +#include "../technical stuff/Vec2.h" + +struct Particle { + Texture* m_Texture; + Vec2d m_Position; + Vec2d m_Size; + Vec2d m_Vel; + double m_VelDamping; + double m_Orientation; + double m_OrientationVel; + double m_OrientationVelDamping; + unsigned long long m_Lifetime; + bool m_Active; + + Particle() { + m_Texture = nullptr; + m_Position = {}; + m_Size = {}; + m_Vel = {}; + m_Orientation = {}; + m_OrientationVel = {}; + m_Active = false; + } + Particle(Texture* texture, const Vec2d& pos, const Vec2d& size, const Vec2d& vel, double vel_damping, double orientation, double orientation_vel, double orientation_vel_damping, unsigned long long lifetime) { + m_Texture = texture; + m_Position = pos; + m_Size = size; + m_Vel = vel; + m_VelDamping = vel_damping; + m_Orientation = orientation; + m_OrientationVel = orientation_vel; + m_OrientationVelDamping = orientation_vel_damping; + m_Lifetime = lifetime; + + m_Active = true; + } + + void Tick(); + void Draw(Drawing* drawing) const; + +}; + +class GameWorld; +class Particles { +private: + GameWorld* m_World; + Drawing* m_Drawing; + Particle m_Particles[1024]; + size_t m_CreateParticleIndex; + +public: + explicit Particles(GameWorld* game_world); + + // Manipulating + bool PlayParticle(Particle particle); + + // Ticking + void Tick(); + void Draw(); + +}; + diff --git a/src/game/GameWorld.cpp b/src/game/GameWorld.cpp index 27134cb..03ebd24 100644 --- a/src/game/GameWorld.cpp +++ b/src/game/GameWorld.cpp @@ -12,6 +12,7 @@ GameWorld::GameWorld(GameReference *game_window, int width, int height) { m_GameWindow = game_window; + m_Particles = new Particles(this); m_Tiles = new TileMap(game_window->Render(), 32, width, height); m_Width = m_Tiles->TotalWidth(); m_Height = m_Tiles->TotalHeight(); @@ -47,6 +48,7 @@ GameWorld::GameWorld(GameReference *game_window, int width, int height) GameWorld::~GameWorld() { delete m_Tiles; + delete m_Particles; Entity *CurrentEntity = m_Last; while (CurrentEntity) @@ -435,6 +437,7 @@ void GameWorld::Tick() TickSpawner(); TickEntities(); TickDestroy(); + m_Particles->Tick(); TickCamera(); m_CurrentTick++; @@ -454,6 +457,7 @@ void GameWorld::Draw() Render->SetColor(255, 0, 0, 255); Render->DrawRectCamera(DrawRect); + m_Particles->Draw(); for (auto Current : m_FirstType) for (; Current; Current = Current->NextType()) Current->Draw(); diff --git a/src/game/GameWorld.h b/src/game/GameWorld.h index 34e15bf..6c32d4d 100644 --- a/src/game/GameWorld.h +++ b/src/game/GameWorld.h @@ -9,6 +9,7 @@ #include "indicators/TextSurface.h" #include "collision/TileMap.h" #include "../Protocol.h" +#include "../client/Particles.h" class Player; class Entity; @@ -18,6 +19,7 @@ class GameWorld { private: GameReference* m_GameWindow; TileMap* m_Tiles; + Particles* m_Particles; double m_Width, m_Height; double m_ShowNamesVisibility; bool m_ShowNames; @@ -53,6 +55,7 @@ class GameWorld { // Getting [[nodiscard]] GameReference* GameWindow() const { return m_GameWindow; } + [[nodiscard]] Particles* GetParticles() const { return m_Particles; }; [[nodiscard]] double GetWidth() const { return m_Width; } [[nodiscard]] double GetHeight() const { return m_Height; } [[nodiscard]] double GetNamesShown() const { return m_ShowNamesVisibility < 0.1 ? 0.0 : m_ShowNamesVisibility; } diff --git a/src/game/entities/Entity.cpp b/src/game/entities/Entity.cpp index 6e67f54..15e1065 100644 --- a/src/game/entities/Entity.cpp +++ b/src/game/entities/Entity.cpp @@ -167,6 +167,7 @@ const char* Entity::toString() const { // Add some velocity to this characters void Entity::Accelerate(const Vec2d& direction) { m_Core.Vel += direction; + std::cout << FStringColors("Accelerate %f, %f", m_Core.Vel.x, m_Core.Vel.y) << std::endl; } void Entity::Tick() { diff --git a/src/game/entities/Projectile.cpp b/src/game/entities/Projectile.cpp index d10ece2..a1b5a16 100644 --- a/src/game/entities/Projectile.cpp +++ b/src/game/entities/Projectile.cpp @@ -13,6 +13,7 @@ LoadedTexture Projectile::sTextureBurst("entity.projectile.burst"); LoadedTexture Projectile::sTextureShotgun("entity.projectile.shotgun"); LoadedTexture Projectile::sTextureSniper("entity.projectile.sniper"); LoadedTexture Projectile::sTextureMinigun("entity.projectile.minigun"); +LoadedTexture Projectile::sTextureSpark("entity.projectile.spark"); LoadedSound Projectile::sMetalImpactSounds[2] = { LoadedSound("entity.projectile.impact.metal.1"), LoadedSound("entity.projectile.impact.metal.2"), @@ -101,7 +102,7 @@ void Projectile::TickCollision() { if (Entity->GetType() == CHARACTER_ENTITY) { auto ShootableCharacter = (Character*)Entity; ShootableCharacter->Damage(m_Damage, m_Shooter); - ShootableCharacter->Accelerate(m_Core.Vel * 0.01 * m_Damage); + ShootableCharacter->Accelerate(direction * 0.5 * m_Damage); } else if (Entity->GetType() == CRATE_ENTITY) { auto ShootableCrate = (Crate*)Entity; ShootableCrate->Damage(m_Damage, m_Shooter); @@ -120,6 +121,15 @@ void Projectile::TickWallCollision() { if (m_Core.Pos.x < 0 || m_Core.Pos.x > m_World->GetWidth() || m_Core.Pos.y < 0 || m_Core.Pos.y > m_World->GetHeight()) { sMetalImpactSounds[rand() % 2].GetSound()->PlaySound(); + + if (m_Core.Pos.x < 0 || m_Core.Pos.x > m_World->GetWidth()) { m_Core.Vel.x *= -1; } + if (m_Core.Pos.y < 0 || m_Core.Pos.y > m_World->GetHeight()) { m_Core.Vel.y *= -1; } + for (int i = 0; i < 6; i++) { + auto vel = Vec2d(m_Core.Vel.x * (0.15 + 0.1 * (double)(rand()) / RAND_MAX) + 0.05 * (double)(rand()) / RAND_MAX, + m_Core.Vel.y * (0.15 + 0.1 * (double)(rand()) / RAND_MAX) + 0.05 * (double)(rand()) / RAND_MAX); + m_World->GetParticles()->PlayParticle(Particle(sTextureSpark.GetTexture(), m_Core.Pos, Vec2d(3.0, 5.0), vel, 0.98, 0.0, 0.0, 1.0, 20)); + } + m_Alive = false; } } @@ -133,7 +143,7 @@ void Projectile::Tick() { void Projectile::Draw() { Drawing* Render = m_World->GameWindow()->Render(); - double Angle = std::atan2(m_Core.Vel.y, m_Core.Vel.x) / M_PI * 180.0 + 90.0; + double Angle = std::atan2(m_Core.Vel.y, m_Core.Vel.x) / M_PI * 180.0 - 90.0; SDL_Rect BulletRect = { int(m_Core.Pos.x - m_Core.Size.x / 2.0), int(m_Core.Pos.y - m_Core.Size.y / 2.0), int(m_Core.Size.x), diff --git a/src/game/entities/Projectile.h b/src/game/entities/Projectile.h index f088889..c850cec 100644 --- a/src/game/entities/Projectile.h +++ b/src/game/entities/Projectile.h @@ -26,6 +26,7 @@ class Projectile : public Entity { static LoadedTexture sTextureShotgun; static LoadedTexture sTextureSniper; static LoadedTexture sTextureMinigun; + static LoadedTexture sTextureSpark; static LoadedSound sMetalImpactSounds[2]; Projectile(GameWorld* world, diff --git a/src/game/entities/characters/character/Character.cpp b/src/game/entities/characters/character/Character.cpp index 8e73163..b89e45a 100644 --- a/src/game/entities/characters/character/Character.cpp +++ b/src/game/entities/characters/character/Character.cpp @@ -50,6 +50,7 @@ LoadedTexture Character::sTextureErrorHealersParadise("icons.healing"); LoadedTexture Character::sTextureErrorRanged("icons.ranged"); LoadedTexture Character::sTextureErrorSlowDown("icons.slow"); LoadedTexture Character::sTextureErrorDangerousRecoil("icons.golden_apple"); +LoadedTexture Character::BLOOD("entity.character.blood"); // Link sounds LoadedSound Character::sHitSounds[3] = { @@ -473,6 +474,18 @@ void Character::AmmoPickup(AmmoBox* ammo_box) { } void Character::EventDeath() { + // Play a toned down version particle effect :) + BLOOD.GetTexture()->SetColorMod(255, 0, 0); // + auto particles = m_World->GetParticles(); + for (int i = 0; i < 50; i++) { + Vec2d vel = { m_Core.Vel.x * (double)(rand()) / RAND_MAX + 2.0 * ((double)(rand()) / RAND_MAX * 2.0 - 1.0), + m_Core.Vel.y * (double)(rand()) / RAND_MAX + 2.0 * ((double)(rand()) / RAND_MAX * 2.0 - 1.0) }; + + double size = 5.0 + (double)(rand()) / RAND_MAX * 10.0; + double orientation = (double)(rand()) / RAND_MAX * 360.0; + particles->PlayParticle(Particle(BLOOD.GetTexture(), m_Core.Pos, Vec2d(size, size), vel, 0.95, orientation, 20, 0.98, 200)); + } + for (int i = 0; i < NUM_WEAPONS; i++) { if (!m_Weapons[i]) continue; diff --git a/src/game/entities/characters/character/Character.h b/src/game/entities/characters/character/Character.h index b7238ab..a97b926 100644 --- a/src/game/entities/characters/character/Character.h +++ b/src/game/entities/characters/character/Character.h @@ -128,6 +128,7 @@ class Character : public DirectionalEntity { static LoadedTexture sTextureErrorRanged; static LoadedTexture sTextureErrorSlowDown; static LoadedTexture sTextureErrorDangerousRecoil; + static LoadedTexture BLOOD; static LoadedSound sHitSounds[3]; static LoadedSound sInvincibleHitSound; static LoadedSound sDeathSound; diff --git a/src/game/weapons/projectile/WeaponShotgun.cpp b/src/game/weapons/projectile/WeaponShotgun.cpp index ecbc64b..44954b7 100644 --- a/src/game/weapons/projectile/WeaponShotgun.cpp +++ b/src/game/weapons/projectile/WeaponShotgun.cpp @@ -27,7 +27,7 @@ WeaponShotgun::WeaponShotgun(Character* owner) m_PelletCount = 6; m_BaseRecoilForce = 20.0; m_RecoilForce = m_BaseRecoilForce; - m_Damage = 6; + m_Damage = 8; SetSpread(10.0, 3); SetRandomProjectileSpeed(13.0, 0.5, 1);