diff --git a/.gitignore b/.gitignore index 217a3aa..4ccf327 100644 --- a/.gitignore +++ b/.gitignore @@ -366,3 +366,4 @@ FodyWeavers.xsd *.swp /Resources/scenes/.debugScene.xml.swp compile_commands.json +compile_flags.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..c0b958e --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# Personal Game Engine + +A modular, event driven 2D game engine, built from scratch to learn engine architecture and low-level graphics programming. + +Supports sprite-based animation, Lua scripting, XML-driven definitions and Tiled map creation. + +--- + +## Features + +- Event-based animation and sound system +- Animation and tile-sets supported by texture atlases +- Map creation and collision map support in Tiled map editor +- Component-based entity structure +- Basic audio engine integration via OpenAL (XML definitions) +- Basic physics system +- Lua scripted enemy and weapon behavior + +--- + +## Current Status + +**Work in Progress** - This project is still under active development, I am currently cleaning up my resource management system for better ease of use for future users of this engine. + +--- + +## Dependencies + +- SDL2, SDL2_image +- OpenGL 3.3 +- sol2 (Lua binding) +- TinyXML2 +- OpenAL +- Freetype +- GLM +- pkg-config +- CMake + +## Build Instructions + +1. Clone the repo (git.wienermeister.net/snakert12345/yupplemayham.git) +2. Install list of dependencies. Ensure they're available via pkg-config +3. Build with CMake + +```bash +git clone https://git.wienermeister.net/snakert12345/yupplemayham.git +cd yupplemayham +mkdir build && cd build +cmake .. +make +``` + +--- + +## Screenshot + +![Screenshot](https://git.wienermeister.net/attachments/79b04767-d675-4aa3-a17e-969341105579) + +--- + +## Roadmap + +- Save/Load system +- Modular and scalable menu system +- In-game dialog and conversation systems +- Expanded combat system diff --git a/YuppleMayham/include/gameplay/camera.h b/YuppleMayham/include/gameplay/camera.h index 055e3da..2412ce5 100644 --- a/YuppleMayham/include/gameplay/camera.h +++ b/YuppleMayham/include/gameplay/camera.h @@ -3,42 +3,43 @@ #include "gameplay/entity.h" -class Camera -{ +class Camera { public: - Camera(float viewPortW, float viewPortH) : - position(glm::vec3(0.0f, 0.0f, 0.0f)), - front(glm::vec3(0.0f, 0.0f, -1.0f)), - up(glm::vec3(0.0f, 1.0f, 0.0f)), - viewPortW(viewPortW), - viewPortH(viewPortH) - {}; + Camera(float viewPortW, float viewPortH) + : position(glm::vec3(0.0f, 0.0f, 0.0f)), + front(glm::vec3(0.0f, 0.0f, -1.0f)), up(glm::vec3(0.0f, 1.0f, 0.0f)), + viewPortW(viewPortW), viewPortH(viewPortH) {}; - void setPosition(const glm::vec3& position) { this->position = position; } + void setPosition(const glm::vec3 &position) { this->position = position; } - const Entity* getTarget() const { return target; } - const glm::vec3 getCenterPos() const { return glm::vec3(position.x + (viewPortW / 2.f), position.y + (viewPortH / 2.f), 0.0f); } - void setTarget(Entity* target) { this->target = target; } - void unsetTarget() { target = nullptr; } - bool isTargeting() { return (target != nullptr); } + const Entity *getTarget() const { return target; } + const glm::vec3 getCenterPos() const { + return glm::vec3(position.x + (viewPortW / 2.f), + position.y + (viewPortH / 2.f), 0.0f); + } + void setTarget(Entity *target) { this->target = target; } + void unsetTarget() { target = nullptr; } + bool isTargeting() { return (target != nullptr); } - void update(double deltaTime); + void update(double deltaTime); + void setViewportSize(float width, float height); - const glm::vec3 worldToLocal(const glm::vec3& worldCoordinates); + const glm::vec3 worldToLocal(const glm::vec3 &worldCoordinates); + + glm::mat4 getViewMatrix(); + glm::mat4 getProjectionMatrix(); + const glm::vec3 getPosition() const { return position; } - glm::mat4 getViewMatrix(); - glm::mat4 getProjectionMatrix(); - const glm::vec3 getPosition() const { return position; } private: - Entity* target = nullptr; + Entity *target = nullptr; - glm::vec3 position; - glm::vec3 front; - glm::vec3 up; + glm::vec3 position; + glm::vec3 front; + glm::vec3 up; - float viewPortW, viewPortH; + float viewPortW, viewPortH; - float speed = 300.0f; + float speed = 300.0f; }; -#endif // _H_CAMERA_H \ No newline at end of file +#endif // _H_CAMERA_H diff --git a/YuppleMayham/include/graphics/glwindow.h b/YuppleMayham/include/graphics/glwindow.h index d4ea144..904f2e2 100644 --- a/YuppleMayham/include/graphics/glwindow.h +++ b/YuppleMayham/include/graphics/glwindow.h @@ -20,6 +20,8 @@ public: unsigned Width() const { return w; } unsigned Height() const { return h; } + void resizeWindow(size_t w, size_t h); + SDL_Window *getWindow() const { return window; } const SDL_GLContext &getContext() const { return glContext; } diff --git a/YuppleMayham/include/graphics/renderer.h b/YuppleMayham/include/graphics/renderer.h index 41f81ac..9930dbd 100644 --- a/YuppleMayham/include/graphics/renderer.h +++ b/YuppleMayham/include/graphics/renderer.h @@ -56,6 +56,8 @@ private: void initFrameBuffers(); void initUniformBuffers(); + void resizeFrameBuffers(); + std::unique_ptr postProcessor; void sortLayerPool(auto &layerPool); diff --git a/YuppleMayham/include/utility/events.h b/YuppleMayham/include/utility/events.h index 0f6c23f..25c822d 100644 --- a/YuppleMayham/include/utility/events.h +++ b/YuppleMayham/include/utility/events.h @@ -1,10 +1,10 @@ #ifndef _H_EVENTS_H #define _H_EVENTS_H +#include +#include #include #include -#include -#include #include #include "utility/direction.h" @@ -14,90 +14,90 @@ class Bullet; struct PhysicsComponent; struct BulletFiredEvent { - std::weak_ptr bullet; + std::weak_ptr bullet; }; struct BulletDiedEvent { - std::shared_ptr physObj; + std::shared_ptr physObj; }; struct BulletCollideEvent { - unsigned int ownerID; - unsigned int victimID; - std::shared_ptr bullet; - glm::vec2 normal; + unsigned int ownerID; + unsigned int victimID; + std::shared_ptr bullet; + glm::vec2 normal; }; struct DirectionChangeEvent { - int entityid; - Direction direction; + int entityid; + Direction direction; }; struct EntityMoveEvent { - int entityid; + int entityid; }; struct EntityStopEvent { - int entityid; + int entityid; }; struct EntityReloadEvent { - int entityid; - glm::vec3 position; - std::string weaponType; + int entityid; + glm::vec3 position; + std::string weaponType; }; struct EntityFinishReloadEvent { - int entityid; + int entityid; }; struct EntityFireEvent { - int entityid; - float fireDelay; - glm::vec3 firePosition; - std::string weaponType; + int entityid; + float fireDelay; + glm::vec3 firePosition; + std::string weaponType; }; struct AnimationFinishedEvent { - int entityid; - std::string animType; + int entityid; + std::string animType; }; struct ScreenShakeEvent { - float intensity; - float duration; + float intensity; + float duration; }; struct ScreenBlurEvent { - float intensity; - float duration; + float intensity; + float duration; +}; + +struct WindowResizeEvent { + size_t width; + size_t height; }; class EventManager { public: - template - using EventCallback = std::function; + template using EventCallback = std::function; + + template void subscribe(EventCallback cb) { + auto wrapper = [cb](void *ev) { cb(*static_cast(ev)); }; + callbacks[typeid(T)].push_back(wrapper); + } + template void notify(const T &event) { + auto iterator = callbacks.find(typeid(T)); + if (iterator != callbacks.end()) { + for (auto &cb : iterator->second) { + cb((void *)&event); + } + } + } - template - void subscribe(EventCallback cb) { - auto wrapper = [cb](void *ev) { - cb(*static_cast(ev)); - }; - callbacks[typeid(T)].push_back(wrapper); - } - template - void notify(const T& event) { - auto iterator = callbacks.find(typeid(T)); - if (iterator != callbacks.end()) - { - for (auto& cb : iterator->second) - { - cb((void*)&event); - } - } - } private: - std::unordered_map >> callbacks; + std::unordered_map>> + callbacks; }; #endif //_H_EVENTS_H diff --git a/YuppleMayham/src/gameplay/ai.cpp b/YuppleMayham/src/gameplay/ai.cpp index 47a3fc1..9e8719b 100644 --- a/YuppleMayham/src/gameplay/ai.cpp +++ b/YuppleMayham/src/gameplay/ai.cpp @@ -4,103 +4,91 @@ #include "utility/raycaster.h" #include "utility/script.h" -AI::AI(GameActor* actor, std::unique_ptr raycaster) - : state(AIState::Idle), raycaster(std::move(raycaster)), actor(actor), - lastGCTime(std::chrono::high_resolution_clock::now()), GCTimeout(3) -{} +AI::AI(GameActor *actor, std::unique_ptr raycaster) + : state(AIState::Idle), raycaster(std::move(raycaster)), actor(actor), + lastGCTime(std::chrono::high_resolution_clock::now()), GCTimeout(3) {} -/* - * The behavior script works off of three different states, idle, patrol and alert. - * When the script is idle, this is */ -void AI::attachBehaviourScript(std::unique_ptr behaviour) -{ - // passing out instance of raycaster and this AI into our scripting api - // pay special attention each ai script has control of only their own instance of ai! - this->behaviour = std::move(behaviour); - this->behaviour->lua["raycaster"] = sol::make_reference(this->behaviour->lua, raycaster.get()); - this->behaviour->lua["ai"] = sol::make_reference(this->behaviour->lua, this); +/* + * The behavior script works off of three different states, idle, patrol and + * alert. When the script is idle, this is */ +void AI::attachBehaviourScript(std::unique_ptr behaviour) { + // passing out instance of raycaster and this AI into our scripting api + // pay special attention each ai script has control of only their own instance + // of ai! + this->behaviour = std::move(behaviour); + this->behaviour->lua["raycaster"] = + sol::make_reference(this->behaviour->lua, raycaster.get()); + this->behaviour->lua["ai"] = sol::make_reference(this->behaviour->lua, this); - idleFunc = this->behaviour->lua["idle"]; - patrolFunc = this->behaviour->lua["patrol"]; - alertFunc = this->behaviour->lua["alert"]; + idleFunc = this->behaviour->lua["idle"]; + patrolFunc = this->behaviour->lua["patrol"]; + alertFunc = this->behaviour->lua["alert"]; } -void AI::update() -{ - try { - // If our ai doesn't have a reference to the actor it's controlling it will do nothing. - // If our ai script does have an actor but no target, it will default to its idle state. - if (actor && target) { - switch (state) - { - case AIState::Idle: - if (idleFunc.valid()) - { - auto result = idleFunc(actor, target); - if (!result.valid()) - { - sol::error err = result; +void AI::update() { + try { + // If our ai doesn't have a reference to the actor it's controlling it will + // do nothing. If our ai script does have an actor but no target, it will + // default to its idle state. + if (actor && target) { + switch (state) { + case AIState::Idle: + if (idleFunc.valid()) { + auto result = idleFunc(actor, target); + if (!result.valid()) { + sol::error err = result; LOG(ERROR, "Lua error: {}", err.what(), NULL); - } - } - break; - case AIState::Patrol: - if (patrolFunc.valid()) - { - auto result = patrolFunc(actor, target); - if (!result.valid()) - { - sol::error err = result; - LOG(ERROR, "Lua error: {}", err.what(), NULL); - } - } - break; - case AIState::Alert: - if (alertFunc.valid()) - { - auto result = alertFunc(actor, target); - if (!result.valid()) - { - sol::error err = result; - LOG(ERROR, "Lua error: {}", err.what(), NULL); - } - } - break; - } - } else if (actor) { - switch (state) - { - case AIState::Idle: - if (idleFunc.valid()) { - auto result = idleFunc(actor, nullptr); - if (!result.valid()) { - sol::error err = result; - LOG(ERROR, "Lua Error: {}", err.what()); - } } + } + break; + case AIState::Patrol: + if (patrolFunc.valid()) { + auto result = patrolFunc(actor, target); + if (!result.valid()) { + sol::error err = result; + LOG(ERROR, "Lua error: {}", err.what(), NULL); + } + } + break; + case AIState::Alert: + if (alertFunc.valid()) { + auto result = alertFunc(actor, target); + if (!result.valid()) { + sol::error err = result; + LOG(ERROR, "Lua error: {}", err.what(), NULL); + } + } + break; + } + } else if (actor) { + if (idleFunc.valid()) { + auto result = idleFunc(actor, nullptr); + if (!result.valid()) { + sol::error err = result; + LOG(ERROR, "Lua Error: {}", err.what()); + } } } // Collect garbage just to be sure. - std::chrono::high_resolution_clock::time_point curTime = std::chrono::high_resolution_clock::now(); - if (curTime - lastGCTime >= GCTimeout) - { - behaviour->lua.collect_gc(); - lastGCTime = curTime; - } - } - catch (const std::exception& e) { + std::chrono::high_resolution_clock::time_point curTime = + std::chrono::high_resolution_clock::now(); + if (curTime - lastGCTime >= GCTimeout) { + behaviour->lua.collect_gc(); + lastGCTime = curTime; + } + } catch (const std::exception &e) { LOG(ERROR, "Problem occured during AI update: {}", e.what()); - state = AIState::Idle; - } + state = AIState::Idle; + } } -AI::~AI() -{ - // Just set all of the references to null, given they are smart pointers, they are freed when no longer used. - behaviour->lua["raycaster"] = sol::nil; - behaviour->lua["ai"] = sol::nil; - behaviour->lua["idle"] = sol::nil; - behaviour->lua["patrol"] = sol::nil; - behaviour->lua["alert"] = sol::nil; - behaviour->lua.collect_gc(); +AI::~AI() { + // Just set all of the references to null, given they are smart pointers, they + // are freed when no longer used. + behaviour->lua["raycaster"] = sol::nil; + behaviour->lua["ai"] = sol::nil; + behaviour->lua["idle"] = sol::nil; + behaviour->lua["patrol"] = sol::nil; + behaviour->lua["alert"] = sol::nil; + behaviour->lua.collect_gc(); } diff --git a/YuppleMayham/src/gameplay/camera.cpp b/YuppleMayham/src/gameplay/camera.cpp index 9c74bf2..31a7271 100644 --- a/YuppleMayham/src/gameplay/camera.cpp +++ b/YuppleMayham/src/gameplay/camera.cpp @@ -1,28 +1,31 @@ #include "gameplay/camera.h" -// follow our target set using the setTarget. If there is no target set the camera will not move. -void Camera::update(double deltaTime) -{ - if (target == nullptr) - return; - float smoothingFactor = 5.0f; - //if (glm::distance(target->getCenter(), getCenterPos()) > 20.f) - position += (target->getCenter() - getCenterPos()) * smoothingFactor * static_cast(deltaTime); +// follow our target set using the setTarget. If there is no target set the +// camera will not move. +void Camera::update(double deltaTime) { + if (target == nullptr) + return; + float smoothingFactor = 5.0f; + // if (glm::distance(target->getCenter(), getCenterPos()) > 20.f) + position += (target->getCenter() - getCenterPos()) * smoothingFactor * + static_cast(deltaTime); } -glm::mat4 Camera::getViewMatrix() -{ - return glm::lookAt(position, position + front, up); +glm::mat4 Camera::getViewMatrix() { + return glm::lookAt(position, position + front, up); } -glm::mat4 Camera::getProjectionMatrix() -{ - return glm::ortho(0.f, viewPortW, viewPortH, 0.f); +glm::mat4 Camera::getProjectionMatrix() { + return glm::ortho(0.f, viewPortW, viewPortH, 0.f); +} + +void Camera::setViewportSize(float width, float height) { + viewPortW = width; + viewPortH = height; } // The local coordinates are the corrdinates relative to the camera. -const glm::vec3 Camera::worldToLocal(const glm::vec3& worldCoordinates) -{ - //return worldCoordinates - position; - return glm::vec3(getViewMatrix() * glm::vec4(worldCoordinates, 1.0f)); +const glm::vec3 Camera::worldToLocal(const glm::vec3 &worldCoordinates) { + // return worldCoordinates - position; + return glm::vec3(getViewMatrix() * glm::vec4(worldCoordinates, 1.0f)); } diff --git a/YuppleMayham/src/gameplay/game.cpp b/YuppleMayham/src/gameplay/game.cpp index 9a0b19e..f8b4b70 100644 --- a/YuppleMayham/src/gameplay/game.cpp +++ b/YuppleMayham/src/gameplay/game.cpp @@ -11,6 +11,7 @@ #include "sound/engine.h" +#include #include #include #include @@ -85,7 +86,17 @@ bool Game::loadDebugScene() { return true; } -void Game::captureInput(SDL_Event &e) { inputHandler->captureInput(e); } +void Game::captureInput(SDL_Event &e) { + inputHandler->captureInput(e); + if (e.type == SDL_WINDOWEVENT_RESIZED) { + size_t width = static_cast(e.window.data1); + size_t height = static_cast(e.window.data2); + globalEventManager->notify({width, height}); + window->resizeWindow(width, height); + camera->setViewportSize(static_cast(e.window.data1), + static_cast(e.window.data2)); + } +} void Game::executeInputs() { inputHandler->handleInput(); diff --git a/YuppleMayham/src/gameplay/gameactor.cpp b/YuppleMayham/src/gameplay/gameactor.cpp index be45128..a7c0c51 100644 --- a/YuppleMayham/src/gameplay/gameactor.cpp +++ b/YuppleMayham/src/gameplay/gameactor.cpp @@ -3,156 +3,181 @@ #include "gameplay/physics.h" #include "gameplay/scene.h" #include "gameplay/weapons/weapon.h" -#include "utility/events.h" -#include "utility/direction.h" #include "utility/component.h" +#include "utility/direction.h" +#include "utility/events.h" #include -GameActor::~GameActor() { } +// The components are smart pointer references to resources owned by the +// resource manager. So the GameActor is not responsible for cleaning resources. +GameActor::~GameActor() {} -void GameActor::addComponent(std::unique_ptr component) -{ - component->ownerid = entityid; - components.push_back(std::move(component)); +// Adding a component also means attaching the id of the entity to the +// component, so it's aware of who owns it. This is important for event handling +void GameActor::addComponent(std::unique_ptr component) { + component->ownerid = entityid; + components.push_back(std::move(component)); } -Weapon* GameActor::getHeldWeapon() const -{ - return (weapons.empty() || currentWeaponIndex >= weapons.size()) ? nullptr : weapons[currentWeaponIndex].get(); +Weapon *GameActor::getHeldWeapon() const { + return (weapons.empty() || currentWeaponIndex >= weapons.size()) + ? nullptr + : weapons[currentWeaponIndex].get(); } -std::span GameActor::getAllWeapons() -{ - return weaponCache; +std::span GameActor::getAllWeapons() { return weaponCache; } + +// Keep a seperate vector that is used as the cache for external calls to +// getAllWeapons() +void GameActor::pickupWeapon(std::unique_ptr weapon) { + weapon->setWielder(this); + if (auto eventManager = sceneContext->getEventManager().lock()) { + weapon->hookEventManager(eventManager); + } + weaponCache.push_back(weapon.get()); + weapons.push_back(std::move(weapon)); + // wield the newly picked up weapon. + getHeldWeapon()->putaway(); + currentWeaponIndex = weapons.size() - 1; + getHeldWeapon()->wield(); } -void GameActor::pickupWeapon(std::unique_ptr weapon) -{ - weapon->setWielder(this); - if (auto eventManager = sceneContext->getEventManager().lock()) { - weapon->hookEventManager(eventManager); - } - weaponCache.push_back(weapon.get()); - weapons.push_back(std::move(weapon)); - // wield the newly picked up weapon. - getHeldWeapon()->putaway(); - currentWeaponIndex = weapons.size() - 1; - getHeldWeapon()->wield(); +void GameActor::setRotation(const float &rotation) { + // Any attached animation component would be interested if their owner needs + // their sprite swapped + if (!isRotatable) { + if (auto eventManager = sceneContext->getEventManager().lock()) { + Direction newDir = getDirectionFromRotation(rotation); + if (getDirectionFromRotation(this->rotation) != newDir) + eventManager->notify({entityid, newDir}); + } + } + this->rotation = rotation; + updateModelMatrix(); } -void GameActor::setRotation(const float& rotation) -{ - if (!isRotatable) { - if (auto eventManager = sceneContext->getEventManager().lock()) { - Direction newDir = getDirectionFromRotation(rotation); - if (getDirectionFromRotation(this->rotation) != newDir) - eventManager->notify({ entityid, newDir }); - } - } - this->rotation = rotation; - updateModelMatrix(); +void GameActor::update(double deltaTime) { + Entity::update(deltaTime); + + for (const auto &component : components) + component->update(); + for (const auto &weapon : weapons) + weapon->update(deltaTime); + + // Not the cleanest solution, but this is to make sure the animation isn't + // starting to move over and over. + if (isMoving && !wasMoving) { + if (auto event = sceneContext->getEventManager().lock()) { + event->notify({entityid}); + } + wasMoving = true; + } else if (!isMoving && wasMoving) { + if (auto event = sceneContext->getEventManager().lock()) { + event->notify({entityid}); + } + wasMoving = false; + } + isMoving = false; } -void GameActor::update(double deltaTime) -{ - Entity::update(deltaTime); - - for (const auto& component : components) - component->update(); - for (const auto& weapon : weapons) - weapon->update(deltaTime); - - if (isMoving && !wasMoving) - { - if (auto event = sceneContext->getEventManager().lock()) { - event->notify({ entityid }); - } - wasMoving = true; - } - else if (!isMoving && wasMoving) - { - if (auto event = sceneContext->getEventManager().lock()) { - event->notify({ entityid }); - } - wasMoving = false; - } - isMoving = false; +void GameActor::draw() { + Entity::draw(); + for (const auto &component : components) { + component->bind(); + component->render(); + } } -void GameActor::draw() -{ - Entity::draw(); - - // regular loop through components, but if the component returns true to kill, we erase it. - // Components are always assumed to be smart pointers! - for (const auto& component : components) - { - component->bind(); - component->render(); - } - //for (auto& weapon : weapons) - // weapon->draw(); +void GameActor::moveUp() { + if (physics) + physics->rigidBody.applyForce(glm::vec3(0.f, -1.f, 0.f), 1500.25f); + isMoving = true; +} +void GameActor::moveDown() { + if (physics) + physics->rigidBody.applyForce(glm::vec3(0.f, 1.f, 0.f), 1500.25f); + isMoving = true; +} +void GameActor::moveLeft() { + if (physics) + physics->rigidBody.applyForce(glm::vec3(-1.f, 0.f, 0.f), 1500.25f); + isMoving = true; +} +void GameActor::moveRight() { + if (physics) + physics->rigidBody.applyForce(glm::vec3(1.f, 0.f, 0.f), 1500.25f); + isMoving = true; } - -void GameActor::moveUp() { if (physics) physics->rigidBody.applyForce(glm::vec3( 0.f,-1.f, 0.f), 1500.25f); isMoving = true; } -void GameActor::moveDown() { if (physics) physics->rigidBody.applyForce(glm::vec3( 0.f, 1.f, 0.f), 1500.25f); isMoving = true; } -void GameActor::moveLeft() { if (physics) physics->rigidBody.applyForce(glm::vec3(-1.f, 0.f, 0.f), 1500.25f); isMoving = true; } -void GameActor::moveRight(){ if (physics) physics->rigidBody.applyForce(glm::vec3( 1.f, 0.f, 0.f), 1500.25f); isMoving = true; } // top-down shooter mode controls -void GameActor::fireWeapon()const { - if (auto weapon = getHeldWeapon()) { - if (weapon->shoot()) { - if (sceneContext->getPlayerID() == entityid) { - if (auto gEvent = sceneContext->getGlobalEventManager().lock()) { - gEvent->notify({0.01f, 0.8f}); - gEvent->notify({1.f, 0.8f}); - } - } - } - } +void GameActor::fireWeapon() const { + if (auto weapon = getHeldWeapon()) { + if (weapon->shoot()) { + // If it's the player that is shooting apply a shake and blur effect to + // give the shots some weight + if (sceneContext->getPlayerID() == entityid) { + if (auto gEvent = sceneContext->getGlobalEventManager().lock()) { + gEvent->notify({0.01f, 0.8f}); + gEvent->notify({1.f, 0.8f}); + } + } + } + } } -void GameActor::cycleUpWeapons() { - if (!weapons.empty()) { - weapons[currentWeaponIndex]->putaway(); - currentWeaponIndex = (currentWeaponIndex + 1) % weapons.size(); - weapons[currentWeaponIndex]->wield(); - } +void GameActor::cycleUpWeapons() { + if (!weapons.empty()) { + weapons[currentWeaponIndex]->putaway(); + currentWeaponIndex = (currentWeaponIndex + 1) % weapons.size(); + weapons[currentWeaponIndex]->wield(); + } } void GameActor::cycleDownWeapons() { - if (!weapons.empty()) { - weapons[currentWeaponIndex]->putaway(); - currentWeaponIndex = (currentWeaponIndex + weapons.size() - 1) % weapons.size(); - weapons[currentWeaponIndex]->wield(); - } + if (!weapons.empty()) { + weapons[currentWeaponIndex]->putaway(); + currentWeaponIndex = + (currentWeaponIndex + weapons.size() - 1) % weapons.size(); + weapons[currentWeaponIndex]->wield(); + } } -void GameActor::cycleWeapons(const MouseState& mouse_state) -{ - if (mouse_state.scroll < 0) - cycleUpWeapons(); - else if (mouse_state.scroll > 0) - cycleDownWeapons(); +void GameActor::cycleWeapons(const MouseState &mouse_state) { + if (mouse_state.scroll < 0) + cycleUpWeapons(); + else if (mouse_state.scroll > 0) + cycleDownWeapons(); } -void GameActor::followMouse(const MouseState& mouse_state) -{ - glm::vec2 direction = glm::vec2(mouse_state.x, mouse_state.y) - glm::vec2(localPosition.x, localPosition.y); - float newRotation = glm::degrees(glm::atan(direction.y, direction.x)); - if (getDirectionFromRotation(rotation) != getDirectionFromRotation(newRotation)) { - if (auto event = sceneContext->getEventManager().lock()) { - event->notify({ entityid, getDirectionFromRotation(newRotation) }); - } - } - //setRotation(glm::degrees(glm::atan(direction.y, direction.x))); - this->rotation = newRotation; +void GameActor::followMouse(const MouseState &mouse_state) { + glm::vec2 direction = glm::vec2(mouse_state.x, mouse_state.y) - + glm::vec2(localPosition.x, localPosition.y); + float newRotation = glm::degrees(glm::atan(direction.y, direction.x)); + if (getDirectionFromRotation(rotation) != + getDirectionFromRotation(newRotation)) { + if (auto event = sceneContext->getEventManager().lock()) { + event->notify( + {entityid, getDirectionFromRotation(newRotation)}); + } + } + // setRotation(glm::degrees(glm::atan(direction.y, direction.x))); + this->rotation = newRotation; } -void GameActor::strafeLeft() { position.x += sin(glm::radians(rotation)) * speed; position.y -= cos(glm::radians(rotation)) * speed; } -void GameActor::strafeRight() { position.x -= sin(glm::radians(rotation)) * speed; position.y += cos(glm::radians(rotation)) * speed; } -void GameActor::moveBackward() { position.x -= cos(glm::radians(rotation)) * speed; position.y -= sin(glm::radians(rotation)) * speed; } -void GameActor::moveForward() { - if (physics) { - physics->rigidBody.velocity.x += cos(glm::radians(rotation)) * speed; - physics->rigidBody.velocity.y += sin(glm::radians(rotation)) * speed; - } - isMoving = true; +void GameActor::strafeLeft() { + position.x += sin(glm::radians(rotation)) * speed; + position.y -= cos(glm::radians(rotation)) * speed; +} +void GameActor::strafeRight() { + position.x -= sin(glm::radians(rotation)) * speed; + position.y += cos(glm::radians(rotation)) * speed; +} +void GameActor::moveBackward() { + position.x -= cos(glm::radians(rotation)) * speed; + position.y -= sin(glm::radians(rotation)) * speed; +} +void GameActor::moveForward() { // More than likely the most useful of the + // movement commands so far. But this could + // change in the future + if (physics) { + physics->rigidBody.velocity.x += cos(glm::radians(rotation)) * speed; + physics->rigidBody.velocity.y += sin(glm::radians(rotation)) * speed; + } + isMoving = true; } diff --git a/YuppleMayham/src/gameplay/input.cpp b/YuppleMayham/src/gameplay/input.cpp index 5eca327..dea8c09 100644 --- a/YuppleMayham/src/gameplay/input.cpp +++ b/YuppleMayham/src/gameplay/input.cpp @@ -3,56 +3,51 @@ #include -void InputHandler::handleInput() -{ - if (!actor) return; - Uint32 currentTime = SDL_GetTicks(); - // check for bound keys that were pressed, - // next check if the hasn't been executed within the amount specified in delay - // if not execute the command and set lastExecution to currentTime - for (auto& [key, command] : keyCommands) - { - if (keys[key] == true) - { - if (currentTime - command.lastExecution >= command.delay) - { - commandQueue.push_back(command.cmd.get()); - command.lastExecution = currentTime; - } - } - } - // Same with the mouse, for this context we'll be checking for motion events and for click events - for (auto& [button, command] : mouseCommands) - { - if (mouseButtons[button] == true) - { - if (currentTime - command.lastExecution >= command.delay) - { - mouseQueue.push_back(command.cmd.get()); - command.lastExecution = currentTime; - } - } - } - if (mouseMotionCommand) - mouseMotionCommand->execute(*actor, mouse_state); - if (mouseScrollCommand) - mouseScrollCommand->execute(*actor, mouse_state); - mouse_state.scroll = 0.0f; // clear mouse scroll since we have handled the event. +void InputHandler::handleInput() { + // If our input handler is not attached to an actor we return. + // This will be due for change given we will need to handle input during menus + if (!actor) + return; + Uint32 currentTime = SDL_GetTicks(); + // check for bound keys that were pressed, + // next check if the hasn't been executed within the amount specified in delay + // if not execute the command and set lastExecution to currentTime + for (auto &[key, command] : keyCommands) { + if (keys[key] == true) { + if (currentTime - command.lastExecution >= command.delay) { + commandQueue.push_back(command.cmd.get()); + command.lastExecution = currentTime; + } + } + } + // Same with the mouse, for this context we'll be checking for motion events + // and for click events + for (auto &[button, command] : mouseCommands) { + if (mouseButtons[button] == true) { + if (currentTime - command.lastExecution >= command.delay) { + mouseQueue.push_back(command.cmd.get()); + command.lastExecution = currentTime; + } + } + } + if (mouseMotionCommand) + mouseMotionCommand->execute(*actor, mouse_state); + if (mouseScrollCommand) + mouseScrollCommand->execute(*actor, mouse_state); + mouse_state.scroll = + 0.0f; // clear mouse scroll since we have handled the event. } // Executes every captured command during the frame -void InputHandler::executeCommands() -{ - for (auto& command : commandQueue) { - command->execute(*actor); - } - for (auto& mouse : mouseQueue) { - mouse->execute(*actor, mouse_state); - } - commandQueue.clear(); - mouseQueue.clear(); +void InputHandler::executeCommands() { + for (auto &command : commandQueue) { + command->execute(*actor); + } + for (auto &mouse : mouseQueue) { + mouse->execute(*actor, mouse_state); + } + commandQueue.clear(); + mouseQueue.clear(); } -InputHandler::~InputHandler() -{ -} +InputHandler::~InputHandler() {} diff --git a/YuppleMayham/src/gameplay/map.cpp b/YuppleMayham/src/gameplay/map.cpp index 10c5844..513ba60 100644 --- a/YuppleMayham/src/gameplay/map.cpp +++ b/YuppleMayham/src/gameplay/map.cpp @@ -1,125 +1,129 @@ #include "gameplay/map.h" -#include "gameplay/camera.h" -#include "graphics/shader.h" #include "graphics/texture.h" -#include "utility/xmlloader.h" -#include "utility/resourcemanager.h" #include "utility/logger.h" +#include "utility/resourcemanager.h" +#include "utility/xmlloader.h" #include -Map::Map(const MapData* mapData, const unsigned shaderID, std::shared_ptr resourceManager) : - mapData(mapData), - tileIds(mapData->tiles) -{ - this->shaderID = shaderID; +Map::Map(const MapData *mapData, const unsigned shaderID, + std::shared_ptr resourceManager) + : mapData(mapData), tileIds(mapData->tiles) { + this->shaderID = shaderID; - for (auto& tileSet : mapData->tileSets) - tileSetData.push_back(resourceManager->loadTileSet(tileSet.path)); + // Tiles are held on layers, drawn back to front + for (auto &tileSet : mapData->tileSets) + tileSetData.push_back(resourceManager->loadTileSet(tileSet.path)); - if (!tileSetData.empty()) - { - std::vector buffer; - for (int layer = 0; layer < tileIds.size(); layer++) - { - buffer.clear(); - for (auto& set : tileSetData) - buffer.push_back(set->file.c_str()); - if (!buffer.empty()) - instanceHandles.push_back(std::make_shared(buffer)); - } + if (!tileSetData.empty()) { + // Storing all of the tilesets we will need to load and sending it to our + // texture instance handle + std::vector buffer; + for (int layer = 0; layer < tileIds.size(); layer++) { + buffer.clear(); + for (auto &set : tileSetData) + buffer.push_back(set->file.c_str()); + if (!buffer.empty()) + instanceHandles.push_back( + std::make_shared(buffer)); + } - loadMap(); - createCollisionMap(); - } - -} -#include -void Map::loadMap() -{ - tileData.resize(tileIds.size()); - for (int layer = 0; layer < tileIds.size(); layer++) - { - for (int y = 0; y < tileIds[layer].size(); y++) - { - for (int x = 0; x < tileIds[layer][y].size(); x++) - { - glm::mat4 modelMatrix = - glm::translate(glm::mat4(1.f), glm::vec3(x * mapData->tileSize, y * mapData->tileSize, 0.0f)) * - glm::scale(glm::mat4(1.f), glm::vec3(mapData->tileSize, mapData->tileSize, 1.0f)); - - int textureIndex = static_cast(getTileSetIndex(tileIds[layer][y][x])); - glm::vec2 originalSize = (textureIndex != -1) ? - glm::vec2(tileSetData[textureIndex]->width, tileSetData[textureIndex]->height) : - glm::vec2(0.0f); - int tilesPerRow = (textureIndex != -1) ? tileSetData[textureIndex]->columns : 0; - int startID = (textureIndex != -1) ? mapData->tileSets[textureIndex].startID : 0; - int tileIndex = tileIds[layer][y][x]; - - tileData[layer].push_back({modelMatrix, originalSize, tileIndex, textureIndex, tilesPerRow, startID}); - } - } - instanceHandles[layer]->updateInstanceData(tileData[layer]); - } - glm::vec2 canvasSize = glm::vec2(instanceHandles[0]->getTextureArray()->getWidth(), instanceHandles[0]->getTextureArray()->getHeight()); - editUniformOnce("uCanvasSize", canvasSize); + loadMap(); + createCollisionMap(); + } } -void Map::createCollisionMap() -{ - // Match collisionMap to map size - collisionMap.resize(tileIds[0].size()); - for (int y = 0; y < tileIds[0].size(); ++y) - { - collisionMap[y].resize(tileIds[0][y].size(), 0); - } +void Map::loadMap() { + tileData.resize(tileIds.size()); + // Tiles are drawn back to front, we track the tileset the tile comes from and + // additional information about the tilesets themselves so the shader can + // properly draw the right tile. Each layer is its own instance + for (int layer = 0; layer < tileIds.size(); layer++) { + for (int y = 0; y < tileIds[layer].size(); y++) { + for (int x = 0; x < tileIds[layer][y].size(); x++) { + glm::mat4 modelMatrix = + glm::translate( + glm::mat4(1.f), + glm::vec3(x * mapData->tileSize, y * mapData->tileSize, 0.0f)) * + glm::scale(glm::mat4(1.f), + glm::vec3(mapData->tileSize, mapData->tileSize, 1.0f)); - for (int layer = 0; layer < tileIds.size(); layer++) - { - for (int y = 0; y < tileIds[layer].size(); y++) - { - for (int x = 0; x < tileIds[layer][y].size(); x++) - { - int id = tileIds[layer][y][x]; - size_t tileSetIndex = getTileSetIndex(id); - if (tileSetIndex == -1) - collisionMap[y][x] = 0; - else - { - int startID = mapData->tileSets[tileSetIndex].startID; - auto& tile = tileSetData[tileSetIndex]->tiles[id - startID]; - if (!tile->walkable) - collisionMap[y][x] = 1; - } - } - } - } + int textureIndex = + static_cast(getTileSetIndex(tileIds[layer][y][x])); + glm::vec2 originalSize = + (textureIndex != -1) ? glm::vec2(tileSetData[textureIndex]->width, + tileSetData[textureIndex]->height) + : glm::vec2(0.0f); + int tilesPerRow = + (textureIndex != -1) ? tileSetData[textureIndex]->columns : 0; + int startID = + (textureIndex != -1) ? mapData->tileSets[textureIndex].startID : 0; + int tileIndex = tileIds[layer][y][x]; + + tileData[layer].push_back({modelMatrix, originalSize, tileIndex, + textureIndex, tilesPerRow, startID}); + } + } + instanceHandles[layer]->updateInstanceData(tileData[layer]); + } + // The canvas size is the same for every tile atlas, each one growing to match + // the size of the larget tileset + glm::vec2 canvasSize = + glm::vec2(instanceHandles[0]->getTextureArray()->getWidth(), + instanceHandles[0]->getTextureArray()->getHeight()); + editUniformOnce("uCanvasSize", canvasSize); } -void Map::draw() -{ - for (int layer = 0; layer < instanceHandles.size(); layer++) - { - instanceHandles[layer]->draw(); - } +// The collision map is just a 2D array of 0's and 1's, 1's being collidable and +// 0's not. This may see some changes in the future to properly address special +// tiles, such as portals. +void Map::createCollisionMap() { + // Match collisionMap to map size + collisionMap.resize(tileIds[0].size()); + for (int y = 0; y < tileIds[0].size(); ++y) { + collisionMap[y].resize(tileIds[0][y].size(), 0); + } + + for (int layer = 0; layer < tileIds.size(); layer++) { + for (int y = 0; y < tileIds[layer].size(); y++) { + for (int x = 0; x < tileIds[layer][y].size(); x++) { + int id = tileIds[layer][y][x]; + size_t tileSetIndex = getTileSetIndex(id); + if (tileSetIndex == -1) + collisionMap[y][x] = 0; + else { + int startID = mapData->tileSets[tileSetIndex].startID; + auto &tile = tileSetData[tileSetIndex]->tiles[id - startID]; + if (!tile->walkable) + collisionMap[y][x] = 1; + } + } + } + } } -/* -Use this function to get the tileSetIndex from a tile ID. -the index of the tileSet is the same index as the texture index used in the instanceHandle +// Draw each layer in it's own instance +void Map::draw() { + for (int layer = 0; layer < instanceHandles.size(); layer++) { + instanceHandles[layer]->draw(); + } +} -returns tileSetIndex of the tile id passed. Unless the id is either 0 or +/* +Use this function to get the tileSetIndex from a tile ID. +the index of the tileSet is the same index as the texture index used in the +instanceHandle + +returns tileSetIndex of the tile id passed. Unless the id is either 0 or the returned tileSetIndex is out of bounds, returns -1 */ -size_t Map::getTileSetIndex(int id) const -{ - // work from the bottom, break if ID > startID - // If we get a textureIndex of -1 then we are on an empty tile - size_t tileSetIndex = mapData->tileSets.size() - 1; - for (; tileSetIndex != -1; --tileSetIndex) - { - if (id >= mapData->tileSets[tileSetIndex].startID) - break; - } - return (tileSetIndex >= mapData->tileSets.size()) ? -1 : tileSetIndex; +size_t Map::getTileSetIndex(int id) const { + // work from the bottom, break if ID > startID + // If we get a textureIndex of -1 then we are on an empty tile + size_t tileSetIndex = mapData->tileSets.size() - 1; + for (; tileSetIndex != -1; --tileSetIndex) { + if (id >= mapData->tileSets[tileSetIndex].startID) + break; + } + return (tileSetIndex >= mapData->tileSets.size()) ? -1 : tileSetIndex; } diff --git a/YuppleMayham/src/gameplay/physics.cpp b/YuppleMayham/src/gameplay/physics.cpp index 41bd5ca..272469b 100644 --- a/YuppleMayham/src/gameplay/physics.cpp +++ b/YuppleMayham/src/gameplay/physics.cpp @@ -2,212 +2,215 @@ #include "gameplay/weapons/bullet.h" #include "utility/events.h" -#include "utility/logger.h" - -void PhysicsEngine::hookEventManager(const std::shared_ptr& eventManager) -{ - this->eventManager = eventManager; - this->eventManager->subscribe([this](const BulletFiredEvent& event) { - if (auto bullet = event.bullet.lock()) { - this->addObject(bullet->getPhysicsComponent()); - } - }); - this->eventManager->subscribe([this](const BulletDiedEvent& event) { - this->removeObject(event.physObj); - }); +void PhysicsEngine::hookEventManager( + const std::shared_ptr &eventManager) { + this->eventManager = eventManager; + this->eventManager->subscribe( + [this](const BulletFiredEvent &event) { + if (auto bullet = event.bullet.lock()) { + this->addObject(bullet->getPhysicsComponent()); + } + }); + this->eventManager->subscribe( + [this](const BulletDiedEvent &event) { + this->removeObject(event.physObj); + }); } -std::shared_ptr PhysicsEngine::createObject(const unsigned int ID, - const glm::vec3& pos, - float mass, - PhysicsComponent::Collider::Shape shape, - glm::vec3 dimensions, const - glm::vec3 offset) -{ - auto component = std::make_shared (); - component->ID = ID; - component->rigidBody.position = pos; - component->rigidBody.acceleration = glm::vec2(0.f); - component->rigidBody.mass = mass; - component->collider.shape = shape; - component->collider.dimensions = dimensions; - component->collider.offset = offset; +std::shared_ptr +PhysicsEngine::createObject(const unsigned int ID, const glm::vec3 &pos, + float mass, PhysicsComponent::Collider::Shape shape, + glm::vec3 dimensions, const glm::vec3 offset) { + auto component = std::make_shared(); + component->ID = ID; + component->rigidBody.position = pos; + component->rigidBody.acceleration = glm::vec2(0.f); + component->rigidBody.mass = mass; + component->collider.shape = shape; + component->collider.dimensions = dimensions; + component->collider.offset = offset; - addObject(component); - return component; + addObject(component); + return component; } -void PhysicsEngine::loadCollisionMap(const std::vector>& collisionMap, float tileSize) -{ - this->collisionMap = collisionMap; - this->tileSize = tileSize; +void PhysicsEngine::loadCollisionMap( + const std::vector> &collisionMap, float tileSize) { + this->collisionMap = collisionMap; + this->tileSize = tileSize; } -void PhysicsEngine::addObject(const std::shared_ptr& component) -{ - if (component) - objects.emplace_back(component); +void PhysicsEngine::addObject( + const std::shared_ptr &component) { + if (component) + objects.emplace_back(component); } -void PhysicsEngine::removeObject(const std::shared_ptr& component) -{ - if (std::find(objects.begin(), objects.end(), component) != objects.end()) - objects.erase(std::remove(objects.begin(), objects.end(), component)); +void PhysicsEngine::removeObject( + const std::shared_ptr &component) { + if (std::find(objects.begin(), objects.end(), component) != objects.end()) + objects.erase(std::remove(objects.begin(), objects.end(), component)); } -int PhysicsEngine::getTileCollider(const glm::vec2& position) -{ - int x = static_cast((position.x + 0.5f * tileSize) / tileSize); - int y = static_cast((position.y + 0.5f * tileSize) / tileSize); - if (y >= 0 && y < collisionMap.size()) - { - if (x >= 0 && x < collisionMap[y].size()) - return collisionMap[y][x]; - } - return 0; +int PhysicsEngine::getTileCollider(const glm::vec2 &position) { + int x = static_cast((position.x + 0.5f * tileSize) / tileSize); + int y = static_cast((position.y + 0.5f * tileSize) / tileSize); + if (y >= 0 && y < collisionMap.size()) { + if (x >= 0 && x < collisionMap[y].size()) + return collisionMap[y][x]; + } + return 0; } -void PhysicsEngine::getPossibleCollisions() -{ - objCollisions.clear(); - for (size_t i = 0; i < objects.size(); ++i) - { - auto& obj = objects[i]; - for (size_t j = i + 1; j < objects.size(); ++j) - { - auto& colliderObj = objects[j]; - if (obj.get() == colliderObj.get() || obj->ID == colliderObj->ID) continue; - float colliderRight = colliderObj->rigidBody.position.x + colliderObj->collider.dimensions.x; - float colliderBottom = colliderObj->rigidBody.position.y + colliderObj->collider.dimensions.y; - float objectRight = obj->rigidBody.position.x + obj->collider.dimensions.x; - float objectBottom = obj->rigidBody.position.y + obj->collider.dimensions.y; - if ((obj->rigidBody.position.x <= colliderRight && - objectRight >= colliderObj->rigidBody.position.x) || - (obj->rigidBody.position.y <= colliderBottom && - objectBottom >= colliderObj->rigidBody.position.y)) - objCollisions.push_back(CollisionPair(obj.get(), colliderObj.get())); - } - } +void PhysicsEngine::getPossibleCollisions() { + objCollisions.clear(); + for (size_t i = 0; i < objects.size(); ++i) { + auto &obj = objects[i]; + for (size_t j = i + 1; j < objects.size(); ++j) { + auto &colliderObj = objects[j]; + if (obj.get() == colliderObj.get() || obj->ID == colliderObj->ID) + continue; + float colliderRight = colliderObj->rigidBody.position.x + + colliderObj->collider.dimensions.x; + float colliderBottom = colliderObj->rigidBody.position.y + + colliderObj->collider.dimensions.y; + float objectRight = + obj->rigidBody.position.x + obj->collider.dimensions.x; + float objectBottom = + obj->rigidBody.position.y + obj->collider.dimensions.y; + if ((obj->rigidBody.position.x <= colliderRight && + objectRight >= colliderObj->rigidBody.position.x) || + (obj->rigidBody.position.y <= colliderBottom && + objectBottom >= colliderObj->rigidBody.position.y)) + objCollisions.push_back(CollisionPair(obj.get(), colliderObj.get())); + } + } } -void PhysicsEngine::resolvePossibleCollisions() -{ - for (auto& objs : objCollisions) - { - // Solve for two circles, we'll need to expand upon this for different colliders... - float sumOfRadius = objs.first->collider.dimensions.x + objs.second->collider.dimensions.x; - glm::vec2 objFirstCenter = objs.first->rigidBody.position + objs.first->collider.offset; - glm::vec2 objSecondCenter = objs.second->rigidBody.position + objs.second->collider.offset; - glm::vec2 distance = objFirstCenter - objSecondCenter; - if (glm::length(distance) < sumOfRadius) - { - // We got impact! - glm::vec2 normal = distance / glm::length(distance); - // That impact is a bullet hitting a gameactor! - if ((objs.first->isBullet || objs.second->isBullet) && !(objs.first->isBullet && objs.second->isBullet)) - { - eventManager->notify(std::make_shared( - ( objs.first->isBullet) ? objs.first->ID : objs.second->ID, - (!objs.first->isBullet) ? objs.first->ID : objs.second->ID, - std::make_shared(( objs.first->isBullet) ? objs.first : objs.second), - normal - )); - } - // Apply impulse force - float penetrationDepth = sumOfRadius - glm::length(distance); - glm::vec2 correctionVector = normal * (penetrationDepth / ((1 / objs.first->rigidBody.mass) + (1 / objs.second->rigidBody.mass))); - glm::vec2 vrel = objs.first->rigidBody.velocity - objs.second->rigidBody.velocity; +void PhysicsEngine::resolvePossibleCollisions() { + for (auto &objs : objCollisions) { + // Solve for two circles, we'll need to expand upon this for different + // colliders... + float sumOfRadius = + objs.first->collider.dimensions.x + objs.second->collider.dimensions.x; + glm::vec2 objFirstCenter = + objs.first->rigidBody.position + objs.first->collider.offset; + glm::vec2 objSecondCenter = + objs.second->rigidBody.position + objs.second->collider.offset; + glm::vec2 distance = objFirstCenter - objSecondCenter; + if (glm::length(distance) < sumOfRadius) { + // We got impact! + glm::vec2 normal = distance / glm::length(distance); + // That impact is a bullet hitting a gameactor! + if ((objs.first->isBullet || objs.second->isBullet) && + !(objs.first->isBullet && objs.second->isBullet)) { + eventManager->notify(std::make_shared( + (objs.first->isBullet) ? objs.first->ID : objs.second->ID, + (!objs.first->isBullet) ? objs.first->ID : objs.second->ID, + std::make_shared( + (objs.first->isBullet) ? objs.first : objs.second), + normal)); + } + // Apply impulse force + float penetrationDepth = sumOfRadius - glm::length(distance); + glm::vec2 correctionVector = + normal * (penetrationDepth / ((1 / objs.first->rigidBody.mass) + + (1 / objs.second->rigidBody.mass))); + glm::vec2 vrel = + objs.first->rigidBody.velocity - objs.second->rigidBody.velocity; - // smallest elasticity of the two colliders - float e = std::min(objs.first->rigidBody.elasticity, objs.second->rigidBody.elasticity); - float impulseMag = (-(1 + e) * glm::dot(vrel, normal)) / ((1 / objs.first->rigidBody.mass) + (1 / objs.second->rigidBody.mass)); + // smallest elasticity of the two colliders + float e = std::min(objs.first->rigidBody.elasticity, + objs.second->rigidBody.elasticity); + float impulseMag = (-(1 + e) * glm::dot(vrel, normal)) / + ((1 / objs.first->rigidBody.mass) + + (1 / objs.second->rigidBody.mass)); - objs.first->rigidBody.position += (correctionVector / objs.first->rigidBody.mass); - objs.second->rigidBody.position -= (correctionVector / objs.second->rigidBody.mass); - objs.first->rigidBody.velocity += impulseMag * normal / objs.first->rigidBody.mass; - objs.second->rigidBody.velocity -= impulseMag * normal / objs.second->rigidBody.mass; - } - } + objs.first->rigidBody.position += + (correctionVector / objs.first->rigidBody.mass); + objs.second->rigidBody.position -= + (correctionVector / objs.second->rigidBody.mass); + objs.first->rigidBody.velocity += + impulseMag * normal / objs.first->rigidBody.mass; + objs.second->rigidBody.velocity -= + impulseMag * normal / objs.second->rigidBody.mass; + } + } } -void PhysicsEngine::resolveWorldCollision(const std::shared_ptr& obj) -{ - switch (obj->collider.shape) - { - case PhysicsComponent::Collider::Shape::Circle: - float radius = obj->collider.dimensions.x; - glm::vec2 position = obj->rigidBody.position + obj->collider.offset; - int topTile = getTileCollider(position - glm::vec2(0, radius)); - int bottomTile = getTileCollider(position + glm::vec2(0, radius)); - int leftTile = getTileCollider(position - glm::vec2(radius, 0)); - int rightTile = getTileCollider(position + glm::vec2(radius, 0)); - if (obj->isBullet) - { - if (topTile || bottomTile || leftTile || rightTile) - { - eventManager->notify(std::make_shared(obj)); - return; - } - } - int tileY = static_cast((position.y) / tileSize); - int tileX = static_cast((position.x) / tileSize); - if (topTile) - { - //obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y; - obj->rigidBody.position.y = (tileY+1) * tileSize + obj->collider.offset.y; - } - if (bottomTile) - { - //obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y; - obj->rigidBody.position.y = (tileY) * tileSize - obj->collider.offset.y; - } - if (leftTile) - { - //obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x; - obj->rigidBody.position.x = (tileX + 1) * tileSize + obj->collider.offset.x; - } - if (rightTile) - { - //obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x; - obj->rigidBody.position.x = (tileX) * tileSize - obj->collider.offset.x; - } - } +void PhysicsEngine::resolveWorldCollision( + const std::shared_ptr &obj) { + switch (obj->collider.shape) { + case PhysicsComponent::Collider::Shape::Circle: + float radius = obj->collider.dimensions.x; + glm::vec2 position = obj->rigidBody.position + obj->collider.offset; + int topTile = getTileCollider(position - glm::vec2(0, radius)); + int bottomTile = getTileCollider(position + glm::vec2(0, radius)); + int leftTile = getTileCollider(position - glm::vec2(radius, 0)); + int rightTile = getTileCollider(position + glm::vec2(radius, 0)); + if (obj->isBullet) { + if (topTile || bottomTile || leftTile || rightTile) { + eventManager->notify(std::make_shared(obj)); + return; + } + } + int tileY = static_cast((position.y) / tileSize); + int tileX = static_cast((position.x) / tileSize); + if (topTile) { + // obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y; + obj->rigidBody.position.y = + (tileY + 1) * tileSize + obj->collider.offset.y; + } + if (bottomTile) { + // obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y; + obj->rigidBody.position.y = (tileY)*tileSize - obj->collider.offset.y; + } + if (leftTile) { + // obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x; + obj->rigidBody.position.x = + (tileX + 1) * tileSize + obj->collider.offset.x; + } + if (rightTile) { + // obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x; + obj->rigidBody.position.x = (tileX)*tileSize - obj->collider.offset.x; + } + } } -void PhysicsEngine::update(double deltaTime) -{ - for (auto& obj : objects) - { - if (!obj) continue; - glm::vec2 frictionForce = obj->rigidBody.velocity * -0.1f; - if (std::abs(obj->rigidBody.acceleration.x) == std::abs(obj->rigidBody.acceleration.y)) - { - obj->rigidBody.acceleration.x *= 0.75f; - obj->rigidBody.acceleration.y *= 0.75f; - } - if (!obj->isBullet) - obj->rigidBody.velocity += (frictionForce); - obj->rigidBody.velocity += obj->rigidBody.acceleration; +void PhysicsEngine::update(double deltaTime) { + for (auto &obj : objects) { + if (!obj) + continue; + glm::vec2 frictionForce = obj->rigidBody.velocity * -0.1f; + if (std::abs(obj->rigidBody.acceleration.x) == + std::abs(obj->rigidBody.acceleration.y)) { + obj->rigidBody.acceleration.x *= 0.75f; + obj->rigidBody.acceleration.y *= 0.75f; + } + if (!obj->isBullet) + obj->rigidBody.velocity += (frictionForce); + obj->rigidBody.velocity += obj->rigidBody.acceleration; - float maxSpeed = 500.f; - float curSpeed = glm::length(obj->rigidBody.velocity); - if (curSpeed > maxSpeed) - { - // Move at maxspeed - obj->rigidBody.velocity = glm::normalize(obj->rigidBody.velocity) * maxSpeed; - } - obj->rigidBody.acceleration = glm::vec2(0.f); - if (obj->collider.dimensions != glm::vec2(0.f)) - { - // check map collisions - resolveWorldCollision(obj); - } - obj->rigidBody.position += obj->rigidBody.velocity * static_cast(deltaTime); - // Make sure we keep our Z at 0.f, a better choice would be to remove the need for vec3 all together! - // TODO: REMOVE VEC3 NO NEED FOR Z COODINATE! - // obj->rigidBody.position.z = 0.f; - } - getPossibleCollisions(); - if (!objCollisions.empty()) - resolvePossibleCollisions(); + float maxSpeed = 500.f; + float curSpeed = glm::length(obj->rigidBody.velocity); + if (curSpeed > maxSpeed) { + // Move at maxspeed + obj->rigidBody.velocity = + glm::normalize(obj->rigidBody.velocity) * maxSpeed; + } + obj->rigidBody.acceleration = glm::vec2(0.f); + if (obj->collider.dimensions != glm::vec2(0.f)) { + // check map collisions + resolveWorldCollision(obj); + } + obj->rigidBody.position += + obj->rigidBody.velocity * static_cast(deltaTime); + // Make sure we keep our Z at 0.f, a better choice would be to remove the + // need for vec3 all together! + // TODO: REMOVE VEC3 NO NEED FOR Z COODINATE! + // obj->rigidBody.position.z = 0.f; + } + getPossibleCollisions(); + if (!objCollisions.empty()) + resolvePossibleCollisions(); } diff --git a/YuppleMayham/src/gameplay/scene.cpp b/YuppleMayham/src/gameplay/scene.cpp index 2081edc..1b6484f 100644 --- a/YuppleMayham/src/gameplay/scene.cpp +++ b/YuppleMayham/src/gameplay/scene.cpp @@ -21,18 +21,6 @@ #include -#include - -// Scene xml files, should contain a node called that holds the sprite -// location -/* -like this: - - - - -*/ - Scene::Scene(SceneType sceneType, std::shared_ptr resources, std::weak_ptr globalEvents) : type(sceneType), resourceManager(resources), @@ -43,7 +31,6 @@ Scene::Scene(SceneType sceneType, std::shared_ptr resources, void Scene::init() { physicsEngine->hookEventManager(eventManager); - // if (sceneType == SCENE_SHOOTER) loadDebugShooterScene(); } @@ -128,8 +115,6 @@ void Scene::loadDebugShooterScene() { } physicsEngine->loadCollisionMap(map->getCollisionMap(), mapData->tileSize); - - // Setup map and other entities... } std::shared_ptr Scene::getPlayer() const { @@ -152,9 +137,7 @@ void Scene::render(std::shared_ptr renderer) { renderer->addDrawable(RenderLayer::Background, static_cast(background)); } - // map->draw(); for (auto &[id, e] : entities) { - // e->draw(); renderer->addDrawable(RenderLayer::GameObjects, e.get()); if (e->getHeldWeapon()) { renderer->addDrawable(RenderLayer::GameObjects, e->getHeldWeapon()); @@ -168,37 +151,6 @@ void Scene::render(std::shared_ptr renderer) { } renderer->render(); - /* - for (const auto& bullet : - player->getHeldWeapon()->getBulletManager()->getBullets()) { - DebugDrawer::getInstance().addLine(player->getCenter(), - bullet->getCenter(), glm::vec4(1.f, 0.f, 0.f, 0.f)); DEBUG_TEXT( - glm::vec3(camera.get()->worldToLocal(bullet->getCenter()).x, - camera.get()->worldToLocal(bullet->getCenter()).y, - 0.f), glm::vec4(1.f, 0.f, 0.f, 1.f), 0.2f, - "( {}, {}, {} )", - bullet->getCenter().x, - bullet->getCenter().y, - bullet->getCenter().z - ); - DEBUG_TEXT( - glm::vec3(camera.get()->worldToLocal(bullet->getCenter()).x, - camera.get()->worldToLocal(bullet->getCenter()).y - + 10.f, 0.f), glm::vec4(1.f, 1.f, 0.f, 1.f), 0.2f, - "( {}, {} )", - bullet->getPhysicsComponent()->rigidBody.position.x, - bullet->getPhysicsComponent()->rigidBody.position.y - ); - DEBUG_TEXT( - glm::vec3(camera.get()->worldToLocal(bullet->getCenter()).x, - camera.get()->worldToLocal(bullet->getCenter()).y - + 20.f, 0.f), glm::vec4(0.f, 1.f, 1.f, 1.f), 0.2f, - "( {}, {} )", - bullet->getPhysicsComponent()->rigidBody.velocity.x, - bullet->getPhysicsComponent()->rigidBody.velocity.y); - } - */ - DEBUG_TEXT(glm::vec3(10.f, 10.f, 0.f), glm::vec4(0.f, 0.f, 0.f, 1.f), 0.5f, "{} / {}", getPlayer()->getHeldWeapon()->getMagazine(), getPlayer()->getHeldWeapon()->getAmmo()); diff --git a/YuppleMayham/src/gameplay/weapons/weapon.cpp b/YuppleMayham/src/gameplay/weapons/weapon.cpp index 8926315..d1536f7 100644 --- a/YuppleMayham/src/gameplay/weapons/weapon.cpp +++ b/YuppleMayham/src/gameplay/weapons/weapon.cpp @@ -1,291 +1,249 @@ #include "gameplay/weapons/weapon.h" -#include "gameplay/weapons/bulletmanager.h" -#include "gameplay/weapons/bullet.h" #include "gameplay/gameactor.h" #include "gameplay/physics.h" +#include "gameplay/weapons/bullet.h" +#include "gameplay/weapons/bulletmanager.h" #include -#include "utility/debugdraw.h" #include "utility/component.h" +#include "utility/debugdraw.h" #include "utility/events.h" +#include "utility/logger.h" #include "utility/resourcemanager.h" #include "utility/script.h" -#include "utility/logger.h" // TODO: Regular clean up, make this mess readable! -Weapon::Weapon(const WeaponData* data, const unsigned weaponShaderID, const unsigned bulletShaderID, ResourceManager* resourceManager) - : - Entity (weaponShaderID), - weaponType (data->id), - weaponSize (glm::vec2(data->sizeX, data->sizeY)), - weaponOffset (glm::vec2(data->offsetX, data->offsetY)), - weaponMag (data->clipSize), - weaponMagSize (data->clipSize), - weaponAmmo (data->maxAmmo), - bulletSpeed (data->bulletSpeed), - bulletDrop (data->bulletDrop), - fireSpeed (data->fireSpeed), - bulletSize (glm::vec2(data->bulletSizeX, data->bulletSizeY)), - bulletShaderID (bulletShaderID), - bulletManager (std::make_shared()), - bulletSpread (std::make_unique(-data->bulletSpread, data->bulletSpread)), - bulletModifer (std::make_unique(data->modMin, data->modMax)) -{ - if (data->bulletAnimated) - bulletSprite = std::make_unique(resourceManager->loadAnimationSet(data->bulletGraphic, entityid)); - else - bulletSprite = std::make_unique(resourceManager->loadSpriteStatic(data->bulletGraphic)); +Weapon::Weapon(const WeaponData *data, const unsigned weaponShaderID, + const unsigned bulletShaderID, ResourceManager *resourceManager) + : Entity(weaponShaderID), weaponType(data->id), + weaponSize(glm::vec2(data->sizeX, data->sizeY)), + weaponOffset(glm::vec2(data->offsetX, data->offsetY)), + weaponMag(data->clipSize), weaponMagSize(data->clipSize), + weaponAmmo(data->maxAmmo), bulletSpeed(data->bulletSpeed), + bulletDrop(data->bulletDrop), fireSpeed(data->fireSpeed), + bulletSize(glm::vec2(data->bulletSizeX, data->bulletSizeY)), + bulletShaderID(bulletShaderID), + bulletManager(std::make_shared()), + bulletSpread(std::make_unique(-data->bulletSpread, + data->bulletSpread)), + bulletModifer( + std::make_unique(data->modMin, data->modMax)) { + if (data->bulletAnimated) + bulletSprite = std::make_unique( + resourceManager->loadAnimationSet(data->bulletGraphic, entityid)); + else + bulletSprite = std::make_unique( + resourceManager->loadSpriteStatic(data->bulletGraphic)); - if (data->animated) - { - addComponent(std::make_unique(resourceManager->loadAnimationSet(data->id, entityid))); - } - else - addComponent(std::make_unique(resourceManager->loadSpriteStatic(data->graphic))); - this->setScale(glm::vec3(weaponSize.x, weaponSize.y, 1.0f)); + if (data->animated) { + addComponent(std::make_unique( + resourceManager->loadAnimationSet(data->id, entityid))); + } else + addComponent(std::make_unique( + resourceManager->loadSpriteStatic(data->graphic))); + this->setScale(glm::vec3(weaponSize.x, weaponSize.y, 1.0f)); }; void Weapon::addComponent(std::unique_ptr comp) { - components.push_back(std::move(comp)); + components.push_back(std::move(comp)); } -void Weapon::reload() -{ - if (auto event = eventManager.lock()) - { - event->notify({ entityid, wielder->getPosition(), weaponType }); - reloading = true; - if (weaponAmmo < weaponMagSize) { - weaponMag = weaponAmmo; - weaponAmmo = 0; - } - else { - weaponMag = weaponMagSize; - weaponAmmo -= weaponMagSize; - } - } +void Weapon::reload() { + if (auto event = eventManager.lock()) { + event->notify( + {entityid, wielder->getPosition(), weaponType}); + reloading = true; + if (weaponAmmo < weaponMagSize) { + weaponMag = weaponAmmo; + weaponAmmo = 0; + } else { + weaponMag = weaponMagSize; + weaponAmmo -= weaponMagSize; + } + } } -bool Weapon::shoot() -{ - bool shotsFired = false; - if (wielder) - { - Uint32 currentTime = SDL_GetTicks(); - if (currentTime - lastFireTime >= fireSpeed && !reloading) - { - if (weaponMag > 0) - { - shotsFired = true; - if (auto event = eventManager.lock()) - event->notify({entityid, fireSpeed, wielder->getPosition(), weaponType}); - if (!weaponScript || !weaponScript->lua["onShoot"].valid()) - { - // create bullet using this generated data - BulletData b = genBulletData(); - createBullet(b); - weaponMag -= 1; - } - else { - auto result = weaponScript->lua["onShoot"](); - if (!result.valid()) - { - sol::error err = result; - std::cerr << "lua error: " << err.what() << std::endl; - } - // auto reload - if ((weaponMag -= 1) <= 0) reload(); - } - } - else if (weaponMag <= 0) reload(); - lastFireTime = currentTime; - } - } - return shotsFired; +bool Weapon::shoot() { + bool shotsFired = false; + if (wielder) { + Uint32 currentTime = SDL_GetTicks(); + if (currentTime - lastFireTime >= fireSpeed && !reloading) { + if (weaponMag > 0) { + shotsFired = true; + if (auto event = eventManager.lock()) + event->notify( + {entityid, fireSpeed, wielder->getPosition(), weaponType}); + if (!weaponScript || !weaponScript->lua["onShoot"].valid()) { + // create bullet using this generated data + BulletData b = genBulletData(); + createBullet(b); + weaponMag -= 1; + } else { + auto result = weaponScript->lua["onShoot"](); + if (!result.valid()) { + sol::error err = result; + std::cerr << "lua error: " << err.what() << std::endl; + } + // auto reload + if ((weaponMag -= 1) <= 0) + reload(); + } + } else if (weaponMag <= 0) + reload(); + lastFireTime = currentTime; + } + } + return shotsFired; } -void Weapon::hookEventManager(std::weak_ptr eventManager) -{ - this->eventManager = eventManager; +void Weapon::hookEventManager(std::weak_ptr eventManager) { + this->eventManager = eventManager; - for (auto& component : components) - { - if (component->getType() == Component::TYPE::ANIMATION) - { - auto animComponent = static_cast(component.get()); - animComponent->getAnimationSet()->attachEventManager(eventManager); - } - } + for (auto &component : components) { + if (component->getType() == Component::TYPE::ANIMATION) { + auto animComponent = static_cast(component.get()); + animComponent->getAnimationSet()->attachEventManager(eventManager); + } + } - if (auto event = this->eventManager.lock()) { - auto self = this; - event->subscribe([self](const AnimationFinishedEvent& e) { - if (self) { - if (e.entityid == self->entityid && e.animType == "reload") - { - if (self->reloading) - { - self->reloading = false; - self->wasReloading = true; - } - } - } - }); - } + if (auto event = this->eventManager.lock()) { + auto self = this; + event->subscribe( + [self](const AnimationFinishedEvent &e) { + if (self) { + if (e.entityid == self->entityid && e.animType == "reload") { + if (self->reloading) { + self->reloading = false; + self->wasReloading = true; + } + } + } + }); + } - bulletManager->hookEventManager(eventManager); + bulletManager->hookEventManager(eventManager); } -void Weapon::attachScript(std::unique_ptr script) -{ - weaponScript = std::move(script); - weaponScript->lua["weapon"] = this; - LOG(DEBUG, "Weapon state bound", NULL); +void Weapon::attachScript(std::unique_ptr script) { + weaponScript = std::move(script); + weaponScript->lua["weapon"] = this; + LOG(DEBUG, "Weapon state bound", NULL); } -void Weapon::onHitCallback(GameActor* target, PhysicsComponent* bullet, const glm::vec2& normal) -{ - if (weaponScript && weaponScript->lua["onHit"].valid()) - { - auto result = weaponScript->lua["onHit"](target, bullet, normal); - if (!result.valid()) - { - sol::error err = result; - std::cerr << "lua error: " << err.what() << std::endl; - } - } +void Weapon::onHitCallback(GameActor *target, PhysicsComponent *bullet, + const glm::vec2 &normal) { + if (weaponScript && weaponScript->lua["onHit"].valid()) { + auto result = weaponScript->lua["onHit"](target, bullet, normal); + if (!result.valid()) { + sol::error err = result; + std::cerr << "lua error: " << err.what() << std::endl; + } + } } -void Weapon::update(double deltaTime) -{ - Entity::update(deltaTime); - if (wielded) - { - // move the weapon into place as the wielder rotates and moves - if (wielder) - adjustWeapon(); +void Weapon::update(double deltaTime) { + Entity::update(deltaTime); + if (wielded) { + // move the weapon into place as the wielder rotates and moves + if (wielder) + adjustWeapon(); - for (auto& component : components) - component->update(); - if (wasReloading) - { - wasReloading = false; - if (auto event = eventManager.lock()) { - event->notify({entityid}); - } - } - } - bulletManager->update(deltaTime); + for (auto &component : components) + component->update(); + if (wasReloading) { + wasReloading = false; + if (auto event = eventManager.lock()) { + event->notify({entityid}); + } + } + } + bulletManager->update(deltaTime); } -void Weapon::draw() -{ - Entity::draw(); - if (wielded) - { - for (auto& component : components) - { - component->play(); - component->bind(); - component->render(); - } - } - //bulletManager->draw(); +void Weapon::draw() { + Entity::draw(); + if (wielded) { + for (auto &component : components) { + component->play(); + component->bind(); + component->render(); + } + } + // bulletManager->draw(); } -void Weapon::adjustWeapon() -{ - float rotation = glm::radians(wielder->getRotation()); +void Weapon::adjustWeapon() { + float rotation = glm::radians(wielder->getRotation()); - glm::vec3 offset = glm::vec3( - cos(rotation) * ((wielder->getScale().x) - weaponSize.x * 0.5f), - sin(rotation) * ((wielder->getScale().y) - weaponSize.y * 0.5f), - 0.0f - ); - glm::vec3 origin = wielder->getCenter() + offset; - //origin.x += (weaponSize.x) * 0.25f; - //origin.y += (weaponSize.y) * 0.25f; + glm::vec3 offset = glm::vec3( + cos(rotation) * ((wielder->getScale().x) - weaponSize.x * 0.5f), + sin(rotation) * ((wielder->getScale().y) - weaponSize.y * 0.5f), 0.0f); + glm::vec3 origin = wielder->getCenter() + offset; + // origin.x += (weaponSize.x) * 0.25f; + // origin.y += (weaponSize.y) * 0.25f; - // Flip the texture if the weapon is facing upwards or downwards - Direction d = getDirectionFromRotation(glm::degrees(rotation)); - if ((lastDir == Direction::Up || lastDir == Direction::Left) && - (d == Direction::Down || d == Direction::Right) && !isFlipped()) - flip(); - if ((lastDir == Direction::Down || lastDir == Direction::Right) && - (d == Direction::Up || d == Direction::Left) && isFlipped()) - flip(); - - setRotation(wielder->getRotation() - 180); - setPosition(origin); - lastDir = getDirectionFromRotation(glm::degrees(rotation)); + // Flip the texture if the weapon is facing upwards or downwards + Direction d = getDirectionFromRotation(glm::degrees(rotation)); + if ((lastDir == Direction::Up || lastDir == Direction::Left) && + (d == Direction::Down || d == Direction::Right) && !isFlipped()) + flip(); + if ((lastDir == Direction::Down || lastDir == Direction::Right) && + (d == Direction::Up || d == Direction::Left) && isFlipped()) + flip(); + + setRotation(wielder->getRotation() - 180); + setPosition(origin); + lastDir = getDirectionFromRotation(glm::degrees(rotation)); } -Weapon::BulletData Weapon::genBulletData() -{ - BulletData b; - float rotation = glm::radians(wielder->getRotation()); - float spreadOffset = glm::radians(static_cast(bulletSpread->genFloat())); - b.mass = 0.1f; - glm::vec2 facing = glm::vec2( - cos(rotation + spreadOffset), - sin(rotation + spreadOffset) - ); - b.direction = glm::normalize(facing); - b.sizeMod = bulletModifer->genFloat(); - b.speedMod = bulletModifer->genFloat(); - b.dropMod = bulletModifer->genFloat(); +Weapon::BulletData Weapon::genBulletData() { + BulletData b; + float rotation = glm::radians(wielder->getRotation()); + float spreadOffset = + glm::radians(static_cast(bulletSpread->genFloat())); + b.mass = 0.1f; + glm::vec2 facing = + glm::vec2(cos(rotation + spreadOffset), sin(rotation + spreadOffset)); + b.direction = glm::normalize(facing); + b.sizeMod = bulletModifer->genFloat(); + b.speedMod = bulletModifer->genFloat(); + b.dropMod = bulletModifer->genFloat(); - double radius = wielder->getScale().x + (weaponSize.x * 0.5) + weaponOffset.x; + double radius = wielder->getScale().x + (weaponSize.x * 0.5) + weaponOffset.x; - b.origin = glm::vec3( - // x offset from the wielder - wielder->getCenter().x + cos(rotation) * radius - sin(rotation) * weaponOffset.y, - // y offset from the wielder - wielder->getCenter().y + sin(rotation) * radius + cos(rotation) * weaponOffset.y, - 0.0f - ); - b.origin.x -= ((bulletSize.x) * b.sizeMod) * 0.5f; - b.origin.y -= ((bulletSize.y) * b.sizeMod) * 0.5f; - return b; + b.origin = glm::vec3( + // x offset from the wielder + wielder->getCenter().x + cos(rotation) * radius - + sin(rotation) * weaponOffset.y, + // y offset from the wielder + wielder->getCenter().y + sin(rotation) * radius + + cos(rotation) * weaponOffset.y, + 0.0f); + b.origin.x -= ((bulletSize.x) * b.sizeMod) * 0.5f; + b.origin.y -= ((bulletSize.y) * b.sizeMod) * 0.5f; + return b; } -void Weapon::createBullet(const Weapon::BulletData& data) -{ - auto bullet = std::make_shared(wielder->getEntityID(), bulletShaderID, data.origin, data.direction, bulletSpeed, bulletDrop, bulletSize); - bullet->addComponent(bulletSprite.get()); - bullet->addPhysicsComponent(std::make_shared(PhysicsComponentFactory::makeBullet(wielder->getEntityID(), data.origin, data.mass, bulletSize.x / 2))); - bullet->getPhysicsComponent()->rigidBody.velocity += bulletSpeed * data.direction / data.mass; +void Weapon::createBullet(const Weapon::BulletData &data) { + auto bullet = std::make_shared(wielder->getEntityID(), bulletShaderID, + data.origin, data.direction, + bulletSpeed, bulletDrop, bulletSize); + bullet->addComponent(bulletSprite.get()); + bullet->addPhysicsComponent( + std::make_shared(PhysicsComponentFactory::makeBullet( + wielder->getEntityID(), data.origin, data.mass, bulletSize.x / 2))); + bullet->getPhysicsComponent()->rigidBody.velocity += + bulletSpeed * data.direction / data.mass; - if (auto event = eventManager.lock()) - event->notify({bullet}); - bulletManager->addBullet(bullet); + if (auto event = eventManager.lock()) + event->notify({bullet}); + bulletManager->addBullet(bullet); } -Weapon::~Weapon() -{ - if (weaponScript) { - weaponScript->lua["onShoot"] = sol::nil; - weaponScript->lua.collect_gc(); - } +Weapon::~Weapon() { + if (weaponScript) { + weaponScript->lua["onShoot"] = sol::nil; + weaponScript->lua.collect_gc(); + } } - -/* - !| SLATED FOR REMOVAL |! - -// Swap the reload animation and the regular weapon animation -void Weapon::swapSprites() -{ - //std::swap(weaponSprites.first, weaponSprites.second); -} - -void Weapon::checkAndFinishReload() -{ - if (weaponSprites.first->kill() && reloading) { - weaponSprites.first->idle(); - weaponSprites.first->reset(); - std::swap(weaponSprites.first, weaponSprites.second); - reloading = false; - } -} -*/ diff --git a/YuppleMayham/src/graphics/glwindow.cpp b/YuppleMayham/src/graphics/glwindow.cpp index 1c3e538..1757f24 100644 --- a/YuppleMayham/src/graphics/glwindow.cpp +++ b/YuppleMayham/src/graphics/glwindow.cpp @@ -1,5 +1,6 @@ #include "graphics/glwindow.h" #include +#include bool GLWindow::Init() { window = SDL_CreateWindow(name, SDL_WINDOWPOS_UNDEFINED, @@ -16,6 +17,11 @@ bool GLWindow::Init() { return true; } +void GLWindow::resizeWindow(size_t width, size_t height) { + w = width; + h = height; +} + GLWindow::~GLWindow() { SDL_GL_DeleteContext(glContext); SDL_DestroyWindow(window); diff --git a/YuppleMayham/src/graphics/renderer.cpp b/YuppleMayham/src/graphics/renderer.cpp index 58f1364..a11a6b5 100644 --- a/YuppleMayham/src/graphics/renderer.cpp +++ b/YuppleMayham/src/graphics/renderer.cpp @@ -28,6 +28,8 @@ void Renderer::hookEventManager(std::weak_ptr eventManager) { postProcessor->ApplyEffect(Postprocessor::BLUR, event.intensity, event.duration); }); + e->subscribe( + [this](const WindowResizeEvent &event) { resizeFrameBuffers(); }); } } @@ -41,7 +43,6 @@ void Renderer::initFrameBuffers() { // World buffer creation glGenTextures(1, &worldBuffer.texture); glBindTexture(GL_TEXTURE_2D, worldBuffer.texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glWindow->Width(), glWindow->Height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); @@ -88,6 +89,15 @@ void Renderer::initFrameBuffers() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void Renderer::resizeFrameBuffers() { + glDeleteFramebuffers(1, &worldBuffer.frame); + glDeleteFramebuffers(1, &hudBuffer.frame); + glDeleteTextures(1, &worldBuffer.texture); + glDeleteTextures(1, &hudBuffer.texture); + + initFrameBuffers(); +} + void Renderer::initUniformBuffers() { glGenBuffers(1, &uboMatrices);