243 lines
6.5 KiB
C++
243 lines
6.5 KiB
C++
#include "AudioDevice.hpp"
|
|
#include "Color.hpp"
|
|
#include "Keyboard.hpp"
|
|
#include "Matrix.hpp"
|
|
#include "Mesh.hpp"
|
|
#include "Model.hpp"
|
|
#include "RadiansDegrees.hpp"
|
|
#include "raylib.h"
|
|
#include <concepts>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <raylib-cpp.hpp>
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
#define SKYBOX_IMPLEMENTATION
|
|
#include "skybox.hpp"
|
|
|
|
void DrawBoundedModel(raylib::Model &model, auto transformer) {
|
|
// store the original transform to apply a different transform to the
|
|
// model without affecting the next time we draw
|
|
raylib::Matrix oldTransform = model.GetTransform();
|
|
|
|
// apply the transform that we get from whatever the transformer callback
|
|
// gives us
|
|
raylib::Matrix transform = transformer(model.GetTransform());
|
|
|
|
// apply the transform that we got from the transformer to the model
|
|
model.SetTransform(transform);
|
|
|
|
// draw the model, passing the origin and default scale as arguments since
|
|
// the transform is already applied to the model
|
|
model.Draw({ 0, 0, 0 }, 1.0f, raylib::Color::White());
|
|
|
|
// get the bounding box of the model after applying the transform
|
|
auto box = model.GetTransformedBoundingBox();
|
|
|
|
// draw the bounding box of the model using raylib's built in function
|
|
DrawBoundingBox(box, raylib::Color::White());
|
|
|
|
// 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
|
|
model.SetTransform(oldTransform);
|
|
}
|
|
|
|
class Component {
|
|
public:
|
|
struct Entity *e;
|
|
virtual void Setup() = 0;
|
|
virtual void Update(float dt) = 0;
|
|
virtual void Cleanup() = 0;
|
|
};
|
|
|
|
struct Entity {
|
|
std::vector<std::shared_ptr<Component>> components;
|
|
|
|
template<std::derived_from<Component> T>
|
|
T &AddComponent() {
|
|
auto out = components.emplace_back(std::make_shared<T>());
|
|
out->e = this;
|
|
return out;
|
|
}
|
|
|
|
template<std::derived_from<Component> T>
|
|
std::optional<std::reference_wrapper<T>> GetComponent() {
|
|
for (auto &c : components) {
|
|
T *cast = dynamic_cast<T *>(c.get());
|
|
if (cast) {
|
|
return *cast;
|
|
}
|
|
}
|
|
|
|
return { };
|
|
}
|
|
};
|
|
|
|
struct TransformComponent : public Component {
|
|
raylib::Transform t;
|
|
|
|
void Setup() override { }
|
|
|
|
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, []());
|
|
}
|
|
|
|
void Cleanup() override { }
|
|
};
|
|
|
|
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);
|
|
}
|
|
|
|
int main() {
|
|
raylib::Window window(800, 600, "CS381 - Assignment 3");
|
|
window.SetState(FLAG_WINDOW_RESIZABLE);
|
|
raylib::AudioDevice audio;
|
|
|
|
raylib::Model penguin("models/penguin.glb");
|
|
|
|
// behind and above the penguin (in penguin-local space)
|
|
const float CAM_DIST = 512.0f;
|
|
const float CAM_HEIGHT = 256.0f;
|
|
const float CAM_ANGULAR_VELOCITY = 2.0f;
|
|
const float CAM_PITCH_MIN = -0.5f;
|
|
const float CAM_PITCH_MAX = 1.5f;
|
|
|
|
float camYaw = 3.14f; // offset by 90 deg so it faces in the proper direction
|
|
float camPitch = 0;
|
|
|
|
raylib::Camera3D camera(
|
|
{ 0, CAM_DIST * std::sin(camPitch), CAM_DIST * std::cos(camPitch) },
|
|
{ 0, 0, 0 },
|
|
{ 0, 1, 0 },
|
|
45.0f);
|
|
|
|
raylib::Model ground = raylib::Mesh::Plane(10000, 10000, 50, 50, 25);
|
|
|
|
raylib::Texture snowTexture("textures/snow.jpg");
|
|
ground.GetMaterials()[0].maps[MATERIAL_MAP_DIFFUSE].texture = snowTexture;
|
|
|
|
cs381::SkyBox skybox("textures/skybox.png");
|
|
|
|
std::vector<Entity> entities;
|
|
|
|
Entity &e = entities.emplace_back();
|
|
e.AddComponent<TransformComponent>();
|
|
e.AddComponent<DrawModelComponent>();
|
|
|
|
// penguin physics
|
|
raylib::Vector3 position = { 0, 0, 0 };
|
|
raylib::Vector3 velocity = { 0, 0, 0 };
|
|
float heading = 0.0f;
|
|
float speed = 0.0f;
|
|
|
|
// units/s
|
|
const float ACCELERATION = 100.0f;
|
|
|
|
// in radians
|
|
const float ANGULAR_VELOCITY = 3.14f;
|
|
|
|
window.SetTargetFPS(60); // save cpu cycles
|
|
|
|
while (!window.ShouldClose()) {
|
|
window.BeginDrawing();
|
|
window.ClearBackground(raylib::Color::Gray());
|
|
|
|
float dt = window.GetFrameTime();
|
|
|
|
position += velocity * dt * 0.5f;
|
|
|
|
// movement for penguin
|
|
if (IsKeyDown(KEY_W)) {
|
|
speed += ACCELERATION * dt;
|
|
}
|
|
|
|
if (IsKeyDown(KEY_S)) {
|
|
speed -= ACCELERATION * dt;
|
|
}
|
|
|
|
if (IsKeyDown(KEY_A)) {
|
|
heading += ANGULAR_VELOCITY * dt;
|
|
}
|
|
|
|
if (IsKeyDown(KEY_D)) {
|
|
heading -= ANGULAR_VELOCITY * dt;
|
|
}
|
|
|
|
if (IsKeyDown(KEY_SPACE)) {
|
|
speed = 0.0f;
|
|
}
|
|
|
|
velocity = raylib::Vector3 {
|
|
std::sin(heading) * speed,
|
|
0.0f,
|
|
std::cos(heading) * speed
|
|
};
|
|
|
|
// ds = 1/2 * (v0 + v1) * dt
|
|
position += velocity * dt * 0.5f;
|
|
|
|
// movement for camera
|
|
if (IsKeyDown(KEY_LEFT)) {
|
|
camYaw += CAM_ANGULAR_VELOCITY * dt;
|
|
}
|
|
if (IsKeyDown(KEY_RIGHT)) {
|
|
camYaw -= CAM_ANGULAR_VELOCITY * dt;
|
|
}
|
|
if (IsKeyDown(KEY_UP)) {
|
|
camPitch += CAM_ANGULAR_VELOCITY * dt;
|
|
}
|
|
if (IsKeyDown(KEY_DOWN)) {
|
|
camPitch -= CAM_ANGULAR_VELOCITY * dt;
|
|
}
|
|
|
|
// clamp the angle between
|
|
camPitch = std::clamp(camPitch, CAM_PITCH_MIN, CAM_PITCH_MAX);
|
|
|
|
// x = cos(pitch) * sin(yaw)
|
|
// y = sin(pitch)
|
|
// z = cos(pitch) * cos(yaw)
|
|
float yaw = camYaw + heading; // follow penguin
|
|
raylib::Vector3 camOffset = {
|
|
CAM_DIST * std::cos(camPitch) * std::sin(yaw),
|
|
CAM_DIST * std::sin(camPitch) + CAM_HEIGHT,
|
|
CAM_DIST * std::cos(camPitch) * std::cos(yaw)
|
|
};
|
|
camera.SetPosition(position + camOffset);
|
|
camera.SetTarget(position);
|
|
|
|
camera.BeginMode();
|
|
skybox.Draw();
|
|
|
|
ground.Draw({ 0, 0, 0 }, 1.0f, raylib::Color::White());
|
|
|
|
DrawBoundedModel(penguin, [&position, &heading](raylib::Matrix transform) {
|
|
return transform
|
|
.RotateY(heading)
|
|
.Scale(40, 40, 40)
|
|
.Translate(position);
|
|
});
|
|
|
|
camera.EndMode();
|
|
window.EndDrawing();
|
|
}
|
|
|
|
return 0;
|
|
}
|