Add black hole obstacle
parent
f25a796073
commit
fb506f6f05
|
|
@ -70,6 +70,43 @@ std::shared_ptr<Entity> CreateGravityWell() {
|
|||
return e;
|
||||
}
|
||||
|
||||
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>();
|
||||
well.mass = static_cast<float>(1 << 21);
|
||||
well.minDist = 24.0f;
|
||||
well.controlledByMouse = false;
|
||||
well.alwaysActive = true;
|
||||
|
||||
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);
|
||||
DrawCircle(cx, cy, 18.0f, Color{8, 10, 20, 255});
|
||||
DrawCircleLines(cx, cy, 18.0f, Color{70, 95, 170, 240});
|
||||
DrawCircleLines(cx, cy, 24.0f, Color{95, 120, 200, 120});
|
||||
};
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
std::shared_ptr<Entity> CreateStar(float x, float y) {
|
||||
auto e = std::make_shared<Entity>();
|
||||
auto &t = e->AddComponent<TransformComponent>();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
std::shared_ptr<Entity> CreateProbe();
|
||||
std::shared_ptr<Entity> CreateGravityWell();
|
||||
std::shared_ptr<Entity> CreateBlackHole(float x, float y);
|
||||
std::shared_ptr<Entity> CreateStar(float x, float y);
|
||||
std::shared_ptr<Entity> CreateAsteroid(float x, float y);
|
||||
std::shared_ptr<Entity> CreateDebris(float x, float y, float vx, float vy, float ttl = 1.25f);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ void GravityWellComponent::Update(float dt) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!controlledByMouse) {
|
||||
active = alwaysActive;
|
||||
return;
|
||||
}
|
||||
|
||||
active = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
|
||||
|
||||
const Vector2 mouse = GetMousePosition();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,16 @@ struct GravityWellComponent : public Component {
|
|||
*/
|
||||
bool active = false;
|
||||
|
||||
/**
|
||||
* If true, active state is driven by left mouse button and this well follows the cursor.
|
||||
*/
|
||||
bool controlledByMouse = true;
|
||||
|
||||
/**
|
||||
* If true and not mouse-controlled, this well applies gravity every frame.
|
||||
*/
|
||||
bool alwaysActive = false;
|
||||
|
||||
/**
|
||||
* Lerp factor for how quickly the gravity well follows the mouse position.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -67,30 +67,20 @@ bool PhysicsComponent::IsInsideNullZone(double xPos) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool PhysicsComponent::ComputeWellDeltaVelocity(double px, double py, double dt, double &dvx,
|
||||
bool PhysicsComponent::ComputeGravityDeltaVelocity(double px, double py, double dt, double &dvx,
|
||||
double &dvy, bool ignoreWellActive) const {
|
||||
dvx = 0.0;
|
||||
dvy = 0.0;
|
||||
|
||||
if (!context || !context->wellEntity) {
|
||||
if (!context || !context->entities) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto wellTransform = context->wellEntity->GetComponent<TransformComponent>();
|
||||
auto wellGravity = context->wellEntity->GetComponent<GravityWellComponent>();
|
||||
if (!wellTransform || !wellGravity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ignoreWellActive && !wellGravity->get().active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Probe cannot receive well acceleration when meter is depleted.
|
||||
bool probeMeterDepleted = false;
|
||||
if (context && entity == context->probeEntity && context->statsEntity) {
|
||||
auto stats = context->statsEntity->GetComponent<StatsComponent>();
|
||||
if (stats && stats->get().value <= 0.0f) {
|
||||
return false;
|
||||
probeMeterDepleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,25 +88,49 @@ bool PhysicsComponent::ComputeWellDeltaVelocity(double px, double py, double dt,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool applied = false;
|
||||
for (auto &other : *context->entities) {
|
||||
if (!other || other.get() == entity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto wellTransform = other->GetComponent<TransformComponent>();
|
||||
auto wellGravity = other->GetComponent<GravityWellComponent>();
|
||||
if (!wellTransform || !wellGravity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (probeMeterDepleted && wellGravity->get().controlledByMouse) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ignoreWellActive && !wellGravity->get().active) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const double dx = static_cast<double>(wellTransform->get().x) - px;
|
||||
const double dy = static_cast<double>(wellTransform->get().y) - py;
|
||||
const double dist = std::sqrt(dx * dx + dy * dy);
|
||||
if (dist <= 0.0001) {
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const double clampedDist = std::max(dist, static_cast<double>(wellGravity->get().minDist));
|
||||
const double force = static_cast<double>(wellGravity->get().mass) / (clampedDist * clampedDist);
|
||||
dvx = (dx / dist) * force * dt;
|
||||
dvy = (dy / dist) * force * dt;
|
||||
return true;
|
||||
const double force =
|
||||
static_cast<double>(wellGravity->get().mass) / (clampedDist * clampedDist);
|
||||
dvx += (dx / dist) * force * dt;
|
||||
dvy += (dy / dist) * force * dt;
|
||||
applied = true;
|
||||
}
|
||||
|
||||
return applied;
|
||||
}
|
||||
|
||||
void PhysicsComponent::SimulateStep(double &xRef, double &yRef, double &vxRef, double &vyRef,
|
||||
double dt, bool ignoreWellActive) const {
|
||||
double dvx = 0.0;
|
||||
double dvy = 0.0;
|
||||
ComputeWellDeltaVelocity(xRef, yRef, dt, dvx, dvy, ignoreWellActive);
|
||||
ComputeGravityDeltaVelocity(xRef, yRef, dt, dvx, dvy, ignoreWellActive);
|
||||
vxRef += dvx;
|
||||
vyRef += dvy;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ struct PhysicsComponent : public Component {
|
|||
bool IsInsideNullZone(double xPos) const;
|
||||
|
||||
/**
|
||||
* Computes velocity delta from well gravity for a position.
|
||||
* Returns false when gravity should not apply.
|
||||
* Computes summed velocity delta from all gravity sources for a position.
|
||||
* Returns false when no gravity should apply.
|
||||
*/
|
||||
bool ComputeWellDeltaVelocity(double px, double py, double dt, double &dvx, double &dvy,
|
||||
bool ComputeGravityDeltaVelocity(double px, double py, double dt, double &dvx, double &dvy,
|
||||
bool ignoreWellActive = false) const;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -33,21 +33,26 @@ void SpawnComponent::Update(float) {
|
|||
|
||||
while (cursorWX < spawnLimit) {
|
||||
const float r = static_cast<float>(GetRandomValue(0, 99));
|
||||
if (r < 55.0f) {
|
||||
if (r < 50.0f) {
|
||||
const float y = static_cast<float>(GetRandomValue(48, GetScreenHeight() - 48));
|
||||
auto star = CreateStar(cursorWX, y);
|
||||
star->SetContext(context);
|
||||
context->entities->push_back(star);
|
||||
} else if (r < 88.0f) {
|
||||
} else if (r < 78.0f) {
|
||||
const float y = static_cast<float>(GetRandomValue(42, GetScreenHeight() - 42));
|
||||
auto asteroid = CreateAsteroid(cursorWX, y);
|
||||
asteroid->SetContext(context);
|
||||
context->entities->push_back(asteroid);
|
||||
} else {
|
||||
} else if (r < 95.0f) {
|
||||
const float width = static_cast<float>(GetRandomValue(70, 140));
|
||||
auto zone = CreateNullZone(cursorWX, width);
|
||||
zone->SetContext(context);
|
||||
context->entities->push_back(zone);
|
||||
} else {
|
||||
const float y = static_cast<float>(GetRandomValue(42, GetScreenHeight() - 42));
|
||||
auto blackHole = CreateBlackHole(cursorWX, y);
|
||||
blackHole->SetContext(context);
|
||||
context->entities->push_back(blackHole);
|
||||
}
|
||||
|
||||
const float gap =
|
||||
|
|
|
|||
Loading…
Reference in New Issue