357 lines
9.4 KiB
C++
357 lines
9.4 KiB
C++
#pragma once
|
|
|
|
#include "Entity.hpp"
|
|
#include "GameContext.hpp"
|
|
|
|
#include "raylib.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <functional>
|
|
#include <vector>
|
|
|
|
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 SetValue(float newValue) {
|
|
const float oldValue = value;
|
|
value = newValue;
|
|
if (context && oldValue != value) {
|
|
context->EmitMeterChanged(oldValue, value);
|
|
}
|
|
}
|
|
|
|
void AddValue(float delta) { SetValue(std::clamp(value + delta, 0.0f, maxValue)); }
|
|
|
|
void Drain(float amount) { AddValue(-amount); }
|
|
|
|
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;
|
|
std::vector<std::function<void(Entity &)>> onCollision;
|
|
void Setup() override {}
|
|
|
|
void EmitCollision(Entity &other) {
|
|
for (auto &callback : onCollision) {
|
|
callback(other);
|
|
}
|
|
}
|
|
|
|
void AddCollisionListener(std::function<void(Entity &)> callback) {
|
|
onCollision.push_back(std::move(callback));
|
|
}
|
|
|
|
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 {
|
|
auto selfCollider = entity->GetComponent<ColliderComponent>();
|
|
if (!selfCollider) {
|
|
return;
|
|
}
|
|
|
|
selfCollider->get().AddCollisionListener([this](Entity &other) {
|
|
if (collected || !context || !context->probeEntity || &other != context->probeEntity) {
|
|
return;
|
|
}
|
|
|
|
collected = true;
|
|
context->EmitCollectiblePicked(*entity);
|
|
|
|
if (!context->hudEntity) {
|
|
return;
|
|
}
|
|
|
|
auto meter = context->hudEntity->GetComponent<MeterComponent>();
|
|
if (!meter) {
|
|
return;
|
|
}
|
|
|
|
meter->get().AddValue(meter->get().gainPerStar);
|
|
});
|
|
}
|
|
|
|
void Update(float) override {}
|
|
|
|
void Cleanup() override {}
|
|
};
|
|
|
|
struct HazardComponent : public Component {
|
|
void Setup() override {
|
|
auto selfCollider = entity->GetComponent<ColliderComponent>();
|
|
if (!selfCollider) {
|
|
return;
|
|
}
|
|
|
|
selfCollider->get().AddCollisionListener([this](Entity &other) {
|
|
if (!context || !context->probeEntity || &other != context->probeEntity) {
|
|
return;
|
|
}
|
|
|
|
if (context->onPlayerDeath) {
|
|
context->onPlayerDeath();
|
|
}
|
|
});
|
|
}
|
|
void Update(float) override {}
|
|
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->Drain(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>();
|
|
if (!transform) {
|
|
return;
|
|
}
|
|
|
|
if (transform->get().y < -20.0f ||
|
|
transform->get().y > static_cast<float>(GetScreenHeight() + 20) ||
|
|
transform->get().x < -20.0f) {
|
|
if (context->onPlayerDeath) {
|
|
context->onPlayerDeath();
|
|
}
|
|
}
|
|
}
|
|
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 {}
|
|
};
|