cs381/as6/Components.hpp

371 lines
10 KiB
C++

#pragma once
#include "Entity.hpp"
#include "GameContext.hpp"
#include "raylib.h"
#include <algorithm>
#include <cmath>
#include <functional>
struct TransformComponent : public Component {
float x = 0.0f;
float y = 0.0f;
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};
struct PhysicsComponent : public Component {
float vx = 0.0f;
float vy = 0.0f;
float speedCap = 400.0f;
void Setup() override {}
void Update(float dt) override {
auto transform = entity->GetComponent<TransformComponent>();
if (!transform) {
return;
}
const float speed = std::sqrt(vx * vx + vy * vy);
if (speed > speedCap && speed > 0.0f) {
const float scale = speedCap / speed;
vx *= scale;
vy *= scale;
}
transform->get().x += vx * dt;
transform->get().y += vy * dt;
}
void Cleanup() override {}
};
struct GravityWellComponent : public Component {
float mass = 150000.0f;
float minDist = 30.0f;
bool active = false;
float followLerp = 12.0f;
void Setup() override {}
void Update(float dt) override {
auto transform = entity->GetComponent<TransformComponent>();
if (!transform) {
return;
}
active = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
const Vector2 mouse = GetMousePosition();
auto &t = transform->get();
const float blend = std::clamp(followLerp * dt, 0.0f, 1.0f);
t.x += (mouse.x - t.x) * blend;
t.y += (mouse.y - t.y) * blend;
}
void Cleanup() override {}
};
struct ScrollComponent : public Component {
float scrollX = 0.0f;
float speed = 2.0f;
float accel = 0.018f;
void Setup() override {}
void Update(float dt) override {
speed += accel * dt;
scrollX += speed * dt * 60.0f;
if (context) {
context->scrollX = scrollX;
}
}
void Cleanup() override {}
};
struct MeterComponent : public Component {
float value = 60.0f;
float maxValue = 100.0f;
float drainRate = 14.0f;
float gainPerStar = 28.0f;
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};
struct NullZoneComponent : public Component {
float width = 70.0f;
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};
struct ColliderComponent : public Component {
float radius = 8.0f;
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};
struct ScrollableComponent : public Component {
float worldX = 0.0f;
void Setup() override {}
void Update(float) override {
if (!context) {
return;
}
auto transform = entity->GetComponent<TransformComponent>();
if (!transform) {
return;
}
transform->get().x = worldX - context->scrollX;
}
void Cleanup() override {}
};
struct SpawnComponent : public Component {
float cursorWX = 0.0f;
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};
struct TrailComponent : public Component {
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};
struct ProjectionComponent : public Component {
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};
struct CollectibleComponent : public Component {
bool collected = false;
void Setup() override {}
void Update(float) override {
if (collected || !context || !context->probeEntity || entity == context->probeEntity) {
return;
}
auto selfTransform = entity->GetComponent<TransformComponent>();
auto selfCollider = entity->GetComponent<ColliderComponent>();
auto probeTransform = context->probeEntity->GetComponent<TransformComponent>();
auto probeCollider = context->probeEntity->GetComponent<ColliderComponent>();
if (!selfTransform || !selfCollider || !probeTransform || !probeCollider) {
return;
}
const float dx = selfTransform->get().x - probeTransform->get().x;
const float dy = selfTransform->get().y - probeTransform->get().y;
const float r = selfCollider->get().radius + probeCollider->get().radius;
if ((dx * dx + dy * dy) > (r * r)) {
return;
}
collected = true;
if (!context->hudEntity) {
return;
}
auto meter = context->hudEntity->GetComponent<MeterComponent>();
if (!meter) {
return;
}
meter->get().value =
std::min(meter->get().maxValue, meter->get().value + meter->get().gainPerStar);
}
void Cleanup() override {}
};
struct HazardComponent : public Component {
void Setup() override {}
void Update(float) override {
if (!context || !context->probeEntity || entity == context->probeEntity) {
return;
}
auto selfTransform = entity->GetComponent<TransformComponent>();
auto selfCollider = entity->GetComponent<ColliderComponent>();
auto probeTransform = context->probeEntity->GetComponent<TransformComponent>();
auto probeCollider = context->probeEntity->GetComponent<ColliderComponent>();
if (!selfTransform || !selfCollider || !probeTransform || !probeCollider) {
return;
}
const float dx = selfTransform->get().x - probeTransform->get().x;
const float dy = selfTransform->get().y - probeTransform->get().y;
const float r = selfCollider->get().radius + probeCollider->get().radius;
if ((dx * dx + dy * dy) <= (r * r)) {
context->resetRequested = true;
}
}
void Cleanup() override {}
};
struct GravityReceiverComponent : public Component {
Entity *well = nullptr;
bool inVoid = false;
void Setup() override {}
void Update(float dt) override {
if (!context || !context->probeEntity || entity != context->probeEntity) {
return;
}
if (!well && context->wellEntity) {
well = context->wellEntity;
}
if (!well) {
return;
}
auto myTransform = entity->GetComponent<TransformComponent>();
auto physics = entity->GetComponent<PhysicsComponent>();
auto wellTransform = well->GetComponent<TransformComponent>();
auto wellGravity = well->GetComponent<GravityWellComponent>();
if (!myTransform || !physics || !wellTransform || !wellGravity) {
return;
}
MeterComponent *meterPtr = nullptr;
if (context->hudEntity) {
auto meter = context->hudEntity->GetComponent<MeterComponent>();
if (meter) {
meterPtr = &meter->get();
}
}
if (!wellGravity->get().active) {
return;
}
if (meterPtr && meterPtr->value <= 0.0f) {
return;
}
inVoid = false;
if (context->entities) {
for (auto &other : *context->entities) {
if (!other || other.get() == entity) {
continue;
}
auto zone = other->GetComponent<NullZoneComponent>();
auto zoneTransform = other->GetComponent<TransformComponent>();
if (!zone || !zoneTransform) {
continue;
}
const float left = zoneTransform->get().x;
const float right = left + zone->get().width;
if (myTransform->get().x >= left && myTransform->get().x <= right) {
inVoid = true;
break;
}
}
}
if (inVoid) {
return;
}
const float dx = wellTransform->get().x - myTransform->get().x;
const float dy = wellTransform->get().y - myTransform->get().y;
const float dist = std::sqrt(dx * dx + dy * dy);
if (dist <= 0.0001f) {
return;
}
const float clampedDist = std::max(dist, wellGravity->get().minDist);
const float force = wellGravity->get().mass / (clampedDist * clampedDist);
const float nx = dx / dist;
const float ny = dy / dist;
physics->get().vx += nx * force * dt;
physics->get().vy += ny * force * dt;
if (meterPtr) {
meterPtr->value = std::max(0.0f, meterPtr->value - meterPtr->drainRate * dt);
}
}
void Cleanup() override {}
};
struct ProbeStateComponent : public Component {
float spawnX = 96.0f;
float spawnY = 230.0f;
float spawnVx = 165.0f;
float spawnVy = 0.0f;
void Setup() override {}
void Update(float) override {
if (!context || !context->probeEntity || entity != context->probeEntity) {
return;
}
auto transform = entity->GetComponent<TransformComponent>();
auto physics = entity->GetComponent<PhysicsComponent>();
if (!transform || !physics) {
return;
}
if (transform->get().y < -20.0f ||
transform->get().y > static_cast<float>(GetScreenHeight() + 20) ||
transform->get().x < -20.0f) {
context->resetRequested = true;
}
if (!context->resetRequested) {
return;
}
transform->get().x = spawnX;
transform->get().y = spawnY;
physics->get().vx = spawnVx;
physics->get().vy = spawnVy;
if (context->hudEntity) {
auto meter = context->hudEntity->GetComponent<MeterComponent>();
if (meter) {
meter->get().value = 60.0f;
}
}
if (context->entities) {
for (auto &other : *context->entities) {
if (!other) {
continue;
}
auto collectible = other->GetComponent<CollectibleComponent>();
if (collectible) {
collectible->get().collected = false;
}
}
}
context->resetRequested = false;
}
void Cleanup() override {}
};
struct HudComponent : public Component {
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};
struct RenderComponent : public Component {
std::function<void()> draw;
virtual void Draw() {
if (draw) {
draw();
}
}
void Setup() override {}
void Update(float) override {}
void Cleanup() override {}
};