#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, 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 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; }