cs381/as4/as4.cpp

216 lines
6.1 KiB
C++

#include "AudioDevice.hpp"
#include "Color.hpp"
#include "Keyboard.hpp"
#include "Matrix.hpp"
#include "Mesh.hpp"
#include "Model.hpp"
#include "RadiansDegrees.hpp"
#include "Vector3.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, bool drawBoundingBox, 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
if (drawBoundingBox) {
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);
}
struct Entity {
raylib::Vector3 position = raylib::Vector3::Zero();
float speed = 0;
raylib::Degree heading = 0;
raylib::Model *model;
enum EntityType {
Penguin = 0,
Eagle = 1,
} type = EntityType::Penguin;
};
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 from_magnitude_and_heading(
float magnitude,
raylib::Degree heading
) {
return raylib::Vector3 {
magnitude * std::sin(heading.RadianValue()),
0,
magnitude * std::cos(heading.RadianValue())
};
}
// this is for the eagle to move in the xy plane
raylib::Vector3 from_magnitude_and_heading_xy(
float magnitude,
raylib::Degree heading
) {
return raylib::Vector3 {
magnitude * std::sin(heading.RadianValue()),
magnitude * std::cos(heading.RadianValue()),
0
};
}
const float ACCELERATION = 100.0f;
const raylib::Degree ANGULAR_VELOCITY = raylib::Degree(180.0f);
int main() {
raylib::Window window(800, 600, "CS381 - Assignment 3");
window.SetState(FLAG_WINDOW_RESIZABLE);
raylib::AudioDevice audio;
raylib::Model penguin("models/penguin.glb");
raylib::Model eagle("models/eagle.glb");
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, 200, -768 },
{ 0, -8, 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 &p1 = entities.emplace_back();
p1.model = &penguin;
p1.type = Entity::EntityType::Penguin;
p1.position = raylib::Vector3(0, 0, 0);
Entity &p2 = entities.emplace_back();
p2.model = &eagle;
p2.type = Entity::EntityType::Eagle;
p2.position = raylib::Vector3(200, 200, 0);
// penguin physics
raylib::Vector3 position = { 0, 0, 0 };
raylib::Vector3 velocity = { 0, 0, 0 };
float heading = 0.0f;
float speed = 0.0f;
int selectedIdx = 0;
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;
if (IsKeyPressed(KEY_TAB)) {
selectedIdx = (selectedIdx + 1) % entities.size();
}
Entity &selected = entities[selectedIdx];
if (IsKeyDown(KEY_W)) {
selected.speed += ACCELERATION * dt;
}
if (IsKeyDown(KEY_S)) {
selected.speed -= ACCELERATION * dt;
}
if (IsKeyDown(KEY_A)) {
selected.heading += dt * ANGULAR_VELOCITY;
}
if (IsKeyDown(KEY_D)) {
selected.heading -= dt * ANGULAR_VELOCITY;
}
if (IsKeyDown(KEY_SPACE)) {
selected.speed = 0.0f;
}
for (Entity &e : entities) {
e.heading = angle_normalize(e.heading);
}
camera.BeginMode();
skybox.Draw();
ground.Draw({ 0, 0, 0 }, 1.0f, raylib::Color::White());
for (size_t i = 0; i < entities.size(); ++i) {
Entity &e = entities[i];
if (e.type == Entity::EntityType::Eagle) {
e.position += from_magnitude_and_heading_xy(e.speed, e.heading) * dt;
} else {
e.position += from_magnitude_and_heading(e.speed, e.heading) * dt;
}
bool drawBox = (int)i == selectedIdx;
DrawBoundedModel(*e.model, drawBox, [&e](raylib::Matrix transform) {
if (e.type == Entity::EntityType::Eagle) {
return transform
.RotateZ(raylib::Degree(0) - e.heading)
.Scale(40, 40, 40)
.Translate(e.position);
} else {
return transform
.RotateY(e.heading)
.Scale(40, 40, 40)
.Translate(e.position);
}
});
}
camera.EndMode();
window.EndDrawing();
}
return 0;
}