cs381/as6/Entities.cpp

291 lines
9.5 KiB
C++

#include "Entities.hpp"
#include "Components.hpp"
#include "EnergyBarRaygui.hpp"
#include "raylib-cpp.hpp"
#include <algorithm>
// main controllable probe with meter, trail, and projection helpers
std::shared_ptr<Entity> CreateProbe() {
auto e = std::make_shared<Entity>();
auto &transform = e->AddComponent<TransformComponent>();
transform.x = 96.0f;
transform.y = 230.0f;
e->AddComponent<GravityReceiverComponent>();
auto &physics = e->AddComponent<PhysicsComponent>();
physics.vx = 16.0f;
physics.vy = 0.0f;
physics.speedCap = 8192.0f;
auto &collider = e->AddComponent<ColliderComponent>();
collider.radius = 7.0f;
collider.monitorable = true;
auto &probeState = e->AddComponent<ProbeStateComponent>();
probeState.spawnX = 96.0f;
probeState.spawnY = 230.0f;
probeState.spawnVx = 165.0f;
probeState.spawnVy = 0.0f;
e->AddComponent<TrailComponent>();
e->AddComponent<ProjectionComponent>();
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto transform = e->GetComponent<TransformComponent>();
if (!transform) {
return;
}
const raylib::Color probeColor(120, 210, 255, 255);
const raylib::Color probeHighlight(255, 255, 255, 120);
raylib::Vector2(transform->get().x, transform->get().y).DrawCircle(7.0f, probeColor);
raylib::Vector2(transform->get().x - 1.0f, transform->get().y - 1.0f)
.DrawCircle(3.0f, probeHighlight);
};
return e;
}
// helper controller entity for free cursor-based well placement
std::shared_ptr<Entity> CreateGravityWell() {
auto e = std::make_shared<Entity>();
auto &transform = e->AddComponent<TransformComponent>();
transform.x = 96.0f;
transform.y = 230.0f;
auto &well = e->AddComponent<GravityWellComponent>();
well.mass = 0.0f;
well.minDist = 28.0f;
return e;
}
// permanent hazard black hole that serves as a heavy obstacle
std::shared_ptr<Entity> CreateBlackHole(float x, float y) {
auto e = std::make_shared<Entity>();
auto &transform = e->AddComponent<TransformComponent>();
transform.x = x;
transform.y = y;
auto &scrollable = e->AddComponent<ScrollableComponent>();
scrollable.worldX = x;
auto &well = e->AddComponent<GravityWellComponent>();
// oversized static hazard that always pulls with high mass so the probe has to dodge it
well.mass = static_cast<float>(1 << 21);
well.minDist = 24.0f;
well.controlledByMouse = false;
well.alwaysActive = true;
// shader removed: previously used for black hole lensing
auto &collider = e->AddComponent<ColliderComponent>();
collider.radius = 18.0f;
e->AddComponent<HazardComponent>();
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto transform = e->GetComponent<TransformComponent>();
if (!transform) {
return;
}
const int cx = static_cast<int>(transform->get().x);
const int cy = static_cast<int>(transform->get().y);
raylib::Vector2(static_cast<float>(cx), static_cast<float>(cy))
.DrawCircle(18.0f, raylib::Color(8, 10, 20, 255));
::DrawCircleLines(cx, cy, 18.0f, raylib::Color(70, 95, 170, 240));
::DrawCircleLines(cx, cy, 24.0f, raylib::Color(95, 120, 200, 120));
};
return e;
}
// player-placed well that expires after ttl and can be cleared via right click
std::shared_ptr<Entity> CreatePlayerBlackHole(float worldX, float y, float scrollX, float ttl) {
auto e = std::make_shared<Entity>();
auto &transform = e->AddComponent<TransformComponent>();
transform.x = worldX - scrollX;
transform.y = y;
auto &scrollable = e->AddComponent<ScrollableComponent>();
scrollable.worldX = worldX;
auto &well = e->AddComponent<GravityWellComponent>();
// temporary player-placed well that drains meter and lasts exactly ttl seconds
well.mass = static_cast<float>(1 << 22);
well.minDist = 28.0f;
well.controlledByMouse = false;
well.alwaysActive = true;
// shader removed: previously used for black hole lensing
auto &lifetime = e->AddComponent<LifetimeComponent>();
lifetime.remaining = ttl;
// Mark this as a player-created black hole so it can be removed via right-click
e->AddComponent<PlayerBlackHoleComponent>();
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto transform = e->GetComponent<TransformComponent>();
if (!transform) {
return;
}
auto lifetime = e->GetComponent<LifetimeComponent>();
if (!lifetime) {
return;
}
const int cx = static_cast<int>(transform->get().x);
const int cy = static_cast<int>(transform->get().y);
float t = 360 * lifetime->get().remaining / 1;
::DrawCircleSector({(float)cx, (float)cy}, 28.0f, 0.0f, t, 32,
raylib::Color(70, 95, 170, 25));
::DrawCircleLines(cx, cy, 18.0f, raylib::Color(70, 95, 170, 240));
::DrawCircleLines(cx, cy, 24.0f, raylib::Color(95, 120, 200, 120));
};
return e;
}
// collectible star that restores meter and counts toward score
std::shared_ptr<Entity> CreateStar(float x, float y) {
auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>();
t.x = x;
t.y = y;
auto &scrollable = e->AddComponent<ScrollableComponent>();
scrollable.worldX = x;
auto &collider = e->AddComponent<ColliderComponent>();
collider.radius = 20.0f;
e->AddComponent<CollectibleComponent>();
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto transform = e->GetComponent<TransformComponent>();
if (!transform) {
return;
}
raylib::Vector2 center(transform->get().x, transform->get().y);
const raylib::Color starColor(255, 223, 86, 255);
const raylib::Color glowColor(255, 223, 86, 80);
center.DrawCircle(20.0f, glowColor);
center.DrawPoly(3, 10.0f, transform->get().x, starColor);
center.DrawPoly(3, 10.0f, transform->get().x + 180.0f, starColor);
};
return e;
}
// small hazard that nudges the player when hit
std::shared_ptr<Entity> CreateAsteroid(float x, float y) {
auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>();
t.x = x;
t.y = y;
auto &scrollable = e->AddComponent<ScrollableComponent>();
scrollable.worldX = x;
auto &collider = e->AddComponent<ColliderComponent>();
collider.radius = 13.0f;
e->AddComponent<HazardComponent>();
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto transform = e->GetComponent<TransformComponent>();
if (!transform) {
return;
}
raylib::Vector2(transform->get().x, transform->get().y)
.DrawCircle(13.0f, raylib::Color(116, 126, 142, 255));
};
return e;
}
// visual debris after collecting stars to reinforce feedback
std::shared_ptr<Entity> CreateDebris(float x, float y, float vx, float vy, float ttl) {
auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>();
t.x = x;
t.y = y;
auto &physics = e->AddComponent<PhysicsComponent>();
physics.vx = vx;
physics.vy = vy;
physics.speedCap = 260.0f;
auto &lifetime = e->AddComponent<LifetimeComponent>();
lifetime.remaining = ttl;
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto transform = e->GetComponent<TransformComponent>();
if (!transform) {
return;
}
raylib::Vector2(transform->get().x, transform->get().y)
.DrawCircle(3.0f, raylib::Color(245, 196, 104, 220));
};
return e;
}
// null zone that strips gravity and forces the player to avoid it
std::shared_ptr<Entity> CreateNullZone(float x, float width) {
auto e = std::make_shared<Entity>();
auto &t = e->AddComponent<TransformComponent>();
t.x = x;
auto &scrollable = e->AddComponent<ScrollableComponent>();
scrollable.worldX = x;
auto &nullZone = e->AddComponent<NullZoneComponent>();
nullZone.width = width;
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto transform = e->GetComponent<TransformComponent>();
auto zone = e->GetComponent<NullZoneComponent>();
if (!transform || !zone) {
return;
}
int x = (int)(transform->get().x);
raylib::Color(96, 64, 146, 80)
.DrawRectangle(x, 0, (int)(zone->get().width), raylib::Window::GetHeight());
raylib::Color(96, 64, 146, 200).DrawText("Null Zone", x + 8, 12, 16);
};
return e;
}
// world entity that owns scrolling and spawn logic
std::shared_ptr<Entity> CreateWorld() {
auto e = std::make_shared<Entity>();
e->AddComponent<ScrollComponent>();
e->AddComponent<SpawnComponent>();
return e;
}
// hud/stat tracker that shows meter and plays sounds
std::shared_ptr<Entity> CreateStats() {
auto e = std::make_shared<Entity>();
e->AddComponent<StatsComponent>();
auto &audio = e->AddComponent<AudioComponent>();
audio.volume = 0.6f;
audio.Load("assets/audio/ping.wav");
auto &render = e->AddComponent<RenderComponent>();
render.draw = [e]() {
auto stats = e->GetComponent<StatsComponent>();
if (!stats) {
return;
}
const float ratio = std::clamp(stats->get().value / stats->get().maxValue, 0.0f, 1.0f);
DrawHud(ratio, stats->get().GetStarCount());
};
return e;
}