From f0ae12797b91ec8e0cda26ad720520b292ec024a Mon Sep 17 00:00:00 2001 From: HumanoidSandvichDispenser Date: Sun, 1 Mar 2026 11:54:41 -0800 Subject: [PATCH] Add monolithic entities --- as4/CMakeLists.txt | 4 +- as4/as4.cpp | 220 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 as4/as4.cpp diff --git a/as4/CMakeLists.txt b/as4/CMakeLists.txt index 3996146..1c19265 100644 --- a/as4/CMakeLists.txt +++ b/as4/CMakeLists.txt @@ -10,8 +10,8 @@ add_subdirectory(../raylib-cpp raylib) include(../assets/includeable.cmake) -add_executable(as3 CO.cpp skybox.cpp) -target_link_libraries(as3 PUBLIC raylib raylib_cpp) +add_executable(as4 as4.cpp skybox.cpp) +target_link_libraries(as4 PUBLIC raylib raylib_cpp) make_includeable(../assets/shaders/skybox.vs generated/skybox.vs) make_includeable(../assets/shaders/skybox.fs generated/skybox.fs) diff --git a/as4/as4.cpp b/as4/as4.cpp new file mode 100644 index 0000000..54eb2ec --- /dev/null +++ b/as4/as4.cpp @@ -0,0 +1,220 @@ +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} + +struct Entity { + raylib::Vector3 position = raylib::Vector3::Zero(); + float speed = 0; + raylib::Degree heading = 0; + raylib::Model *model; +}; + +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()) + }; +} + +// units/s +const float ACCELERATION = 100.0f; + +// in radians +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"); + + // 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 entities; + + Entity &ePenguin = entities.emplace_back(); + ePenguin.model = &penguin; + + Entity &eEagle = entities.emplace_back(); + eEagle.model = &eagle; + + // 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); + } + + // 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()); + + for (Entity &e : entities) { + e.position += from_magnitude_and_heading(e.speed, e.heading) * dt; + + DrawBoundedModel(*e.model, [&e](raylib::Matrix transform) { + return transform + .RotateY(e.heading) + .Scale(40, 40, 40) + .Translate(e.position); + }); + } + + camera.EndMode(); + window.EndDrawing(); + } + + return 0; +}