Add
parent
a57505485e
commit
76b4223fea
476
as5/as5.cpp
476
as5/as5.cpp
|
|
@ -7,17 +7,33 @@
|
||||||
#include "RadiansDegrees.hpp"
|
#include "RadiansDegrees.hpp"
|
||||||
#include "Vector3.hpp"
|
#include "Vector3.hpp"
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
#include <BufferedRaylib.hpp>
|
||||||
|
#include <raylib-cpp.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <raylib-cpp.hpp>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define SKYBOX_IMPLEMENTATION
|
#define SKYBOX_IMPLEMENTATION
|
||||||
#include "skybox.hpp"
|
#include "skybox.hpp"
|
||||||
|
|
||||||
void DrawBoundedModel(raylib::Model &model, auto transformer) {
|
raylib::Degree angle_normalize(raylib::Degree angle) {
|
||||||
|
float decimal = float(angle) - int(angle);
|
||||||
|
int normalized = (int(angle) % 360 + 360) % 360;
|
||||||
|
return raylib::Degree(normalized + decimal);
|
||||||
|
}
|
||||||
|
|
||||||
|
raylib::Vector3 velocity_from_speed_heading(float speed, raylib::Degree heading) {
|
||||||
|
return raylib::Vector3{speed * std::sin(heading.RadianValue()), 0.0f,
|
||||||
|
speed * std::cos(heading.RadianValue())};
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawBoundedModel(raylib::Model &model, bool drawBoundingBox, auto transformer) {
|
||||||
// store the original transform to apply a different transform to the
|
// store the original transform to apply a different transform to the
|
||||||
// model without affecting the next time we draw
|
// model without affecting the next time we draw
|
||||||
raylib::Matrix oldTransform = model.GetTransform();
|
raylib::Matrix oldTransform = model.GetTransform();
|
||||||
|
|
@ -37,32 +53,40 @@ void DrawBoundedModel(raylib::Model &model, auto transformer) {
|
||||||
auto box = model.GetTransformedBoundingBox();
|
auto box = model.GetTransformedBoundingBox();
|
||||||
|
|
||||||
// draw the bounding box of the model using raylib's built in function
|
// draw the bounding box of the model using raylib's built in function
|
||||||
DrawBoundingBox(box, raylib::Color::White());
|
if (drawBoundingBox) {
|
||||||
|
DrawBoundingBox(box, raylib::Color::White());
|
||||||
|
}
|
||||||
|
|
||||||
// restore the model's transform to its original state so that the next time we
|
// restore the model's transform to its original state so that the next time we
|
||||||
// draw the model, it doesn't have the previous transform applied to it
|
// draw the model, it doesn't have the previous transform applied to it
|
||||||
model.SetTransform(oldTransform);
|
model.SetTransform(oldTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Entity;
|
||||||
|
class Component;
|
||||||
|
|
||||||
class Component {
|
class Component {
|
||||||
public:
|
public:
|
||||||
struct Entity *entity;
|
Entity *entity = nullptr;
|
||||||
|
|
||||||
virtual void Setup() = 0;
|
virtual void Setup() = 0;
|
||||||
virtual void Update(float dt) = 0;
|
virtual void Update(float dt) = 0;
|
||||||
virtual void Cleanup() = 0;
|
virtual void Cleanup() = 0;
|
||||||
|
|
||||||
|
virtual ~Component() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Entity {
|
struct Entity {
|
||||||
std::vector<std::shared_ptr<Component>> components;
|
std::vector<std::shared_ptr<Component>> components;
|
||||||
|
|
||||||
template<std::derived_from<Component> T>
|
template <std::derived_from<Component> T> T &AddComponent() {
|
||||||
T &AddComponent() {
|
auto &ptr = components.emplace_back(std::make_shared<T>());
|
||||||
std::shared_ptr<Component> out = components.emplace_back(std::make_shared<T>());
|
ptr->entity = this;
|
||||||
out->entity = this;
|
ptr->Setup();
|
||||||
return (T &)*out;
|
return static_cast<T &>(*ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<Component> T>
|
template <std::derived_from<Component> T>
|
||||||
std::optional<std::reference_wrapper<T>> GetComponent() const {
|
std::optional<std::reference_wrapper<T>> GetComponent() const {
|
||||||
for (auto &c : components) {
|
for (auto &c : components) {
|
||||||
T *cast = dynamic_cast<T *>(c.get());
|
T *cast = dynamic_cast<T *>(c.get());
|
||||||
|
|
@ -70,62 +94,28 @@ struct Entity {
|
||||||
return *cast;
|
return *cast;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
return { };
|
void Update(float dt) {
|
||||||
|
for (auto &c : components) {
|
||||||
|
c->Update(dt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TransformComponent : public Component {
|
template <typename T> struct Delegate {};
|
||||||
raylib::Vector3 position = { 0, 0, 0 };
|
|
||||||
raylib::Quaternion rotation = raylib::Quaternion::Identity();
|
|
||||||
|
|
||||||
void Setup() override { }
|
template <typename TReturn, typename... TArgs> struct Delegate<TReturn(TArgs...)> {
|
||||||
|
|
||||||
void Update(float dt) override { }
|
|
||||||
|
|
||||||
void Cleanup() override { }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DrawModelComponent : public Component {
|
|
||||||
raylib::Model *model;
|
|
||||||
|
|
||||||
void Setup() override { }
|
|
||||||
|
|
||||||
void Update(float dt) override {
|
|
||||||
DrawBoundedModel(*model, [this](raylib::Transform old) {
|
|
||||||
auto t = entity->GetComponent<TransformComponent>();
|
|
||||||
if (t) {
|
|
||||||
return old
|
|
||||||
.Translate(t->get().position)
|
|
||||||
.Rotate(t->get().rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return old;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cleanup() override { }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct Delegate { };
|
|
||||||
|
|
||||||
template<typename TReturn, typename... TArgs>
|
|
||||||
struct Delegate<TReturn(TArgs...)> {
|
|
||||||
std::vector<std::function<void(int)>> functions;
|
std::vector<std::function<void(int)>> functions;
|
||||||
|
|
||||||
void connect(const std::function<TReturn(TArgs ...)> &func) {
|
void connect(const std::function<TReturn(TArgs...)> &func) { functions.push_back(func); }
|
||||||
functions.push_back(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator+=(const std::function<TReturn(TArgs ...)> &func) {
|
void operator+=(const std::function<TReturn(TArgs...)> &func) { connect(func); }
|
||||||
connect(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(int arg) {
|
void operator()(int arg) {
|
||||||
static_assert(
|
static_assert(std::is_same_v<TReturn, void>,
|
||||||
std::is_same_v<TReturn, void>,
|
"EC HW: Delegate only supports void return type");
|
||||||
"EC HW: Delegate only supports void return type");
|
|
||||||
|
|
||||||
for (const auto &func : functions) {
|
for (const auto &func : functions) {
|
||||||
f(std::forward<TArgs>(arg)...);
|
f(std::forward<TArgs>(arg)...);
|
||||||
|
|
@ -133,62 +123,380 @@ struct Delegate<TReturn(TArgs...)> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
raylib::Degree angle_normalize(raylib::Degree angle) {
|
struct TransformComponent : public Component {
|
||||||
float decimal = float(angle) - int(angle);
|
raylib::Vector3 position = {0, 0, 0};
|
||||||
int normalized = (int(angle) % 360 + 360) % 360;
|
raylib::Degree heading = 0;
|
||||||
return raylib::Degree(normalized + decimal);
|
|
||||||
}
|
void Setup() override {}
|
||||||
|
void Update(float dt) override {}
|
||||||
|
void Cleanup() override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderComponent : public Component {
|
||||||
|
raylib::Model *model = nullptr;
|
||||||
|
bool drawBoundingBox = false;
|
||||||
|
float modelScale = 40.0f;
|
||||||
|
|
||||||
|
void Setup() override {}
|
||||||
|
void Cleanup() override {}
|
||||||
|
|
||||||
|
void Update(float dt) override {
|
||||||
|
if (!model) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto t = entity->GetComponent<TransformComponent>();
|
||||||
|
if (!t) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformComponent &tf = t->get();
|
||||||
|
|
||||||
|
DrawBoundedModel(*model, drawBoundingBox, [&tf, this](raylib::Matrix transform) {
|
||||||
|
return transform.RotateY(tf.heading)
|
||||||
|
.Scale(modelScale, modelScale, modelScale)
|
||||||
|
.Translate(tf.position);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PhysicsComponent : public Component {
|
||||||
|
raylib::Vector3 velocity = {0, 0, 0};
|
||||||
|
float maxSpeed = 300.0f;
|
||||||
|
float acceleration = 100.0f;
|
||||||
|
float turningRate = 90.0f;
|
||||||
|
|
||||||
|
void Setup() override {}
|
||||||
|
void Cleanup() override {}
|
||||||
|
|
||||||
|
void Update(float dt) override {
|
||||||
|
auto t = entity->GetComponent<TransformComponent>();
|
||||||
|
if (!t) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t->get().position = t->get().position + velocity * dt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrientedPhysicsComponent : public PhysicsComponent {
|
||||||
|
float speed = 0.0f;
|
||||||
|
|
||||||
|
void Setup() override {}
|
||||||
|
void Cleanup() override {}
|
||||||
|
|
||||||
|
void Update(float dt) override {
|
||||||
|
auto t = entity->GetComponent<TransformComponent>();
|
||||||
|
if (!t) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformComponent &tf = t->get();
|
||||||
|
|
||||||
|
speed = std::clamp(speed, -maxSpeed, maxSpeed);
|
||||||
|
|
||||||
|
velocity = velocity_from_speed_heading(speed, tf.heading);
|
||||||
|
|
||||||
|
tf.position = tf.position + velocity * dt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FollowComponent : public Component {
|
||||||
|
Entity *target = nullptr;
|
||||||
|
float hoverHeight = 200.0f;
|
||||||
|
float speed = 0.0f;
|
||||||
|
float maxSpeed = 250.0f;
|
||||||
|
float acceleration = 80.0f;
|
||||||
|
float turningRate = 120.0f;
|
||||||
|
float epsilon = 8.0f;
|
||||||
|
|
||||||
|
void Setup() override {}
|
||||||
|
void Cleanup() override {}
|
||||||
|
|
||||||
|
void Update(float dt) override {
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto myT = entity->GetComponent<TransformComponent>();
|
||||||
|
auto targetT = target->GetComponent<TransformComponent>();
|
||||||
|
if (!myT || !targetT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformComponent &myTf = myT->get();
|
||||||
|
TransformComponent &targetTf = targetT->get();
|
||||||
|
|
||||||
|
raylib::Vector3 desired = {targetTf.position.x, targetTf.position.y + hoverHeight,
|
||||||
|
targetTf.position.z};
|
||||||
|
|
||||||
|
raylib::Vector3 toDesired = desired - myTf.position;
|
||||||
|
float distXZ = std::sqrt(toDesired.x * toDesired.x + toDesired.z * toDesired.z);
|
||||||
|
|
||||||
|
if (distXZ > epsilon) {
|
||||||
|
float desiredHeadingRad = std::atan2(toDesired.x, toDesired.z);
|
||||||
|
raylib::Degree desiredHeading = raylib::Degree(desiredHeadingRad * RAD2DEG);
|
||||||
|
|
||||||
|
float diff = float(desiredHeading) - float(myTf.heading);
|
||||||
|
|
||||||
|
// norm to [-180, 180] for shortest turn direction
|
||||||
|
angle_normalize(raylib::Degree(diff + 180) - raylib::Degree(180));
|
||||||
|
|
||||||
|
float maxTurn = turningRate * dt;
|
||||||
|
float turn = std::clamp(diff, -maxTurn, maxTurn);
|
||||||
|
myTf.heading = angle_normalize(myTf.heading + raylib::Degree(turn));
|
||||||
|
|
||||||
|
speed = std::min(speed + acceleration * dt, maxSpeed);
|
||||||
|
} else {
|
||||||
|
speed = std::max(speed - acceleration * dt, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
raylib::Vector3 move = velocity_from_speed_heading(speed, myTf.heading);
|
||||||
|
|
||||||
|
myTf.position.x += move.x * dt;
|
||||||
|
myTf.position.z += move.z * dt;
|
||||||
|
|
||||||
|
float yDiff = desired.y - myTf.position.y;
|
||||||
|
myTf.position.y += yDiff * 5.0f * dt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InputComponent : public Component {
|
||||||
|
raylib::BufferedInput *input = nullptr;
|
||||||
|
bool isActive = false;
|
||||||
|
|
||||||
|
float axisForward = 0.0f;
|
||||||
|
float axisTurn = 0.0f;
|
||||||
|
bool keySpace = false;
|
||||||
|
|
||||||
|
void Setup() override {
|
||||||
|
if (!input) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
input->actions["forward"].AddCallback(
|
||||||
|
[this](float state, float delta) { axisForward = state; });
|
||||||
|
|
||||||
|
input->actions["turn"].AddCallback([this](float state, float delta) { axisTurn = state; });
|
||||||
|
|
||||||
|
input->actions["space"].AddCallback(
|
||||||
|
[this](float state, float delta) { keySpace = (state > 0.0f); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cleanup() override {}
|
||||||
|
|
||||||
|
void Update(float dt) override {
|
||||||
|
if (!isActive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// might not be efficient
|
||||||
|
auto oriented = entity->GetComponent<OrientedPhysicsComponent>();
|
||||||
|
auto tf = entity->GetComponent<TransformComponent>();
|
||||||
|
if (!tf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oriented) {
|
||||||
|
OrientedPhysicsComponent &phys = oriented->get();
|
||||||
|
|
||||||
|
float forward = axisForward;
|
||||||
|
float turn = axisTurn;
|
||||||
|
|
||||||
|
phys.speed += forward * phys.acceleration * dt;
|
||||||
|
tf->get().heading =
|
||||||
|
angle_normalize(tf->get().heading + raylib::Degree(turn * phys.turningRate * dt));
|
||||||
|
|
||||||
|
if (keySpace) {
|
||||||
|
phys.speed *= std::pow(0.05f, dt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto phys = entity->GetComponent<PhysicsComponent>();
|
||||||
|
if (!phys) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsComponent &p = phys->get();
|
||||||
|
|
||||||
|
float spd = std::sqrt(p.velocity.x * p.velocity.x + p.velocity.z * p.velocity.z);
|
||||||
|
float forward = axisForward;
|
||||||
|
float turn = axisTurn;
|
||||||
|
|
||||||
|
spd += forward * p.acceleration * dt;
|
||||||
|
tf->get().heading =
|
||||||
|
angle_normalize(tf->get().heading + raylib::Degree(turn * p.turningRate * dt));
|
||||||
|
|
||||||
|
if (keySpace) {
|
||||||
|
spd *= std::pow(0.05f, dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
spd = std::clamp(spd, -p.maxSpeed, p.maxSpeed);
|
||||||
|
p.velocity = velocity_from_speed_heading(spd, tf->get().heading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
raylib::Window window(800, 600, "CS381 - Assignment 5");
|
raylib::Window window(800, 600, "CS381 - Assignment 5");
|
||||||
window.SetState(FLAG_WINDOW_RESIZABLE);
|
window.SetState(FLAG_WINDOW_RESIZABLE);
|
||||||
raylib::AudioDevice audio;
|
raylib::AudioDevice audio;
|
||||||
|
|
||||||
raylib::Model penguin("models/penguin.glb");
|
raylib::Model penguinModel("models/penguin.glb");
|
||||||
raylib::Transform penguinTransform = raylib::Transform::Identity()
|
raylib::Model eagleModel("models/eagle.glb");
|
||||||
.Scale(40, 40, 40);
|
|
||||||
penguin.SetTransform(penguinTransform);
|
|
||||||
|
|
||||||
raylib::Camera3D camera(
|
auto defaultPenguinTf = (raylib::Transform)penguinModel.GetTransform();
|
||||||
{ 0, 400, -40 },
|
defaultPenguinTf = defaultPenguinTf.RotateY(raylib::Degree(90));
|
||||||
{ 0, -0.25f, 1 },
|
penguinModel.SetTransform(defaultPenguinTf);
|
||||||
{ 0, 1, 0 },
|
|
||||||
45.0f);
|
|
||||||
|
|
||||||
raylib::Model ground = raylib::Mesh::Plane(10000, 10000, 50, 50, 25);
|
raylib::Model ground = raylib::Mesh::Plane(10000, 10000, 50, 50, 25);
|
||||||
|
|
||||||
raylib::Texture snowTexture("textures/snow.jpg");
|
raylib::Texture snowTexture("textures/snow.jpg");
|
||||||
ground.GetMaterials()[0].maps[MATERIAL_MAP_DIFFUSE].texture = snowTexture;
|
ground.GetMaterials()[0].maps[MATERIAL_MAP_DIFFUSE].texture = snowTexture;
|
||||||
|
|
||||||
cs381::SkyBox skybox("textures/skybox.png");
|
cs381::SkyBox skybox("textures/skybox.png");
|
||||||
|
|
||||||
|
raylib::Camera3D camera({0, 400, -768}, {0, -8, 0}, {0, 1, 0}, 45.0f);
|
||||||
|
|
||||||
|
raylib::BufferedInput input;
|
||||||
|
|
||||||
|
input.actions["forward"] =
|
||||||
|
raylib::Action::button_axis({raylib::Button::key(KEY_W)}, {raylib::Button::key(KEY_S)})
|
||||||
|
.move();
|
||||||
|
input.actions["turn"] =
|
||||||
|
raylib::Action::button_axis({raylib::Button::key(KEY_A)}, {raylib::Button::key(KEY_D)})
|
||||||
|
.move();
|
||||||
|
input.actions["space"] = raylib::Action::key(KEY_SPACE).move();
|
||||||
|
input.actions["tab"] = raylib::Action::key(KEY_TAB).move();
|
||||||
|
|
||||||
std::vector<Entity> entities;
|
std::vector<Entity> entities;
|
||||||
|
entities.reserve(10);
|
||||||
|
|
||||||
Entity &e = entities.emplace_back();
|
auto makePenguin = [&](float xPos, float maxSpeed, float acceleration,
|
||||||
e.AddComponent<TransformComponent>();
|
float turningRate) -> Entity & {
|
||||||
e.AddComponent<DrawModelComponent>();
|
Entity &e = entities.emplace_back();
|
||||||
e.GetComponent<DrawModelComponent>()->get().model = &penguin;
|
|
||||||
|
|
||||||
window.SetTargetFPS(60); // save cpu cycles
|
auto &tf = e.AddComponent<TransformComponent>();
|
||||||
|
tf.position = raylib::Vector3(xPos, 0.0f, 0.0f);
|
||||||
|
tf.heading = raylib::Degree(90.0f); // face right
|
||||||
|
|
||||||
|
auto &phys = e.AddComponent<OrientedPhysicsComponent>();
|
||||||
|
phys.maxSpeed = maxSpeed;
|
||||||
|
phys.acceleration = acceleration;
|
||||||
|
phys.turningRate = turningRate;
|
||||||
|
|
||||||
|
auto &render = e.AddComponent<RenderComponent>();
|
||||||
|
render.model = &penguinModel;
|
||||||
|
|
||||||
|
auto &inp = e.AddComponent<InputComponent>();
|
||||||
|
inp.input = &input;
|
||||||
|
inp.Setup();
|
||||||
|
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
|
||||||
|
// helper to add an eagle that follows a specific penguin entity
|
||||||
|
auto makeEagle = [&](Entity &penguin, float xPos) -> Entity & {
|
||||||
|
Entity &e = entities.emplace_back();
|
||||||
|
|
||||||
|
auto &tf = e.AddComponent<TransformComponent>();
|
||||||
|
tf.position = raylib::Vector3(xPos, 200.0f, 0.0f);
|
||||||
|
tf.heading = raylib::Degree(90.0f);
|
||||||
|
|
||||||
|
auto &follow = e.AddComponent<FollowComponent>();
|
||||||
|
follow.target = &penguin;
|
||||||
|
follow.maxSpeed = 220.0f;
|
||||||
|
follow.acceleration = 70.0f;
|
||||||
|
follow.turningRate = 100.0f;
|
||||||
|
follow.hoverHeight = 200.0f;
|
||||||
|
|
||||||
|
auto &render = e.AddComponent<RenderComponent>();
|
||||||
|
render.model = &eagleModel;
|
||||||
|
|
||||||
|
auto &inp = e.AddComponent<InputComponent>();
|
||||||
|
inp.input = &input;
|
||||||
|
inp.Setup();
|
||||||
|
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
|
||||||
|
Entity &p0 = makePenguin(-400.0f, 50.0f, 50.0f, 90.0f);
|
||||||
|
Entity &p1 = makePenguin(-200.0f, 350.0f, 140.0f, 60.0f);
|
||||||
|
Entity &p2 = makePenguin(0.0f, 150.0f, 220.0f, 200.0f);
|
||||||
|
Entity &p3 = makePenguin(200.0f, 450.0f, 60.0f, 45.0f);
|
||||||
|
Entity &p4 = makePenguin(400.0f, 800.0f, 4000.0f, 500.0f);
|
||||||
|
|
||||||
|
makeEagle(p0, -400.0f);
|
||||||
|
makeEagle(p1, -200.0f);
|
||||||
|
makeEagle(p2, 0.0f);
|
||||||
|
makeEagle(p3, 200.0f);
|
||||||
|
makeEagle(p4, 400.0f);
|
||||||
|
|
||||||
|
int selectedIdx = 0;
|
||||||
|
|
||||||
|
input.actions["tab"].AddPressedCallback([&]() {
|
||||||
|
auto &old = entities[selectedIdx];
|
||||||
|
if (auto r = old.GetComponent<RenderComponent>()) {
|
||||||
|
r->get().drawBoundingBox = false;
|
||||||
|
}
|
||||||
|
if (auto i = old.GetComponent<InputComponent>()) {
|
||||||
|
i->get().isActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedIdx = (selectedIdx + 1) % (int)entities.size();
|
||||||
|
|
||||||
|
auto ¤t = entities[selectedIdx];
|
||||||
|
if (auto r = current.GetComponent<RenderComponent>()) {
|
||||||
|
r->get().drawBoundingBox = true;
|
||||||
|
}
|
||||||
|
if (auto i = current.GetComponent<InputComponent>()) {
|
||||||
|
i->get().isActive = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (auto r = entities[selectedIdx].GetComponent<RenderComponent>()) {
|
||||||
|
r->get().drawBoundingBox = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto i = entities[selectedIdx].GetComponent<InputComponent>()) {
|
||||||
|
i->get().isActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.SetTargetFPS(60);
|
||||||
|
|
||||||
while (!window.ShouldClose()) {
|
while (!window.ShouldClose()) {
|
||||||
|
float dt = window.GetFrameTime();
|
||||||
|
|
||||||
|
input.PollEvents();
|
||||||
|
|
||||||
window.BeginDrawing();
|
window.BeginDrawing();
|
||||||
window.ClearBackground(raylib::Color::Gray());
|
window.ClearBackground(raylib::Color::Gray());
|
||||||
|
|
||||||
float dt = window.GetFrameTime();
|
// could probably make the camera be an entity and have a transform
|
||||||
|
// and have a camera component but nah
|
||||||
|
if (auto tf = entities[selectedIdx].GetComponent<TransformComponent>()) {
|
||||||
|
TransformComponent &actualTfForReal = tf->get();
|
||||||
|
raylib::Vector3 forward = velocity_from_speed_heading(1.0f, actualTfForReal.heading);
|
||||||
|
|
||||||
|
const float camDistance = 768.0f;
|
||||||
|
const float camHeight = 400.0f;
|
||||||
|
|
||||||
|
camera.SetPosition({actualTfForReal.position.x - forward.x * camDistance,
|
||||||
|
actualTfForReal.position.y + camHeight,
|
||||||
|
actualTfForReal.position.z - forward.z * camDistance});
|
||||||
|
|
||||||
|
camera.SetTarget({actualTfForReal.position.x, actualTfForReal.position.y - 8.0f,
|
||||||
|
actualTfForReal.position.z});
|
||||||
|
}
|
||||||
|
|
||||||
camera.BeginMode();
|
camera.BeginMode();
|
||||||
|
|
||||||
skybox.Draw();
|
skybox.Draw();
|
||||||
|
ground.Draw({0, 0, 0}, 1.0f, raylib::Color::White());
|
||||||
|
|
||||||
ground.Draw({ 0, 0, 0 }, 1.0f, raylib::Color::White());
|
for (Entity &e : entities) {
|
||||||
|
e.Update(dt);
|
||||||
for (const Entity &e : entities) {
|
|
||||||
for (const std::shared_ptr<Component> &c : e.components) {
|
|
||||||
c->Update(dt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
camera.EndMode();
|
camera.EndMode();
|
||||||
|
|
||||||
window.EndDrawing();
|
window.EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue