Compare commits
2 commits
6ad1272d7d
...
3437441feb
| Author | SHA1 | Date | |
|---|---|---|---|
| 3437441feb | |||
| 701ac3e151 |
23 changed files with 1514 additions and 1526 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -366,3 +366,4 @@ FodyWeavers.xsd
|
||||||
*.swp
|
*.swp
|
||||||
/Resources/scenes/.debugScene.xml.swp
|
/Resources/scenes/.debugScene.xml.swp
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
compile_flags.txt
|
||||||
|
|
|
||||||
66
README.md
Normal file
66
README.md
Normal file
|
|
@ -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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
- Save/Load system
|
||||||
|
- Modular and scalable menu system
|
||||||
|
- In-game dialog and conversation systems
|
||||||
|
- Expanded combat system
|
||||||
|
|
@ -1,31 +1,19 @@
|
||||||
-- global vars
|
-- global vars
|
||||||
patrolDestination = { x=500.0, y=500.0, z=0.0 }
|
MoveLeft = true
|
||||||
moveLeft = true
|
|
||||||
-- helper functions
|
-- helper functions
|
||||||
function watchPosition(actor, pos)
|
local function watchPosition(actor, pos)
|
||||||
local y = pos.y - actor.position.y
|
local y = pos.y - actor.position.y
|
||||||
local x = pos.x - actor.position.x
|
local x = pos.x - actor.position.x
|
||||||
local rotation = math.atan2(y, x)
|
local rotation = math.atan2(y, x)
|
||||||
actor.rotation = math.deg(rotation)
|
actor.rotation = math.deg(rotation)
|
||||||
end
|
end
|
||||||
|
|
||||||
function distance(a, b)
|
local function distance(a, b)
|
||||||
local dx = a.x - b.x
|
local dx = a.x - b.x
|
||||||
local dy = a.y - b.y
|
local dy = a.y - b.y
|
||||||
return math.sqrt(dx * dx + dy * dy)
|
return math.sqrt(dx * dx + dy * dy)
|
||||||
end
|
end
|
||||||
|
|
||||||
function moveTo(actor, pos)
|
|
||||||
local a = actor
|
|
||||||
local p = pos
|
|
||||||
watchPosition(a, p)
|
|
||||||
if distance(a.position, p) < 50 then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
a:moveForward()
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Behaviour Functions called on AI
|
-- Behaviour Functions called on AI
|
||||||
|
|
||||||
-- These functions are ai behaviour functions called in the game
|
-- These functions are ai behaviour functions called in the game
|
||||||
|
|
@ -48,24 +36,12 @@ end
|
||||||
function patrol(actor, target)
|
function patrol(actor, target)
|
||||||
local a = actor
|
local a = actor
|
||||||
local t = target
|
local t = target
|
||||||
if t ~= nil then
|
|
||||||
-- print("target is at " .. target.position.x)
|
|
||||||
end
|
|
||||||
--if moveTo(actor, patrolDestination) == true then
|
|
||||||
-- patrolDestination = { x=math.random(400.0, 750.0), y=math.random(400.0, 750.0), z=0.0 }
|
|
||||||
--end
|
|
||||||
-- performRaycast returns if true if the raycast hits the target position it also sets the getter function
|
|
||||||
-- distFromWall, at bot creation distFromWall is and infinite float value.
|
|
||||||
-- This performRaycast function is highly discourage due to slow down
|
|
||||||
--if raycaster:performRaycast(actor.position, actor.rotation, target.position) == true then
|
|
||||||
--ai.state = AIState.Alert
|
|
||||||
--end
|
|
||||||
if raycaster:bresenhamRaycast(a.position, a.rotation, t.position) == true then
|
if raycaster:bresenhamRaycast(a.position, a.rotation, t.position) == true then
|
||||||
--target hit!
|
--target hit!
|
||||||
ai.state = AIState.Alert
|
ai.state = AIState.Alert
|
||||||
end
|
end
|
||||||
if raycaster:distFromWall() < 3 then
|
if raycaster:distFromWall() < 3 then
|
||||||
upOrDown = math.random(2)
|
local upOrDown = math.random(2)
|
||||||
if moveLeft == true then
|
if moveLeft == true then
|
||||||
if upOrDown == 1 then
|
if upOrDown == 1 then
|
||||||
a.rotation = 180
|
a.rotation = 180
|
||||||
|
|
@ -90,10 +66,8 @@ function alert(actor, target)
|
||||||
local a = actor
|
local a = actor
|
||||||
local t = target
|
local t = target
|
||||||
if target ~= nil then
|
if target ~= nil then
|
||||||
-- print("target is at " .. target.position.x)
|
|
||||||
watchPosition(a, t.position)
|
watchPosition(a, t.position)
|
||||||
end
|
end
|
||||||
--print("actor is alert at " .. actor.position.x)
|
|
||||||
if distance(a.position, t.position) > 300 then
|
if distance(a.position, t.position) > 300 then
|
||||||
a:moveForward()
|
a:moveForward()
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
-- helper functions
|
-- helper functions
|
||||||
|
|
||||||
function lookAway(actor, pos)
|
local function lookAway(actor, pos)
|
||||||
y = actor.position.y - pos.y
|
local y = actor.position.y - pos.y
|
||||||
x = actor.position.x - pos.x
|
local x = actor.position.x - pos.x
|
||||||
rotation = math.atan(y, x)
|
local rotation = math.atan(y, x)
|
||||||
actor.rotation = math.deg(rotation)
|
actor.rotation = math.deg(rotation)
|
||||||
end
|
end
|
||||||
|
|
||||||
function distance(a, b)
|
local function distance(a, b)
|
||||||
return math.sqrt((math.abs(a.x - b.x)^2) + (math.abs(a.y - b.y)^2))
|
return math.sqrt((math.abs(a.x - b.x) ^ 2) + (math.abs(a.y - b.y) ^ 2))
|
||||||
end
|
end
|
||||||
|
|
||||||
function idle(actor, target)
|
function idle(actor, target)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
find_package(SDL2 2.30.2 REQUIRED)
|
find_package(SDL2 2.30.2 REQUIRED)
|
||||||
find_package(SDL2_IMAGE 2.8.2 REQUIRED)
|
find_package(SDL2_image 2.8.2 REQUIRED)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(LuaJIT REQUIRED IMPORTED_TARGET GLOBAL luajit)
|
pkg_check_modules(LuaJIT REQUIRED IMPORTED_TARGET GLOBAL luajit)
|
||||||
find_package(sol2 REQUIRED)
|
find_package(sol2 REQUIRED)
|
||||||
|
|
@ -42,6 +42,7 @@ add_executable (YuppleMayham
|
||||||
"src/utility/ftfont.cpp"
|
"src/utility/ftfont.cpp"
|
||||||
"src/graphics/sprite.cpp"
|
"src/graphics/sprite.cpp"
|
||||||
"src/graphics/mesh.cpp"
|
"src/graphics/mesh.cpp"
|
||||||
|
"src/graphics/glwindow.cpp"
|
||||||
"src/gameplay/entity.cpp"
|
"src/gameplay/entity.cpp"
|
||||||
"src/gameplay/gameactor.cpp"
|
"src/gameplay/gameactor.cpp"
|
||||||
"src/graphics/shader.cpp"
|
"src/graphics/shader.cpp"
|
||||||
|
|
@ -104,6 +105,6 @@ endif()
|
||||||
|
|
||||||
target_include_directories(YuppleMayham PRIVATE "${PROJECT_SOURCE_DIR}/YuppleMayham/include" ${LuaJIT_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIR_ft2build})
|
target_include_directories(YuppleMayham PRIVATE "${PROJECT_SOURCE_DIR}/YuppleMayham/include" ${LuaJIT_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIR_ft2build})
|
||||||
|
|
||||||
target_link_libraries(YuppleMayham SDL2::SDL2main SDL2::SDL2 SDL2_image::SDL2_image openal glm::glm-header-only tinyxml2 freetype ${LuaJIT_LINK_LIBRARIES})
|
target_link_libraries(YuppleMayham SDL2::SDL2main SDL2::SDL2 SDL2_image::SDL2_image openal glm::glm tinyxml2 freetype ${LuaJIT_LINK_LIBRARIES})
|
||||||
|
|
||||||
# TODO: Add tests and install targets if needed.
|
# TODO: Add tests and install targets if needed.
|
||||||
|
|
|
||||||
|
|
@ -3,34 +3,35 @@
|
||||||
|
|
||||||
#include "gameplay/entity.h"
|
#include "gameplay/entity.h"
|
||||||
|
|
||||||
class Camera
|
class Camera {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Camera(float viewPortW, float viewPortH) :
|
Camera(float viewPortW, float viewPortH)
|
||||||
position(glm::vec3(0.0f, 0.0f, 0.0f)),
|
: position(glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||||
front(glm::vec3(0.0f, 0.0f, -1.0f)),
|
front(glm::vec3(0.0f, 0.0f, -1.0f)), up(glm::vec3(0.0f, 1.0f, 0.0f)),
|
||||||
up(glm::vec3(0.0f, 1.0f, 0.0f)),
|
viewPortW(viewPortW), viewPortH(viewPortH) {};
|
||||||
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 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); }
|
const glm::vec3 getCenterPos() const {
|
||||||
void setTarget(Entity* target) { this->target = target; }
|
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; }
|
void unsetTarget() { target = nullptr; }
|
||||||
bool isTargeting() { return (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 getViewMatrix();
|
||||||
glm::mat4 getProjectionMatrix();
|
glm::mat4 getProjectionMatrix();
|
||||||
const glm::vec3 getPosition() const { return position; }
|
const glm::vec3 getPosition() const { return position; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Entity* target = nullptr;
|
Entity *target = nullptr;
|
||||||
|
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
glm::vec3 front;
|
glm::vec3 front;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
#ifndef _H_GAME_H
|
#ifndef _H_GAME_H
|
||||||
#define _H_GAME_H
|
#define _H_GAME_H
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <SDL_events.h>
|
#include <SDL_events.h>
|
||||||
|
#include <memory>
|
||||||
#include <utility/events.h>
|
#include <utility/events.h>
|
||||||
|
|
||||||
|
#include "gameplay/camera.h"
|
||||||
|
|
||||||
class InputHandler;
|
class InputHandler;
|
||||||
class Scene;
|
class Scene;
|
||||||
class Text;
|
class Text;
|
||||||
|
|
@ -13,22 +15,16 @@ class Renderer;
|
||||||
class AudioEngine;
|
class AudioEngine;
|
||||||
class GLWindow;
|
class GLWindow;
|
||||||
|
|
||||||
enum {
|
enum { GAME_QUITTING = 0, GAME_RUNNING = 1, GAME_MENU = 2, GAME_PLAYING = 4 };
|
||||||
GAME_QUITTING = 0,
|
|
||||||
GAME_RUNNING = 1,
|
|
||||||
GAME_MENU = 2,
|
|
||||||
GAME_PLAYING = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
class Game
|
class Game {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Game() {}
|
Game() {}
|
||||||
bool init();
|
bool init();
|
||||||
|
|
||||||
bool loadDebugScene();
|
bool loadDebugScene();
|
||||||
|
|
||||||
void captureInput(SDL_Event& e);
|
void captureInput(SDL_Event &e);
|
||||||
void executeInputs();
|
void executeInputs();
|
||||||
|
|
||||||
void update(double deltaTime);
|
void update(double deltaTime);
|
||||||
|
|
@ -47,6 +43,7 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<GLWindow> window;
|
std::shared_ptr<GLWindow> window;
|
||||||
|
|
||||||
|
std::unique_ptr<Camera> camera;
|
||||||
std::shared_ptr<Scene> currentScene;
|
std::shared_ptr<Scene> currentScene;
|
||||||
std::shared_ptr<InputHandler> inputHandler;
|
std::shared_ptr<InputHandler> inputHandler;
|
||||||
std::shared_ptr<ResourceManager> resourceManager;
|
std::shared_ptr<ResourceManager> resourceManager;
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,14 @@
|
||||||
#define _H_GLWINDOW_H
|
#define _H_GLWINDOW_H
|
||||||
|
|
||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
//#include <SDL_opengl.h>
|
|
||||||
|
|
||||||
#include <thirdparty/glad/glad.h>
|
#include <thirdparty/glad/glad.h>
|
||||||
|
|
||||||
class GLWindow
|
#include "utility/logger.h"
|
||||||
{
|
|
||||||
|
class GLWindow {
|
||||||
public:
|
public:
|
||||||
GLWindow(const char* windowName, int width, int height) :
|
GLWindow(const char *windowName, int width, int height)
|
||||||
w(width),
|
: w(width), h(height), name(windowName) {};
|
||||||
h(height),
|
|
||||||
name(windowName) {};
|
|
||||||
~GLWindow();
|
~GLWindow();
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
|
|
@ -20,34 +17,20 @@ public:
|
||||||
void swap() { SDL_GL_SwapWindow(window); }
|
void swap() { SDL_GL_SwapWindow(window); }
|
||||||
void makeCurrent() { SDL_GL_MakeCurrent(window, glContext); }
|
void makeCurrent() { SDL_GL_MakeCurrent(window, glContext); }
|
||||||
|
|
||||||
unsigned width() const { return w; }
|
unsigned Width() const { return w; }
|
||||||
unsigned height() const { return h; }
|
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; }
|
||||||
|
|
||||||
SDL_Window* getWindow() const { return window; }
|
|
||||||
const SDL_GLContext& getContext() const { return glContext; }
|
|
||||||
private:
|
private:
|
||||||
SDL_Window* window = nullptr;
|
SDL_Window *window = nullptr;
|
||||||
SDL_GLContext glContext = NULL;
|
SDL_GLContext glContext = NULL;
|
||||||
|
|
||||||
unsigned w, h;
|
unsigned w, h;
|
||||||
const char* name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool GLWindow::Init()
|
|
||||||
{
|
|
||||||
window = SDL_CreateWindow(name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL);
|
|
||||||
if (!window)
|
|
||||||
return false;
|
|
||||||
glContext = SDL_GL_CreateContext(window);
|
|
||||||
if (!glContext)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLWindow::~GLWindow()
|
|
||||||
{
|
|
||||||
SDL_GL_DeleteContext(glContext);
|
|
||||||
SDL_DestroyWindow(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _H_GLWINDOW_H
|
#endif // _H_GLWINDOW_H
|
||||||
|
|
|
||||||
|
|
@ -1,74 +1,67 @@
|
||||||
#ifndef _H_RENDERER_H
|
#ifndef _H_RENDERER_H
|
||||||
#define _H_RENDERER_H
|
#define _H_RENDERER_H
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <memory>
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "graphics/quad.h"
|
|
||||||
#include "graphics/drawable.h"
|
#include "graphics/drawable.h"
|
||||||
|
#include "graphics/glwindow.h"
|
||||||
#include "graphics/postprocess.h"
|
#include "graphics/postprocess.h"
|
||||||
|
#include "graphics/quad.h"
|
||||||
|
|
||||||
class ResourceManager;
|
class ResourceManager;
|
||||||
class Shader;
|
class Shader;
|
||||||
|
|
||||||
enum class RenderLayer {
|
enum class RenderLayer { Background, Map, GameObjects, Effects, HUD, Menu };
|
||||||
Background,
|
|
||||||
Map,
|
|
||||||
GameObjects,
|
|
||||||
Effects,
|
|
||||||
HUD,
|
|
||||||
Menu
|
|
||||||
};
|
|
||||||
|
|
||||||
class Renderer
|
class Renderer {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Renderer(const std::shared_ptr<ResourceManager>&);
|
Renderer(const std::shared_ptr<ResourceManager> &,
|
||||||
|
const std::shared_ptr<GLWindow> &);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void hookEventManager(const std::weak_ptr<EventManager> eventManager);
|
void hookEventManager(const std::weak_ptr<EventManager> eventManager);
|
||||||
|
|
||||||
void setProjAndViewMatrix(const glm::mat4& proj, const glm::mat4& view);
|
void setProjAndViewMatrix(const glm::mat4 &proj, const glm::mat4 &view);
|
||||||
void addDrawable(RenderLayer renderLayer, Drawable *drawable);
|
void addDrawable(RenderLayer renderLayer, Drawable *drawable);
|
||||||
void removeDrawable(RenderLayer renderLayer, Drawable *drawable);
|
void removeDrawable(RenderLayer renderLayer, Drawable *drawable);
|
||||||
|
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<RenderLayer, std::vector<Drawable*>> worldLayerPool;
|
std::unordered_map<RenderLayer, std::vector<Drawable *>> worldLayerPool;
|
||||||
std::unordered_map<RenderLayer, std::vector<Drawable*>> HUDLayerPool;
|
std::unordered_map<RenderLayer, std::vector<Drawable *>> HUDLayerPool;
|
||||||
std::vector<RenderLayer> renderingOrder = {
|
std::vector<RenderLayer> renderingOrder = {
|
||||||
RenderLayer::Background,
|
RenderLayer::Background, RenderLayer::Map, RenderLayer::GameObjects,
|
||||||
RenderLayer::Map,
|
RenderLayer::Effects, RenderLayer::HUD, RenderLayer::Menu};
|
||||||
RenderLayer::GameObjects,
|
|
||||||
RenderLayer::Effects,
|
|
||||||
RenderLayer::HUD,
|
|
||||||
RenderLayer::Menu
|
|
||||||
};
|
|
||||||
|
|
||||||
void uploadUniforms(const unsigned shaderID, const std::vector<Uniform>& uniforms);
|
void uploadUniforms(const unsigned shaderID,
|
||||||
|
const std::vector<Uniform> &uniforms);
|
||||||
|
|
||||||
unsigned uboMatrices;
|
unsigned uboMatrices;
|
||||||
|
|
||||||
union FrameBuffer {
|
union FrameBuffer {
|
||||||
unsigned int frame;
|
unsigned int frame;
|
||||||
unsigned int texture;
|
unsigned int texture;
|
||||||
}worldBuffer, hudBuffer;
|
} worldBuffer, hudBuffer;
|
||||||
|
|
||||||
std::unique_ptr<ScreenQuad> screenQuad;
|
std::unique_ptr<ScreenQuad> screenQuad;
|
||||||
|
|
||||||
std::shared_ptr<ResourceManager> resourceManager;
|
std::shared_ptr<ResourceManager> resourceManager;
|
||||||
|
std::shared_ptr<GLWindow> glWindow;
|
||||||
|
|
||||||
void initFrameBuffers();
|
void initFrameBuffers();
|
||||||
void initUniformBuffers();
|
void initUniformBuffers();
|
||||||
|
|
||||||
|
void resizeFrameBuffers();
|
||||||
|
|
||||||
std::unique_ptr<Postprocessor> postProcessor;
|
std::unique_ptr<Postprocessor> postProcessor;
|
||||||
|
|
||||||
void sortLayerPool(auto& layerPool);
|
void sortLayerPool(auto &layerPool);
|
||||||
void renderPool(auto& layerPool);
|
void renderPool(auto &layerPool);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
#ifndef _H_EVENTS_H
|
#ifndef _H_EVENTS_H
|
||||||
#define _H_EVENTS_H
|
#define _H_EVENTS_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "utility/direction.h"
|
#include "utility/direction.h"
|
||||||
|
|
@ -73,31 +73,31 @@ struct ScreenBlurEvent {
|
||||||
float duration;
|
float duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WindowResizeEvent {
|
||||||
|
size_t width;
|
||||||
|
size_t height;
|
||||||
|
};
|
||||||
|
|
||||||
class EventManager {
|
class EventManager {
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T> using EventCallback = std::function<void(const T &)>;
|
||||||
using EventCallback = std::function<void(const T&)>;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T> void subscribe(EventCallback<T> cb) {
|
||||||
void subscribe(EventCallback<T> cb) {
|
auto wrapper = [cb](void *ev) { cb(*static_cast<T *>(ev)); };
|
||||||
auto wrapper = [cb](void *ev) {
|
|
||||||
cb(*static_cast<T*>(ev));
|
|
||||||
};
|
|
||||||
callbacks[typeid(T)].push_back(wrapper);
|
callbacks[typeid(T)].push_back(wrapper);
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T> void notify(const T &event) {
|
||||||
void notify(const T& event) {
|
|
||||||
auto iterator = callbacks.find(typeid(T));
|
auto iterator = callbacks.find(typeid(T));
|
||||||
if (iterator != callbacks.end())
|
if (iterator != callbacks.end()) {
|
||||||
{
|
for (auto &cb : iterator->second) {
|
||||||
for (auto& cb : iterator->second)
|
cb((void *)&event);
|
||||||
{
|
|
||||||
cb((void*)&event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map <std::type_index, std::vector <std::function<void(void*)>>> callbacks;
|
std::unordered_map<std::type_index, std::vector<std::function<void(void *)>>>
|
||||||
|
callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_H_EVENTS_H
|
#endif //_H_EVENTS_H
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,20 @@
|
||||||
#include "utility/raycaster.h"
|
#include "utility/raycaster.h"
|
||||||
#include "utility/script.h"
|
#include "utility/script.h"
|
||||||
|
|
||||||
AI::AI(GameActor* actor, std::unique_ptr<Raycaster> raycaster)
|
AI::AI(GameActor *actor, std::unique_ptr<Raycaster> raycaster)
|
||||||
: state(AIState::Idle), raycaster(std::move(raycaster)), actor(actor),
|
: state(AIState::Idle), raycaster(std::move(raycaster)), actor(actor),
|
||||||
lastGCTime(std::chrono::high_resolution_clock::now()), GCTimeout(3)
|
lastGCTime(std::chrono::high_resolution_clock::now()), GCTimeout(3) {}
|
||||||
{}
|
|
||||||
|
|
||||||
void AI::attachBehaviourScript(std::unique_ptr<AIScript> behaviour)
|
/*
|
||||||
{
|
* 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<AIScript> behaviour) {
|
||||||
// passing out instance of raycaster and this AI into our scripting api
|
// 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!
|
// pay special attention each ai script has control of only their own instance
|
||||||
|
// of ai!
|
||||||
this->behaviour = std::move(behaviour);
|
this->behaviour = std::move(behaviour);
|
||||||
this->behaviour->lua["raycaster"] = sol::make_reference(this->behaviour->lua, raycaster.get());
|
this->behaviour->lua["raycaster"] =
|
||||||
|
sol::make_reference(this->behaviour->lua, raycaster.get());
|
||||||
this->behaviour->lua["ai"] = sol::make_reference(this->behaviour->lua, this);
|
this->behaviour->lua["ai"] = sol::make_reference(this->behaviour->lua, this);
|
||||||
|
|
||||||
idleFunc = this->behaviour->lua["idle"];
|
idleFunc = this->behaviour->lua["idle"];
|
||||||
|
|
@ -22,62 +25,66 @@ void AI::attachBehaviourScript(std::unique_ptr<AIScript> behaviour)
|
||||||
alertFunc = this->behaviour->lua["alert"];
|
alertFunc = this->behaviour->lua["alert"];
|
||||||
}
|
}
|
||||||
|
|
||||||
void AI::update()
|
void AI::update() {
|
||||||
{
|
|
||||||
try {
|
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) {
|
if (actor && target) {
|
||||||
switch (state)
|
switch (state) {
|
||||||
{
|
|
||||||
case AIState::Idle:
|
case AIState::Idle:
|
||||||
if (idleFunc.valid())
|
if (idleFunc.valid()) {
|
||||||
{
|
|
||||||
auto result = idleFunc(actor, target);
|
auto result = idleFunc(actor, target);
|
||||||
if (!result.valid())
|
if (!result.valid()) {
|
||||||
{
|
|
||||||
sol::error err = result;
|
sol::error err = result;
|
||||||
std::cerr << "lua error: " << err.what() << std::endl;
|
LOG(ERROR, "Lua error: {}", err.what(), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AIState::Patrol:
|
case AIState::Patrol:
|
||||||
if (patrolFunc.valid())
|
if (patrolFunc.valid()) {
|
||||||
{
|
|
||||||
auto result = patrolFunc(actor, target);
|
auto result = patrolFunc(actor, target);
|
||||||
if (!result.valid())
|
if (!result.valid()) {
|
||||||
{
|
|
||||||
sol::error err = result;
|
sol::error err = result;
|
||||||
std::cerr << "lua error: " << err.what() << std::endl;
|
LOG(ERROR, "Lua error: {}", err.what(), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AIState::Alert:
|
case AIState::Alert:
|
||||||
if (alertFunc.valid())
|
if (alertFunc.valid()) {
|
||||||
{
|
|
||||||
auto result = alertFunc(actor, target);
|
auto result = alertFunc(actor, target);
|
||||||
if (!result.valid())
|
if (!result.valid()) {
|
||||||
{
|
|
||||||
sol::error err = result;
|
sol::error err = result;
|
||||||
std::cerr << "lua error: " << err.what() << std::endl;
|
LOG(ERROR, "Lua error: {}", err.what(), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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());
|
||||||
}
|
}
|
||||||
std::chrono::high_resolution_clock::time_point curTime = std::chrono::high_resolution_clock::now();
|
}
|
||||||
if (curTime - lastGCTime >= GCTimeout)
|
}
|
||||||
{
|
// 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();
|
behaviour->lua.collect_gc();
|
||||||
lastGCTime = curTime;
|
lastGCTime = curTime;
|
||||||
}
|
}
|
||||||
}
|
} catch (const std::exception &e) {
|
||||||
catch (const std::exception& e) {
|
LOG(ERROR, "Problem occured during AI update: {}", e.what());
|
||||||
std::cerr << "Error during AI update: " << e.what() << std::endl;
|
|
||||||
state = AIState::Idle;
|
state = AIState::Idle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AI::~AI()
|
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["raycaster"] = sol::nil;
|
||||||
behaviour->lua["ai"] = sol::nil;
|
behaviour->lua["ai"] = sol::nil;
|
||||||
behaviour->lua["idle"] = sol::nil;
|
behaviour->lua["idle"] = sol::nil;
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,31 @@
|
||||||
#include "gameplay/camera.h"
|
#include "gameplay/camera.h"
|
||||||
|
|
||||||
void Camera::update(double 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)
|
if (target == nullptr)
|
||||||
return;
|
return;
|
||||||
float smoothingFactor = 5.0f;
|
float smoothingFactor = 5.0f;
|
||||||
//if (glm::distance(target->getCenter(), getCenterPos()) > 20.f)
|
// if (glm::distance(target->getCenter(), getCenterPos()) > 20.f)
|
||||||
position += (target->getCenter() - getCenterPos()) * smoothingFactor * static_cast<float>(deltaTime);
|
position += (target->getCenter() - getCenterPos()) * smoothingFactor *
|
||||||
|
static_cast<float>(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 Camera::getViewMatrix()
|
glm::mat4 Camera::getViewMatrix() {
|
||||||
{
|
|
||||||
return glm::lookAt(position, position + front, up);
|
return glm::lookAt(position, position + front, up);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 Camera::getProjectionMatrix()
|
glm::mat4 Camera::getProjectionMatrix() {
|
||||||
{
|
|
||||||
return glm::ortho(0.f, viewPortW, viewPortH, 0.f);
|
return glm::ortho(0.f, viewPortW, viewPortH, 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
const glm::vec3 Camera::worldToLocal(const glm::vec3& worldCoordinates)
|
void Camera::setViewportSize(float width, float height) {
|
||||||
{
|
viewPortW = width;
|
||||||
//return worldCoordinates - position;
|
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));
|
return glm::vec3(getViewMatrix() * glm::vec4(worldCoordinates, 1.0f));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ void Entity::flip()
|
||||||
flipped = !flipped;
|
flipped = !flipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add physics component implies more than one can be attached to an entity...
|
||||||
void Entity::addPhysicsComponent(const std::shared_ptr<PhysicsComponent>& physics)
|
void Entity::addPhysicsComponent(const std::shared_ptr<PhysicsComponent>& physics)
|
||||||
{
|
{
|
||||||
this->physics = physics;
|
this->physics = physics;
|
||||||
|
|
@ -39,6 +40,8 @@ void Entity::addPhysicsComponent(const std::shared_ptr<PhysicsComponent>& physic
|
||||||
|
|
||||||
void Entity::update(double deltaTime)
|
void Entity::update(double deltaTime)
|
||||||
{
|
{
|
||||||
|
// If our entity has a physics component attached and that they're moving,
|
||||||
|
// we will update the entity position to match the rigidBody position.
|
||||||
if (physics && physics->rigidBody.velocity != glm::vec2(0.0f))
|
if (physics && physics->rigidBody.velocity != glm::vec2(0.0f))
|
||||||
{
|
{
|
||||||
position = glm::vec3(physics->rigidBody.position, 0.f);
|
position = glm::vec3(physics->rigidBody.position, 0.f);
|
||||||
|
|
@ -47,21 +50,24 @@ void Entity::update(double deltaTime)
|
||||||
}
|
}
|
||||||
else if (!physics)
|
else if (!physics)
|
||||||
{
|
{
|
||||||
|
// In the case that the entity does not have a physics component we will handle movement on the entity itself.
|
||||||
position += deltaPosition * 1.f;
|
position += deltaPosition * 1.f;
|
||||||
updateModelMatrix();
|
updateModelMatrix();
|
||||||
deltaPosition = glm::vec3(0.f);
|
deltaPosition = glm::vec3(0.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The entity will only need to update its model matrix and the flipped flag on its attached shader.
|
||||||
|
// The shader and sprite component will handle the drawing.
|
||||||
void Entity::draw()
|
void Entity::draw()
|
||||||
{
|
{
|
||||||
//glm::mat4 mvp = camera->getProjectionMatrix() * camera->getViewMatrix() * modelMatrix;
|
|
||||||
editUniform("model", modelMatrix);
|
editUniform("model", modelMatrix);
|
||||||
editUniform("flip", flipped);
|
editUniform("flip", flipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::updateModelMatrix()
|
void Entity::updateModelMatrix()
|
||||||
{
|
{
|
||||||
|
// Quick sanity check to make sure our Z position is zero. Since we are in 2D
|
||||||
position.z = 0.f;
|
position.z = 0.f;
|
||||||
glm::mat4 rotationMat = (isRotatable) ? glm::rotate(glm::mat4(1.f), glm::radians(rotation), glm::vec3(0.0f, 0.0f, 1.0f)) : glm::mat4(1.0f);
|
glm::mat4 rotationMat = (isRotatable) ? glm::rotate(glm::mat4(1.f), glm::radians(rotation), glm::vec3(0.0f, 0.0f, 1.0f)) : glm::mat4(1.0f);
|
||||||
glm::mat4 translation = glm::translate(glm::mat4(1.f), position);
|
glm::mat4 translation = glm::translate(glm::mat4(1.f), position);
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,23 @@
|
||||||
#include "gameplay/game.h"
|
#include "gameplay/game.h"
|
||||||
#include "gameplay/input.h"
|
#include "gameplay/input.h"
|
||||||
#include "gameplay/scene.h"
|
#include "gameplay/scene.h"
|
||||||
/*due for possible removal!*/
|
|
||||||
#include "gameplay/gameactor.h"
|
|
||||||
#include "gameplay/weapons/weapon.h"
|
|
||||||
/*-------------------------*/
|
|
||||||
|
|
||||||
#include "utility/command.h"
|
#include "utility/command.h"
|
||||||
#include "utility/resourcemanager.h"
|
|
||||||
#include "utility/ftfont.h"
|
#include "utility/ftfont.h"
|
||||||
#include "utility/logger.h"
|
#include "utility/logger.h"
|
||||||
|
#include "utility/resourcemanager.h"
|
||||||
|
|
||||||
#include "graphics/glwindow.h"
|
#include "graphics/glwindow.h"
|
||||||
|
|
||||||
#include "sound/engine.h"
|
#include "sound/engine.h"
|
||||||
|
|
||||||
|
#include <SDL_video.h>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
|
||||||
#include <utility/events.h>
|
#include <utility/events.h>
|
||||||
|
|
||||||
bool Game::init()
|
bool Game::init() {
|
||||||
{
|
window = std::make_shared<GLWindow>("Yupple Mayham", 1024, 768);
|
||||||
window = std::make_shared<GLWindow>("Yupple Mayham", 800, 600);
|
|
||||||
|
|
||||||
if (!window->Init())
|
if (!window->Init())
|
||||||
ERROR_LOG("Failed to init GLWindow: {}", SDL_GetError());
|
ERROR_LOG("Failed to init GLWindow: {}", SDL_GetError());
|
||||||
|
|
@ -37,27 +32,31 @@ bool Game::init()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SDL_GL_SetSwapInterval(1);
|
SDL_GL_SetSwapInterval(1);
|
||||||
glViewport(0, 0, window->width(), window->height());
|
glViewport(0, 0, window->Width(), window->Height());
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
// For now we'll init default bindings, but as we move forward controls will be set by the player and saved in controls.xml
|
// For now we'll init default bindings, but as we move forward controls will
|
||||||
|
// be set by the player and saved in controls.xml
|
||||||
inputHandler = std::make_shared<InputHandler>();
|
inputHandler = std::make_shared<InputHandler>();
|
||||||
inputHandler->bindKeyCommand(SDLK_w, 0, std::make_unique<MoveUpCommand>());
|
inputHandler->bindKeyCommand(SDLK_w, 0, std::make_unique<MoveUpCommand>());
|
||||||
inputHandler->bindKeyCommand(SDLK_a, 0, std::make_unique<MoveLeftCommand>());
|
inputHandler->bindKeyCommand(SDLK_a, 0, std::make_unique<MoveLeftCommand>());
|
||||||
inputHandler->bindKeyCommand(SDLK_s, 0, std::make_unique<MoveDownCommand>());
|
inputHandler->bindKeyCommand(SDLK_s, 0, std::make_unique<MoveDownCommand>());
|
||||||
inputHandler->bindKeyCommand(SDLK_d, 0, std::make_unique<MoveRightCommand>());
|
inputHandler->bindKeyCommand(SDLK_d, 0, std::make_unique<MoveRightCommand>());
|
||||||
|
|
||||||
inputHandler->bindMouseCommand(MOUSE_BUTTON_LEFT, 100, std::make_unique<ShootCommand>());
|
inputHandler->bindMouseCommand(MOUSE_BUTTON_LEFT, 100,
|
||||||
|
std::make_unique<ShootCommand>());
|
||||||
inputHandler->bindMouseMotion(std::make_unique<FollowMouseCommand>());
|
inputHandler->bindMouseMotion(std::make_unique<FollowMouseCommand>());
|
||||||
inputHandler->bindMouseScroll(std::make_unique<CycleCommand>());
|
inputHandler->bindMouseScroll(std::make_unique<CycleCommand>());
|
||||||
|
|
||||||
game_state |= GAME_RUNNING;
|
game_state |= GAME_RUNNING;
|
||||||
globalEventManager = std::make_shared<EventManager>();
|
globalEventManager = std::make_shared<EventManager>();
|
||||||
resourceManager = std::make_shared<ResourceManager>();
|
resourceManager = std::make_shared<ResourceManager>();
|
||||||
renderer = std::make_shared<Renderer>(resourceManager);
|
renderer = std::make_shared<Renderer>(resourceManager, window);
|
||||||
audioEngine = std::make_shared<AudioEngine>(resourceManager);
|
audioEngine = std::make_shared<AudioEngine>(resourceManager);
|
||||||
|
camera = std::make_unique<Camera>(static_cast<float>(window->Width()),
|
||||||
|
static_cast<float>(window->Height()));
|
||||||
audioEngine->hookEventManager(globalEventManager);
|
audioEngine->hookEventManager(globalEventManager);
|
||||||
/* Testing */
|
/* Testing */
|
||||||
audioEngine->pushMusic("music/short_song.ogg");
|
audioEngine->pushMusic("music/short_song.ogg");
|
||||||
|
|
@ -72,65 +71,66 @@ bool Game::init()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned Game::getWindowWidth() const { return window->width(); }
|
const unsigned Game::getWindowWidth() const { return window->Width(); }
|
||||||
const unsigned Game::getWindowHeight() const { return window->height(); }
|
const unsigned Game::getWindowHeight() const { return window->Height(); }
|
||||||
|
|
||||||
bool Game::loadDebugScene()
|
bool Game::loadDebugScene() {
|
||||||
{
|
currentScene = std::make_shared<Scene>(SCENE_SHOOTER, resourceManager,
|
||||||
currentScene = std::make_shared<Scene>(SCENE_SHOOTER, resourceManager, globalEventManager);
|
globalEventManager);
|
||||||
currentScene->init();
|
currentScene->init();
|
||||||
audioEngine->hookSceneManager(currentScene->getEventManager());
|
audioEngine->hookSceneManager(currentScene->getEventManager());
|
||||||
if (currentScene->getPlayer() == nullptr)
|
if (currentScene->getPlayer() == nullptr)
|
||||||
return false;
|
return false;
|
||||||
inputHandler->setActor(currentScene->getPlayer().get());
|
inputHandler->setActor(currentScene->getPlayer().get());
|
||||||
|
camera->setTarget(currentScene->getPlayer().get());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::captureInput(SDL_Event& e)
|
void Game::captureInput(SDL_Event &e) {
|
||||||
{
|
|
||||||
inputHandler->captureInput(e);
|
inputHandler->captureInput(e);
|
||||||
|
if (e.type == SDL_WINDOWEVENT_RESIZED) {
|
||||||
|
size_t width = static_cast<size_t>(e.window.data1);
|
||||||
|
size_t height = static_cast<size_t>(e.window.data2);
|
||||||
|
globalEventManager->notify<WindowResizeEvent>({width, height});
|
||||||
|
window->resizeWindow(width, height);
|
||||||
|
camera->setViewportSize(static_cast<float>(e.window.data1),
|
||||||
|
static_cast<float>(e.window.data2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::executeInputs()
|
void Game::executeInputs() {
|
||||||
{
|
|
||||||
inputHandler->handleInput();
|
inputHandler->handleInput();
|
||||||
inputHandler->executeCommands();
|
inputHandler->executeCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::update(double deltaTime)
|
void Game::update(double deltaTime) {
|
||||||
{
|
|
||||||
if (currentScene) {
|
if (currentScene) {
|
||||||
currentScene->update(deltaTime);
|
currentScene->update(deltaTime);
|
||||||
if (auto player = currentScene->getPlayer())
|
if (auto player = currentScene->getPlayer()) {
|
||||||
audioEngine->updateListener(player->getPosition());
|
audioEngine->updateListener(player->getPosition());
|
||||||
|
player->setLocalPosition(camera->worldToLocal(player->getPosition()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
camera->update(deltaTime);
|
||||||
audioEngine->poll();
|
audioEngine->poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::render()
|
void Game::render() {
|
||||||
{
|
|
||||||
glClearColor(0.05f, 0.25f, 0.05f, 1.0f);
|
glClearColor(0.05f, 0.25f, 0.05f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
renderer->setProjAndViewMatrix(camera->getProjectionMatrix(),
|
||||||
|
camera->getViewMatrix());
|
||||||
|
|
||||||
if (currentScene)
|
if (currentScene)
|
||||||
{
|
|
||||||
currentScene->render(renderer);
|
currentScene->render(renderer);
|
||||||
/*Debug ammo indicator*/
|
|
||||||
textHandler->DrawText("comic.ttf", std::to_string(currentScene->getPlayer()->getHeldWeapon()->getMagazine()), glm::vec2(10, 10), 0.5f);
|
|
||||||
textHandler->DrawText("comic.ttf", "/", glm::vec2(50, 10), 0.5f);
|
|
||||||
textHandler->DrawText("comic.ttf", std::to_string(currentScene->getPlayer()->getHeldWeapon()->getAmmo()), glm::vec2(90, 10), 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
window->swap();
|
window->swap();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::quit()
|
void Game::quit() { game_state = GAME_QUITTING; }
|
||||||
{
|
|
||||||
game_state = GAME_QUITTING;
|
|
||||||
}
|
|
||||||
|
|
||||||
Game::~Game()
|
Game::~Game() {
|
||||||
{
|
|
||||||
if (audioEngine) {
|
if (audioEngine) {
|
||||||
audioEngine->killMusic();
|
audioEngine->killMusic();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,31 +3,33 @@
|
||||||
#include "gameplay/physics.h"
|
#include "gameplay/physics.h"
|
||||||
#include "gameplay/scene.h"
|
#include "gameplay/scene.h"
|
||||||
#include "gameplay/weapons/weapon.h"
|
#include "gameplay/weapons/weapon.h"
|
||||||
#include "utility/events.h"
|
|
||||||
#include "utility/direction.h"
|
|
||||||
#include "utility/component.h"
|
#include "utility/component.h"
|
||||||
|
#include "utility/direction.h"
|
||||||
|
#include "utility/events.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
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)
|
// 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) {
|
||||||
component->ownerid = entityid;
|
component->ownerid = entityid;
|
||||||
components.push_back(std::move(component));
|
components.push_back(std::move(component));
|
||||||
}
|
}
|
||||||
|
|
||||||
Weapon* GameActor::getHeldWeapon() const
|
Weapon *GameActor::getHeldWeapon() const {
|
||||||
{
|
return (weapons.empty() || currentWeaponIndex >= weapons.size())
|
||||||
return (weapons.empty() || currentWeaponIndex >= weapons.size()) ? nullptr : weapons[currentWeaponIndex].get();
|
? nullptr
|
||||||
|
: weapons[currentWeaponIndex].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::span<Weapon*> GameActor::getAllWeapons()
|
std::span<Weapon *> GameActor::getAllWeapons() { return weaponCache; }
|
||||||
{
|
|
||||||
return weaponCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameActor::pickupWeapon(std::unique_ptr<Weapon> weapon)
|
// Keep a seperate vector that is used as the cache for external calls to
|
||||||
{
|
// getAllWeapons()
|
||||||
|
void GameActor::pickupWeapon(std::unique_ptr<Weapon> weapon) {
|
||||||
weapon->setWielder(this);
|
weapon->setWielder(this);
|
||||||
if (auto eventManager = sceneContext->getEventManager().lock()) {
|
if (auto eventManager = sceneContext->getEventManager().lock()) {
|
||||||
weapon->hookEventManager(eventManager);
|
weapon->hookEventManager(eventManager);
|
||||||
|
|
@ -40,69 +42,79 @@ void GameActor::pickupWeapon(std::unique_ptr<Weapon> weapon)
|
||||||
getHeldWeapon()->wield();
|
getHeldWeapon()->wield();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameActor::setRotation(const float& rotation)
|
void GameActor::setRotation(const float &rotation) {
|
||||||
{
|
// Any attached animation component would be interested if their owner needs
|
||||||
|
// their sprite swapped
|
||||||
if (!isRotatable) {
|
if (!isRotatable) {
|
||||||
if (auto eventManager = sceneContext->getEventManager().lock()) {
|
if (auto eventManager = sceneContext->getEventManager().lock()) {
|
||||||
Direction newDir = getDirectionFromRotation(rotation);
|
Direction newDir = getDirectionFromRotation(rotation);
|
||||||
if (getDirectionFromRotation(this->rotation) != newDir)
|
if (getDirectionFromRotation(this->rotation) != newDir)
|
||||||
eventManager->notify<DirectionChangeEvent>({ entityid, newDir });
|
eventManager->notify<DirectionChangeEvent>({entityid, newDir});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->rotation = rotation;
|
this->rotation = rotation;
|
||||||
updateModelMatrix();
|
updateModelMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameActor::update(double deltaTime)
|
void GameActor::update(double deltaTime) {
|
||||||
{
|
|
||||||
Entity::update(deltaTime);
|
Entity::update(deltaTime);
|
||||||
|
|
||||||
for (const auto& component : components)
|
for (const auto &component : components)
|
||||||
component->update();
|
component->update();
|
||||||
for (const auto& weapon : weapons)
|
for (const auto &weapon : weapons)
|
||||||
weapon->update(deltaTime);
|
weapon->update(deltaTime);
|
||||||
|
|
||||||
if (isMoving && !wasMoving)
|
// 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()) {
|
if (auto event = sceneContext->getEventManager().lock()) {
|
||||||
event->notify<EntityMoveEvent>({ entityid });
|
event->notify<EntityMoveEvent>({entityid});
|
||||||
}
|
}
|
||||||
wasMoving = true;
|
wasMoving = true;
|
||||||
}
|
} else if (!isMoving && wasMoving) {
|
||||||
else if (!isMoving && wasMoving)
|
|
||||||
{
|
|
||||||
if (auto event = sceneContext->getEventManager().lock()) {
|
if (auto event = sceneContext->getEventManager().lock()) {
|
||||||
event->notify<EntityStopEvent>({ entityid });
|
event->notify<EntityStopEvent>({entityid});
|
||||||
}
|
}
|
||||||
wasMoving = false;
|
wasMoving = false;
|
||||||
}
|
}
|
||||||
isMoving = false;
|
isMoving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameActor::draw()
|
void GameActor::draw() {
|
||||||
{
|
|
||||||
Entity::draw();
|
Entity::draw();
|
||||||
|
for (const auto &component : components) {
|
||||||
// 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->bind();
|
||||||
component->render();
|
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::moveUp() {
|
||||||
void GameActor::moveDown() { if (physics) physics->rigidBody.applyForce(glm::vec3( 0.f, 1.f, 0.f), 1500.25f); isMoving = true; }
|
if (physics)
|
||||||
void GameActor::moveLeft() { if (physics) physics->rigidBody.applyForce(glm::vec3(-1.f, 0.f, 0.f), 1500.25f); isMoving = true; }
|
physics->rigidBody.applyForce(glm::vec3(0.f, -1.f, 0.f), 1500.25f);
|
||||||
void GameActor::moveRight(){ if (physics) physics->rigidBody.applyForce(glm::vec3( 1.f, 0.f, 0.f), 1500.25f); isMoving = true; }
|
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
|
// top-down shooter mode controls
|
||||||
void GameActor::fireWeapon()const {
|
void GameActor::fireWeapon() const {
|
||||||
if (auto weapon = getHeldWeapon()) {
|
if (auto weapon = getHeldWeapon()) {
|
||||||
if (weapon->shoot()) {
|
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 (sceneContext->getPlayerID() == entityid) {
|
||||||
if (auto gEvent = sceneContext->getGlobalEventManager().lock()) {
|
if (auto gEvent = sceneContext->getGlobalEventManager().lock()) {
|
||||||
gEvent->notify<ScreenShakeEvent>({0.01f, 0.8f});
|
gEvent->notify<ScreenShakeEvent>({0.01f, 0.8f});
|
||||||
|
|
@ -123,33 +135,46 @@ void GameActor::cycleUpWeapons() {
|
||||||
void GameActor::cycleDownWeapons() {
|
void GameActor::cycleDownWeapons() {
|
||||||
if (!weapons.empty()) {
|
if (!weapons.empty()) {
|
||||||
weapons[currentWeaponIndex]->putaway();
|
weapons[currentWeaponIndex]->putaway();
|
||||||
currentWeaponIndex = (currentWeaponIndex + weapons.size() - 1) % weapons.size();
|
currentWeaponIndex =
|
||||||
|
(currentWeaponIndex + weapons.size() - 1) % weapons.size();
|
||||||
weapons[currentWeaponIndex]->wield();
|
weapons[currentWeaponIndex]->wield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void GameActor::cycleWeapons(const MouseState& mouse_state)
|
void GameActor::cycleWeapons(const MouseState &mouse_state) {
|
||||||
{
|
|
||||||
if (mouse_state.scroll < 0)
|
if (mouse_state.scroll < 0)
|
||||||
cycleUpWeapons();
|
cycleUpWeapons();
|
||||||
else if (mouse_state.scroll > 0)
|
else if (mouse_state.scroll > 0)
|
||||||
cycleDownWeapons();
|
cycleDownWeapons();
|
||||||
}
|
}
|
||||||
void GameActor::followMouse(const MouseState& mouse_state)
|
void GameActor::followMouse(const MouseState &mouse_state) {
|
||||||
{
|
glm::vec2 direction = glm::vec2(mouse_state.x, mouse_state.y) -
|
||||||
glm::vec2 direction = glm::vec2(mouse_state.x, mouse_state.y) - glm::vec2(localPosition.x, localPosition.y);
|
glm::vec2(localPosition.x, localPosition.y);
|
||||||
float newRotation = glm::degrees(glm::atan(direction.y, direction.x));
|
float newRotation = glm::degrees(glm::atan(direction.y, direction.x));
|
||||||
if (getDirectionFromRotation(rotation) != getDirectionFromRotation(newRotation)) {
|
if (getDirectionFromRotation(rotation) !=
|
||||||
|
getDirectionFromRotation(newRotation)) {
|
||||||
if (auto event = sceneContext->getEventManager().lock()) {
|
if (auto event = sceneContext->getEventManager().lock()) {
|
||||||
event->notify<DirectionChangeEvent>({ entityid, getDirectionFromRotation(newRotation) });
|
event->notify<DirectionChangeEvent>(
|
||||||
|
{entityid, getDirectionFromRotation(newRotation)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//setRotation(glm::degrees(glm::atan(direction.y, direction.x)));
|
// setRotation(glm::degrees(glm::atan(direction.y, direction.x)));
|
||||||
this->rotation = newRotation;
|
this->rotation = newRotation;
|
||||||
}
|
}
|
||||||
void GameActor::strafeLeft() { position.x += sin(glm::radians(rotation)) * speed; position.y -= cos(glm::radians(rotation)) * speed; }
|
void GameActor::strafeLeft() {
|
||||||
void GameActor::strafeRight() { position.x -= sin(glm::radians(rotation)) * speed; position.y += cos(glm::radians(rotation)) * speed; }
|
position.x += sin(glm::radians(rotation)) * speed;
|
||||||
void GameActor::moveBackward() { position.x -= cos(glm::radians(rotation)) * speed; position.y -= sin(glm::radians(rotation)) * speed; }
|
position.y -= cos(glm::radians(rotation)) * speed;
|
||||||
void GameActor::moveForward() {
|
}
|
||||||
|
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) {
|
if (physics) {
|
||||||
physics->rigidBody.velocity.x += cos(glm::radians(rotation)) * speed;
|
physics->rigidBody.velocity.x += cos(glm::radians(rotation)) * speed;
|
||||||
physics->rigidBody.velocity.y += sin(glm::radians(rotation)) * speed;
|
physics->rigidBody.velocity.y += sin(glm::radians(rotation)) * speed;
|
||||||
|
|
|
||||||
|
|
@ -3,31 +3,28 @@
|
||||||
|
|
||||||
#include <SDL_timer.h>
|
#include <SDL_timer.h>
|
||||||
|
|
||||||
void InputHandler::handleInput()
|
void InputHandler::handleInput() {
|
||||||
{
|
// If our input handler is not attached to an actor we return.
|
||||||
if (!actor) return;
|
// This will be due for change given we will need to handle input during menus
|
||||||
|
if (!actor)
|
||||||
|
return;
|
||||||
Uint32 currentTime = SDL_GetTicks();
|
Uint32 currentTime = SDL_GetTicks();
|
||||||
// check for bound keys that were pressed,
|
// check for bound keys that were pressed,
|
||||||
// next check if the hasn't been executed within the amount specified in delay
|
// next check if the hasn't been executed within the amount specified in delay
|
||||||
// if not execute the command and set lastExecution to currentTime
|
// if not execute the command and set lastExecution to currentTime
|
||||||
for (auto& [key, command] : keyCommands)
|
for (auto &[key, command] : keyCommands) {
|
||||||
{
|
if (keys[key] == true) {
|
||||||
if (keys[key] == true)
|
if (currentTime - command.lastExecution >= command.delay) {
|
||||||
{
|
|
||||||
if (currentTime - command.lastExecution >= command.delay)
|
|
||||||
{
|
|
||||||
commandQueue.push_back(command.cmd.get());
|
commandQueue.push_back(command.cmd.get());
|
||||||
command.lastExecution = currentTime;
|
command.lastExecution = currentTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Same with the mouse, for this context we'll be checking for motion events and for click events
|
// Same with the mouse, for this context we'll be checking for motion events
|
||||||
for (auto& [button, command] : mouseCommands)
|
// and for click events
|
||||||
{
|
for (auto &[button, command] : mouseCommands) {
|
||||||
if (mouseButtons[button] == true)
|
if (mouseButtons[button] == true) {
|
||||||
{
|
if (currentTime - command.lastExecution >= command.delay) {
|
||||||
if (currentTime - command.lastExecution >= command.delay)
|
|
||||||
{
|
|
||||||
mouseQueue.push_back(command.cmd.get());
|
mouseQueue.push_back(command.cmd.get());
|
||||||
command.lastExecution = currentTime;
|
command.lastExecution = currentTime;
|
||||||
}
|
}
|
||||||
|
|
@ -37,22 +34,20 @@ void InputHandler::handleInput()
|
||||||
mouseMotionCommand->execute(*actor, mouse_state);
|
mouseMotionCommand->execute(*actor, mouse_state);
|
||||||
if (mouseScrollCommand)
|
if (mouseScrollCommand)
|
||||||
mouseScrollCommand->execute(*actor, mouse_state);
|
mouseScrollCommand->execute(*actor, mouse_state);
|
||||||
mouse_state.scroll = 0.0f; // clear mouse scroll since we have handled the event.
|
mouse_state.scroll =
|
||||||
|
0.0f; // clear mouse scroll since we have handled the event.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes every captured command during the frame
|
// Executes every captured command during the frame
|
||||||
void InputHandler::executeCommands()
|
void InputHandler::executeCommands() {
|
||||||
{
|
for (auto &command : commandQueue) {
|
||||||
for (auto& command : commandQueue) {
|
|
||||||
command->execute(*actor);
|
command->execute(*actor);
|
||||||
}
|
}
|
||||||
for (auto& mouse : mouseQueue) {
|
for (auto &mouse : mouseQueue) {
|
||||||
mouse->execute(*actor, mouse_state);
|
mouse->execute(*actor, mouse_state);
|
||||||
}
|
}
|
||||||
commandQueue.clear();
|
commandQueue.clear();
|
||||||
mouseQueue.clear();
|
mouseQueue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputHandler::~InputHandler()
|
InputHandler::~InputHandler() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,93 +1,99 @@
|
||||||
#include "gameplay/map.h"
|
#include "gameplay/map.h"
|
||||||
#include "gameplay/camera.h"
|
|
||||||
#include "graphics/shader.h"
|
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
#include "utility/xmlloader.h"
|
|
||||||
#include "utility/resourcemanager.h"
|
|
||||||
#include "utility/logger.h"
|
#include "utility/logger.h"
|
||||||
|
#include "utility/resourcemanager.h"
|
||||||
|
#include "utility/xmlloader.h"
|
||||||
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
Map::Map(const MapData* mapData, const unsigned shaderID, std::shared_ptr<ResourceManager> resourceManager) :
|
Map::Map(const MapData *mapData, const unsigned shaderID,
|
||||||
mapData(mapData),
|
std::shared_ptr<ResourceManager> resourceManager)
|
||||||
tileIds(mapData->tiles)
|
: mapData(mapData), tileIds(mapData->tiles) {
|
||||||
{
|
|
||||||
this->shaderID = shaderID;
|
this->shaderID = shaderID;
|
||||||
|
|
||||||
for (auto& tileSet : mapData->tileSets)
|
// Tiles are held on layers, drawn back to front
|
||||||
|
for (auto &tileSet : mapData->tileSets)
|
||||||
tileSetData.push_back(resourceManager->loadTileSet(tileSet.path));
|
tileSetData.push_back(resourceManager->loadTileSet(tileSet.path));
|
||||||
|
|
||||||
if (!tileSetData.empty())
|
if (!tileSetData.empty()) {
|
||||||
{
|
// Storing all of the tilesets we will need to load and sending it to our
|
||||||
std::vector<const char*> buffer;
|
// texture instance handle
|
||||||
for (int layer = 0; layer < tileIds.size(); layer++)
|
std::vector<const char *> buffer;
|
||||||
{
|
for (int layer = 0; layer < tileIds.size(); layer++) {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
for (auto& set : tileSetData)
|
for (auto &set : tileSetData)
|
||||||
buffer.push_back(set->file.c_str());
|
buffer.push_back(set->file.c_str());
|
||||||
if (!buffer.empty())
|
if (!buffer.empty())
|
||||||
instanceHandles.push_back(std::make_shared<TileTextureInstance>(buffer));
|
instanceHandles.push_back(
|
||||||
|
std::make_shared<TileTextureInstance>(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMap();
|
loadMap();
|
||||||
createCollisionMap();
|
createCollisionMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#include <glm/ext.hpp>
|
|
||||||
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<int>(getTileSetIndex(tileIds[layer][y][x]));
|
void Map::loadMap() {
|
||||||
glm::vec2 originalSize = (textureIndex != -1) ?
|
tileData.resize(tileIds.size());
|
||||||
glm::vec2(tileSetData[textureIndex]->width, tileSetData[textureIndex]->height) :
|
// Tiles are drawn back to front, we track the tileset the tile comes from and
|
||||||
glm::vec2(0.0f);
|
// additional information about the tilesets themselves so the shader can
|
||||||
int tilesPerRow = (textureIndex != -1) ? tileSetData[textureIndex]->columns : 0;
|
// properly draw the right tile. Each layer is its own instance
|
||||||
int startID = (textureIndex != -1) ? mapData->tileSets[textureIndex].startID : 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++) {
|
||||||
|
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<int>(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];
|
int tileIndex = tileIds[layer][y][x];
|
||||||
|
|
||||||
tileData[layer].push_back({modelMatrix, originalSize, tileIndex, textureIndex, tilesPerRow, startID});
|
tileData[layer].push_back({modelMatrix, originalSize, tileIndex,
|
||||||
|
textureIndex, tilesPerRow, startID});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instanceHandles[layer]->updateInstanceData(tileData[layer]);
|
instanceHandles[layer]->updateInstanceData(tileData[layer]);
|
||||||
}
|
}
|
||||||
glm::vec2 canvasSize = glm::vec2(instanceHandles[0]->getTextureArray()->getWidth(), instanceHandles[0]->getTextureArray()->getHeight());
|
// 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);
|
editUniformOnce("uCanvasSize", canvasSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::createCollisionMap()
|
// 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
|
// Match collisionMap to map size
|
||||||
collisionMap.resize(tileIds[0].size());
|
collisionMap.resize(tileIds[0].size());
|
||||||
for (int y = 0; y < tileIds[0].size(); ++y)
|
for (int y = 0; y < tileIds[0].size(); ++y) {
|
||||||
{
|
|
||||||
collisionMap[y].resize(tileIds[0][y].size(), 0);
|
collisionMap[y].resize(tileIds[0][y].size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int layer = 0; layer < tileIds.size(); layer++)
|
for (int layer = 0; layer < tileIds.size(); layer++) {
|
||||||
{
|
for (int y = 0; y < tileIds[layer].size(); y++) {
|
||||||
for (int y = 0; y < tileIds[layer].size(); y++)
|
for (int x = 0; x < tileIds[layer][y].size(); x++) {
|
||||||
{
|
|
||||||
for (int x = 0; x < tileIds[layer][y].size(); x++)
|
|
||||||
{
|
|
||||||
int id = tileIds[layer][y][x];
|
int id = tileIds[layer][y][x];
|
||||||
size_t tileSetIndex = getTileSetIndex(id);
|
size_t tileSetIndex = getTileSetIndex(id);
|
||||||
if (tileSetIndex == -1)
|
if (tileSetIndex == -1)
|
||||||
collisionMap[y][x] = 0;
|
collisionMap[y][x] = 0;
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
int startID = mapData->tileSets[tileSetIndex].startID;
|
int startID = mapData->tileSets[tileSetIndex].startID;
|
||||||
auto& tile = tileSetData[tileSetIndex]->tiles[id - startID];
|
auto &tile = tileSetData[tileSetIndex]->tiles[id - startID];
|
||||||
if (!tile->walkable)
|
if (!tile->walkable)
|
||||||
collisionMap[y][x] = 1;
|
collisionMap[y][x] = 1;
|
||||||
}
|
}
|
||||||
|
|
@ -96,28 +102,26 @@ void Map::createCollisionMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::draw()
|
// Draw each layer in it's own instance
|
||||||
{
|
void Map::draw() {
|
||||||
for (int layer = 0; layer < instanceHandles.size(); layer++)
|
for (int layer = 0; layer < instanceHandles.size(); layer++) {
|
||||||
{
|
|
||||||
instanceHandles[layer]->draw();
|
instanceHandles[layer]->draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Use this function to get the tileSetIndex from a tile ID.
|
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
|
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
|
returns tileSetIndex of the tile id passed. Unless the id is either 0 or
|
||||||
the returned tileSetIndex is out of bounds, returns -1
|
the returned tileSetIndex is out of bounds, returns -1
|
||||||
*/
|
*/
|
||||||
size_t Map::getTileSetIndex(int id) const
|
size_t Map::getTileSetIndex(int id) const {
|
||||||
{
|
|
||||||
// work from the bottom, break if ID > startID
|
// work from the bottom, break if ID > startID
|
||||||
// If we get a textureIndex of -1 then we are on an empty tile
|
// If we get a textureIndex of -1 then we are on an empty tile
|
||||||
size_t tileSetIndex = mapData->tileSets.size() - 1;
|
size_t tileSetIndex = mapData->tileSets.size() - 1;
|
||||||
for (; tileSetIndex != -1; --tileSetIndex)
|
for (; tileSetIndex != -1; --tileSetIndex) {
|
||||||
{
|
|
||||||
if (id >= mapData->tileSets[tileSetIndex].startID)
|
if (id >= mapData->tileSets[tileSetIndex].startID)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,26 @@
|
||||||
#include "gameplay/weapons/bullet.h"
|
#include "gameplay/weapons/bullet.h"
|
||||||
#include "utility/events.h"
|
#include "utility/events.h"
|
||||||
|
|
||||||
#include "utility/logger.h"
|
void PhysicsEngine::hookEventManager(
|
||||||
|
const std::shared_ptr<EventManager> &eventManager) {
|
||||||
void PhysicsEngine::hookEventManager(const std::shared_ptr<EventManager>& eventManager)
|
|
||||||
{
|
|
||||||
this->eventManager = eventManager;
|
this->eventManager = eventManager;
|
||||||
this->eventManager->subscribe<BulletFiredEvent>([this](const BulletFiredEvent& event) {
|
this->eventManager->subscribe<BulletFiredEvent>(
|
||||||
|
[this](const BulletFiredEvent &event) {
|
||||||
if (auto bullet = event.bullet.lock()) {
|
if (auto bullet = event.bullet.lock()) {
|
||||||
this->addObject(bullet->getPhysicsComponent());
|
this->addObject(bullet->getPhysicsComponent());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this->eventManager->subscribe<BulletDiedEvent>([this](const BulletDiedEvent& event) {
|
this->eventManager->subscribe<BulletDiedEvent>(
|
||||||
|
[this](const BulletDiedEvent &event) {
|
||||||
this->removeObject(event.physObj);
|
this->removeObject(event.physObj);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<PhysicsComponent> PhysicsEngine::createObject(const unsigned int ID,
|
std::shared_ptr<PhysicsComponent>
|
||||||
const glm::vec3& pos,
|
PhysicsEngine::createObject(const unsigned int ID, const glm::vec3 &pos,
|
||||||
float mass,
|
float mass, PhysicsComponent::Collider::Shape shape,
|
||||||
PhysicsComponent::Collider::Shape shape,
|
glm::vec3 dimensions, const glm::vec3 offset) {
|
||||||
glm::vec3 dimensions, const
|
auto component = std::make_shared<PhysicsComponent>();
|
||||||
glm::vec3 offset)
|
|
||||||
{
|
|
||||||
auto component = std::make_shared <PhysicsComponent>();
|
|
||||||
component->ID = ID;
|
component->ID = ID;
|
||||||
component->rigidBody.position = pos;
|
component->rigidBody.position = pos;
|
||||||
component->rigidBody.acceleration = glm::vec2(0.f);
|
component->rigidBody.acceleration = glm::vec2(0.f);
|
||||||
|
|
@ -37,50 +34,50 @@ std::shared_ptr<PhysicsComponent> PhysicsEngine::createObject(const unsigned int
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::loadCollisionMap(const std::vector<std::vector<int>>& collisionMap, float tileSize)
|
void PhysicsEngine::loadCollisionMap(
|
||||||
{
|
const std::vector<std::vector<int>> &collisionMap, float tileSize) {
|
||||||
this->collisionMap = collisionMap;
|
this->collisionMap = collisionMap;
|
||||||
this->tileSize = tileSize;
|
this->tileSize = tileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::addObject(const std::shared_ptr<PhysicsComponent>& component)
|
void PhysicsEngine::addObject(
|
||||||
{
|
const std::shared_ptr<PhysicsComponent> &component) {
|
||||||
if (component)
|
if (component)
|
||||||
objects.emplace_back(component);
|
objects.emplace_back(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::removeObject(const std::shared_ptr<PhysicsComponent>& component)
|
void PhysicsEngine::removeObject(
|
||||||
{
|
const std::shared_ptr<PhysicsComponent> &component) {
|
||||||
if (std::find(objects.begin(), objects.end(), component) != objects.end())
|
if (std::find(objects.begin(), objects.end(), component) != objects.end())
|
||||||
objects.erase(std::remove(objects.begin(), objects.end(), component));
|
objects.erase(std::remove(objects.begin(), objects.end(), component));
|
||||||
}
|
}
|
||||||
|
|
||||||
int PhysicsEngine::getTileCollider(const glm::vec2& position)
|
int PhysicsEngine::getTileCollider(const glm::vec2 &position) {
|
||||||
{
|
|
||||||
int x = static_cast<int>((position.x + 0.5f * tileSize) / tileSize);
|
int x = static_cast<int>((position.x + 0.5f * tileSize) / tileSize);
|
||||||
int y = static_cast<int>((position.y + 0.5f * tileSize) / tileSize);
|
int y = static_cast<int>((position.y + 0.5f * tileSize) / tileSize);
|
||||||
if (y >= 0 && y < collisionMap.size())
|
if (y >= 0 && y < collisionMap.size()) {
|
||||||
{
|
|
||||||
if (x >= 0 && x < collisionMap[y].size())
|
if (x >= 0 && x < collisionMap[y].size())
|
||||||
return collisionMap[y][x];
|
return collisionMap[y][x];
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::getPossibleCollisions()
|
void PhysicsEngine::getPossibleCollisions() {
|
||||||
{
|
|
||||||
objCollisions.clear();
|
objCollisions.clear();
|
||||||
for (size_t i = 0; i < objects.size(); ++i)
|
for (size_t i = 0; i < objects.size(); ++i) {
|
||||||
{
|
auto &obj = objects[i];
|
||||||
auto& obj = objects[i];
|
for (size_t j = i + 1; j < objects.size(); ++j) {
|
||||||
for (size_t j = i + 1; j < objects.size(); ++j)
|
auto &colliderObj = objects[j];
|
||||||
{
|
if (obj.get() == colliderObj.get() || obj->ID == colliderObj->ID)
|
||||||
auto& colliderObj = objects[j];
|
continue;
|
||||||
if (obj.get() == colliderObj.get() || obj->ID == colliderObj->ID) continue;
|
float colliderRight = colliderObj->rigidBody.position.x +
|
||||||
float colliderRight = colliderObj->rigidBody.position.x + colliderObj->collider.dimensions.x;
|
colliderObj->collider.dimensions.x;
|
||||||
float colliderBottom = colliderObj->rigidBody.position.y + colliderObj->collider.dimensions.y;
|
float colliderBottom = colliderObj->rigidBody.position.y +
|
||||||
float objectRight = obj->rigidBody.position.x + obj->collider.dimensions.x;
|
colliderObj->collider.dimensions.y;
|
||||||
float objectBottom = obj->rigidBody.position.y + obj->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 &&
|
if ((obj->rigidBody.position.x <= colliderRight &&
|
||||||
objectRight >= colliderObj->rigidBody.position.x) ||
|
objectRight >= colliderObj->rigidBody.position.x) ||
|
||||||
(obj->rigidBody.position.y <= colliderBottom &&
|
(obj->rigidBody.position.y <= colliderBottom &&
|
||||||
|
|
@ -90,50 +87,60 @@ void PhysicsEngine::getPossibleCollisions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::resolvePossibleCollisions()
|
void PhysicsEngine::resolvePossibleCollisions() {
|
||||||
{
|
for (auto &objs : objCollisions) {
|
||||||
for (auto& objs : objCollisions)
|
// Solve for two circles, we'll need to expand upon this for different
|
||||||
{
|
// colliders...
|
||||||
// Solve for two circles, we'll need to expand upon this for different colliders...
|
float sumOfRadius =
|
||||||
float sumOfRadius = objs.first->collider.dimensions.x + objs.second->collider.dimensions.x;
|
objs.first->collider.dimensions.x + objs.second->collider.dimensions.x;
|
||||||
glm::vec2 objFirstCenter = objs.first->rigidBody.position + objs.first->collider.offset;
|
glm::vec2 objFirstCenter =
|
||||||
glm::vec2 objSecondCenter = objs.second->rigidBody.position + objs.second->collider.offset;
|
objs.first->rigidBody.position + objs.first->collider.offset;
|
||||||
|
glm::vec2 objSecondCenter =
|
||||||
|
objs.second->rigidBody.position + objs.second->collider.offset;
|
||||||
glm::vec2 distance = objFirstCenter - objSecondCenter;
|
glm::vec2 distance = objFirstCenter - objSecondCenter;
|
||||||
if (glm::length(distance) < sumOfRadius)
|
if (glm::length(distance) < sumOfRadius) {
|
||||||
{
|
|
||||||
// We got impact!
|
// We got impact!
|
||||||
glm::vec2 normal = distance / glm::length(distance);
|
glm::vec2 normal = distance / glm::length(distance);
|
||||||
// That impact is a bullet hitting a gameactor!
|
// That impact is a bullet hitting a gameactor!
|
||||||
if ((objs.first->isBullet || objs.second->isBullet) && !(objs.first->isBullet && objs.second->isBullet))
|
if ((objs.first->isBullet || objs.second->isBullet) &&
|
||||||
{
|
!(objs.first->isBullet && objs.second->isBullet)) {
|
||||||
eventManager->notify(std::make_shared<BulletCollideEvent>(
|
eventManager->notify(std::make_shared<BulletCollideEvent>(
|
||||||
( objs.first->isBullet) ? objs.first->ID : objs.second->ID,
|
(objs.first->isBullet) ? objs.first->ID : objs.second->ID,
|
||||||
(!objs.first->isBullet) ? objs.first->ID : objs.second->ID,
|
(!objs.first->isBullet) ? objs.first->ID : objs.second->ID,
|
||||||
std::make_shared<PhysicsComponent>(( objs.first->isBullet) ? objs.first : objs.second),
|
std::make_shared<PhysicsComponent>(
|
||||||
normal
|
(objs.first->isBullet) ? objs.first : objs.second),
|
||||||
));
|
normal));
|
||||||
}
|
}
|
||||||
// Apply impulse force
|
// Apply impulse force
|
||||||
float penetrationDepth = sumOfRadius - glm::length(distance);
|
float penetrationDepth = sumOfRadius - glm::length(distance);
|
||||||
glm::vec2 correctionVector = normal * (penetrationDepth / ((1 / objs.first->rigidBody.mass) + (1 / objs.second->rigidBody.mass)));
|
glm::vec2 correctionVector =
|
||||||
glm::vec2 vrel = objs.first->rigidBody.velocity - objs.second->rigidBody.velocity;
|
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
|
// smallest elasticity of the two colliders
|
||||||
float e = std::min(objs.first->rigidBody.elasticity, objs.second->rigidBody.elasticity);
|
float e = std::min(objs.first->rigidBody.elasticity,
|
||||||
float impulseMag = (-(1 + e) * glm::dot(vrel, normal)) / ((1 / objs.first->rigidBody.mass) + (1 / objs.second->rigidBody.mass));
|
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.first->rigidBody.position +=
|
||||||
objs.second->rigidBody.position -= (correctionVector / objs.second->rigidBody.mass);
|
(correctionVector / objs.first->rigidBody.mass);
|
||||||
objs.first->rigidBody.velocity += impulseMag * normal / objs.first->rigidBody.mass;
|
objs.second->rigidBody.position -=
|
||||||
objs.second->rigidBody.velocity -= impulseMag * normal / objs.second->rigidBody.mass;
|
(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<PhysicsComponent>& obj)
|
void PhysicsEngine::resolveWorldCollision(
|
||||||
{
|
const std::shared_ptr<PhysicsComponent> &obj) {
|
||||||
switch (obj->collider.shape)
|
switch (obj->collider.shape) {
|
||||||
{
|
|
||||||
case PhysicsComponent::Collider::Shape::Circle:
|
case PhysicsComponent::Collider::Shape::Circle:
|
||||||
float radius = obj->collider.dimensions.x;
|
float radius = obj->collider.dimensions.x;
|
||||||
glm::vec2 position = obj->rigidBody.position + obj->collider.offset;
|
glm::vec2 position = obj->rigidBody.position + obj->collider.offset;
|
||||||
|
|
@ -141,47 +148,42 @@ void PhysicsEngine::resolveWorldCollision(const std::shared_ptr<PhysicsComponent
|
||||||
int bottomTile = getTileCollider(position + glm::vec2(0, radius));
|
int bottomTile = getTileCollider(position + glm::vec2(0, radius));
|
||||||
int leftTile = getTileCollider(position - glm::vec2(radius, 0));
|
int leftTile = getTileCollider(position - glm::vec2(radius, 0));
|
||||||
int rightTile = getTileCollider(position + glm::vec2(radius, 0));
|
int rightTile = getTileCollider(position + glm::vec2(radius, 0));
|
||||||
if (obj->isBullet)
|
if (obj->isBullet) {
|
||||||
{
|
if (topTile || bottomTile || leftTile || rightTile) {
|
||||||
if (topTile || bottomTile || leftTile || rightTile)
|
|
||||||
{
|
|
||||||
eventManager->notify(std::make_shared<BulletDiedEvent>(obj));
|
eventManager->notify(std::make_shared<BulletDiedEvent>(obj));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int tileY = static_cast<int>((position.y) / tileSize);
|
int tileY = static_cast<int>((position.y) / tileSize);
|
||||||
int tileX = static_cast<int>((position.x) / tileSize);
|
int tileX = static_cast<int>((position.x) / tileSize);
|
||||||
if (topTile)
|
if (topTile) {
|
||||||
{
|
// obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y;
|
||||||
//obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y;
|
obj->rigidBody.position.y =
|
||||||
obj->rigidBody.position.y = (tileY+1) * tileSize + obj->collider.offset.y;
|
(tileY + 1) * tileSize + obj->collider.offset.y;
|
||||||
}
|
}
|
||||||
if (bottomTile)
|
if (bottomTile) {
|
||||||
{
|
// obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y;
|
||||||
//obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y;
|
obj->rigidBody.position.y = (tileY)*tileSize - obj->collider.offset.y;
|
||||||
obj->rigidBody.position.y = (tileY) * tileSize - obj->collider.offset.y;
|
|
||||||
}
|
}
|
||||||
if (leftTile)
|
if (leftTile) {
|
||||||
{
|
// obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x;
|
||||||
//obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x;
|
obj->rigidBody.position.x =
|
||||||
obj->rigidBody.position.x = (tileX + 1) * tileSize + obj->collider.offset.x;
|
(tileX + 1) * tileSize + obj->collider.offset.x;
|
||||||
}
|
}
|
||||||
if (rightTile)
|
if (rightTile) {
|
||||||
{
|
// obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x;
|
||||||
//obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x;
|
obj->rigidBody.position.x = (tileX)*tileSize - obj->collider.offset.x;
|
||||||
obj->rigidBody.position.x = (tileX) * tileSize - obj->collider.offset.x;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::update(double deltaTime)
|
void PhysicsEngine::update(double deltaTime) {
|
||||||
{
|
for (auto &obj : objects) {
|
||||||
for (auto& obj : objects)
|
if (!obj)
|
||||||
{
|
continue;
|
||||||
if (!obj) continue;
|
|
||||||
glm::vec2 frictionForce = obj->rigidBody.velocity * -0.1f;
|
glm::vec2 frictionForce = obj->rigidBody.velocity * -0.1f;
|
||||||
if (std::abs(obj->rigidBody.acceleration.x) == std::abs(obj->rigidBody.acceleration.y))
|
if (std::abs(obj->rigidBody.acceleration.x) ==
|
||||||
{
|
std::abs(obj->rigidBody.acceleration.y)) {
|
||||||
obj->rigidBody.acceleration.x *= 0.75f;
|
obj->rigidBody.acceleration.x *= 0.75f;
|
||||||
obj->rigidBody.acceleration.y *= 0.75f;
|
obj->rigidBody.acceleration.y *= 0.75f;
|
||||||
}
|
}
|
||||||
|
|
@ -191,19 +193,20 @@ void PhysicsEngine::update(double deltaTime)
|
||||||
|
|
||||||
float maxSpeed = 500.f;
|
float maxSpeed = 500.f;
|
||||||
float curSpeed = glm::length(obj->rigidBody.velocity);
|
float curSpeed = glm::length(obj->rigidBody.velocity);
|
||||||
if (curSpeed > maxSpeed)
|
if (curSpeed > maxSpeed) {
|
||||||
{
|
|
||||||
// Move at maxspeed
|
// Move at maxspeed
|
||||||
obj->rigidBody.velocity = glm::normalize(obj->rigidBody.velocity) * maxSpeed;
|
obj->rigidBody.velocity =
|
||||||
|
glm::normalize(obj->rigidBody.velocity) * maxSpeed;
|
||||||
}
|
}
|
||||||
obj->rigidBody.acceleration = glm::vec2(0.f);
|
obj->rigidBody.acceleration = glm::vec2(0.f);
|
||||||
if (obj->collider.dimensions != glm::vec2(0.f))
|
if (obj->collider.dimensions != glm::vec2(0.f)) {
|
||||||
{
|
|
||||||
// check map collisions
|
// check map collisions
|
||||||
resolveWorldCollision(obj);
|
resolveWorldCollision(obj);
|
||||||
}
|
}
|
||||||
obj->rigidBody.position += obj->rigidBody.velocity * static_cast<float>(deltaTime);
|
obj->rigidBody.position +=
|
||||||
// Make sure we keep our Z at 0.f, a better choice would be to remove the need for vec3 all together!
|
obj->rigidBody.velocity * static_cast<float>(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!
|
// TODO: REMOVE VEC3 NO NEED FOR Z COODINATE!
|
||||||
// obj->rigidBody.position.z = 0.f;
|
// obj->rigidBody.position.z = 0.f;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,54 @@
|
||||||
#include "gameplay/scene.h"
|
#include "gameplay/scene.h"
|
||||||
#include "gameplay/camera.h"
|
#include "gameplay/ai.h"
|
||||||
#include "gameplay/gameactor.h"
|
#include "gameplay/gameactor.h"
|
||||||
#include "gameplay/weapons/weapons.h"
|
|
||||||
#include "gameplay/weapons/bulletmanager.h"
|
|
||||||
#include "gameplay/map.h"
|
#include "gameplay/map.h"
|
||||||
#include "gameplay/physics.h"
|
#include "gameplay/physics.h"
|
||||||
#include "gameplay/ai.h"
|
#include "gameplay/weapons/bulletmanager.h"
|
||||||
|
#include "gameplay/weapons/weapons.h"
|
||||||
|
|
||||||
#include "graphics/sprite.h"
|
|
||||||
#include "graphics/animation.h"
|
#include "graphics/animation.h"
|
||||||
#include "graphics/background.h"
|
#include "graphics/background.h"
|
||||||
|
#include "graphics/sprite.h"
|
||||||
|
|
||||||
#include "utility/script.h"
|
|
||||||
#include "utility/component.h"
|
#include "utility/component.h"
|
||||||
#include "utility/ftfont.h"
|
|
||||||
#include "utility/xmlloader.h"
|
|
||||||
#include "utility/resourcemanager.h"
|
|
||||||
#include "utility/events.h"
|
|
||||||
#include "utility/raycaster.h"
|
|
||||||
#include "utility/debugdraw.h"
|
#include "utility/debugdraw.h"
|
||||||
|
#include "utility/events.h"
|
||||||
|
#include "utility/ftfont.h"
|
||||||
|
#include "utility/raycaster.h"
|
||||||
|
#include "utility/resourcemanager.h"
|
||||||
|
#include "utility/script.h"
|
||||||
|
#include "utility/xmlloader.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <execution>
|
Scene::Scene(SceneType sceneType, std::shared_ptr<ResourceManager> resources,
|
||||||
|
std::weak_ptr<EventManager> globalEvents)
|
||||||
// Scene xml files, should contain a node called <player> that holds the sprite location
|
: type(sceneType), resourceManager(resources),
|
||||||
/*
|
globalEventManager(globalEvents) {
|
||||||
like this:
|
|
||||||
<player sprite="sprites/player2Atlas.png" frameSize=64.0>
|
|
||||||
<x=5/>
|
|
||||||
<y=6/>
|
|
||||||
</player>
|
|
||||||
*/
|
|
||||||
|
|
||||||
Scene::Scene(SceneType sceneType, std::shared_ptr<ResourceManager> resources, std::weak_ptr<EventManager> globalEvents)
|
|
||||||
: type(sceneType), resourceManager(resources), globalEventManager(globalEvents)
|
|
||||||
{
|
|
||||||
camera = std::make_shared<Camera>(800.f, 600.f);
|
|
||||||
physicsEngine = std::make_shared<PhysicsEngine>();
|
physicsEngine = std::make_shared<PhysicsEngine>();
|
||||||
eventManager = std::make_shared<EventManager>();
|
eventManager = std::make_shared<EventManager>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::init()
|
void Scene::init() {
|
||||||
{
|
|
||||||
physicsEngine->hookEventManager(eventManager);
|
physicsEngine->hookEventManager(eventManager);
|
||||||
//if (sceneType == SCENE_SHOOTER)
|
|
||||||
loadDebugShooterScene();
|
loadDebugShooterScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is full of hardcoded values and test sprites, NOT for use with final product
|
// This function is full of hardcoded values and test sprites, NOT for use with
|
||||||
void Scene::loadDebugShooterScene()
|
// final product
|
||||||
{
|
void Scene::loadDebugShooterScene() {
|
||||||
hookSceneEvents();
|
hookSceneEvents();
|
||||||
sceneData = resourceManager->loadScene("000");
|
sceneData = resourceManager->loadScene("000");
|
||||||
if (!sceneData)
|
if (!sceneData)
|
||||||
return;
|
return;
|
||||||
EntityData playerData = sceneData->entities[0];
|
EntityData playerData = sceneData->entities[0];
|
||||||
auto mapData = sceneData->map;
|
auto mapData = sceneData->map;
|
||||||
auto playerShader = resourceManager->loadShader("GL_player", "shaders/GL_player.vert", "shaders/GL_player.frag");
|
auto playerShader = resourceManager->loadShader(
|
||||||
auto bubbleShader = resourceManager->loadShader("GL_bubble", "shaders/GL_bubble.vert", "shaders/GL_bubble.frag");
|
"GL_player", "shaders/GL_player.vert", "shaders/GL_player.frag");
|
||||||
auto weaponShader = resourceManager->loadShader("GL_pistol", "shaders/GL_pistol.vert", "shaders/GL_pistol.frag");
|
auto bubbleShader = resourceManager->loadShader(
|
||||||
|
"GL_bubble", "shaders/GL_bubble.vert", "shaders/GL_bubble.frag");
|
||||||
|
auto weaponShader = resourceManager->loadShader(
|
||||||
|
"GL_pistol", "shaders/GL_pistol.vert", "shaders/GL_pistol.frag");
|
||||||
|
|
||||||
if (!sceneData->bgFile.empty()) {
|
if (!sceneData->bgFile.empty()) {
|
||||||
LOG(INFO, "Found background loading '{}'", sceneData->bgFile);
|
LOG(INFO, "Found background loading '{}'", sceneData->bgFile);
|
||||||
|
|
@ -67,57 +56,54 @@ void Scene::loadDebugShooterScene()
|
||||||
}
|
}
|
||||||
|
|
||||||
// creating map from scene
|
// creating map from scene
|
||||||
auto tileShader = resourceManager->loadShader("GL_tile", "shaders/GL_tile.vert", "shaders/GL_tile.frag");
|
auto tileShader = resourceManager->loadShader(
|
||||||
|
"GL_tile", "shaders/GL_tile.vert", "shaders/GL_tile.frag");
|
||||||
map = std::make_shared<Map>(mapData, tileShader, resourceManager);
|
map = std::make_shared<Map>(mapData, tileShader, resourceManager);
|
||||||
|
|
||||||
for (EntityData entityData : sceneData->entities)
|
for (EntityData entityData : sceneData->entities) {
|
||||||
{
|
|
||||||
auto entity = std::make_shared<GameActor>(this, playerShader);
|
auto entity = std::make_shared<GameActor>(this, playerShader);
|
||||||
// Directional is the kind of sprite sheet we are using, in this case for directional, I have the sprite sheet handle the rotations
|
// Directional is the kind of sprite sheet we are using, in this case for
|
||||||
// instead of just rotating the object, this makes it look quite a bit better from the end user perspective.
|
// directional, I have the sprite sheet handle the rotations instead of just
|
||||||
if (entityData.animated)
|
// rotating the object, this makes it look quite a bit better from the end
|
||||||
{
|
// user perspective.
|
||||||
auto entityAnimation = resourceManager->loadAnimationSet(entityData.graphic, entity->getEntityID());
|
if (entityData.animated) {
|
||||||
// because we don't want to have the engine rotate the object based on the entities rotation,
|
auto entityAnimation = resourceManager->loadAnimationSet(
|
||||||
// we set the this value to false so we no longer rotate the object.
|
entityData.graphic, entity->getEntityID());
|
||||||
|
// because we don't want to have the engine rotate the object based on the
|
||||||
|
// entities rotation, we set the this value to false so we no longer
|
||||||
|
// rotate the object.
|
||||||
if (entityAnimation->getDirectional())
|
if (entityAnimation->getDirectional())
|
||||||
entity->setRotatable(false);
|
entity->setRotatable(false);
|
||||||
entity->addComponent(std::make_unique<AnimationComponent>(entityAnimation, eventManager));
|
entity->addComponent(
|
||||||
}
|
std::make_unique<AnimationComponent>(entityAnimation, eventManager));
|
||||||
else
|
} else {
|
||||||
{
|
|
||||||
auto entitySprite = resourceManager->loadSpriteStatic(entityData.graphic);
|
auto entitySprite = resourceManager->loadSpriteStatic(entityData.graphic);
|
||||||
entity->addComponent(std::make_unique<SpriteComponent>(entitySprite));
|
entity->addComponent(std::make_unique<SpriteComponent>(entitySprite));
|
||||||
}
|
}
|
||||||
auto defaultWeapon = resourceManager->loadWeapon("gun/pistol", weaponShader, bubbleShader);
|
auto defaultWeapon =
|
||||||
auto entityWeapon = resourceManager->loadWeapon(entityData.weapon, weaponShader, bubbleShader);
|
resourceManager->loadWeapon("gun/pistol", weaponShader, bubbleShader);
|
||||||
|
auto entityWeapon = resourceManager->loadWeapon(entityData.weapon,
|
||||||
|
weaponShader, bubbleShader);
|
||||||
|
|
||||||
entity->pickupWeapon(std::move(defaultWeapon));
|
entity->pickupWeapon(std::move(defaultWeapon));
|
||||||
entity->pickupWeapon(std::move(entityWeapon));
|
entity->pickupWeapon(std::move(entityWeapon));
|
||||||
entity->setPosition(glm::vec3(entityData.x * mapData->tileSize, entityData.y * mapData->tileSize, 0.f));
|
entity->setPosition(glm::vec3(entityData.x * mapData->tileSize,
|
||||||
|
entityData.y * mapData->tileSize, 0.f));
|
||||||
entity->setScale(glm::vec3(mapData->tileSize, mapData->tileSize, 1.f));
|
entity->setScale(glm::vec3(mapData->tileSize, mapData->tileSize, 1.f));
|
||||||
|
|
||||||
entity->addPhysicsComponent(
|
entity->addPhysicsComponent(physicsEngine->createObject(
|
||||||
physicsEngine->createObject(entity->getEntityID(),
|
entity->getEntityID(), entity->getPosition(), 49.0,
|
||||||
entity->getPosition(),
|
|
||||||
49.0,
|
|
||||||
PhysicsComponent::Collider::Shape::Circle,
|
PhysicsComponent::Collider::Shape::Circle,
|
||||||
glm::vec3(mapData->tileSize / 2))
|
glm::vec3(mapData->tileSize / 2)));
|
||||||
);
|
|
||||||
|
|
||||||
if (entityData.isPlayer)
|
if (entityData.isPlayer) {
|
||||||
{
|
|
||||||
player = entity;
|
player = entity;
|
||||||
camera->setTarget(entity.get());
|
} else {
|
||||||
entity->setLocalPosition(camera->worldToLocal(entity->getPosition()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// attach ai
|
// attach ai
|
||||||
if (!entityData.script.empty())
|
if (!entityData.script.empty()) {
|
||||||
{
|
|
||||||
auto behaviour = resourceManager->loadAIScript(entityData.script);
|
auto behaviour = resourceManager->loadAIScript(entityData.script);
|
||||||
auto rayCaster = std::make_unique<Raycaster>(40.f, 300.f, map->getCollisionMap(), mapData->tileSize);
|
auto rayCaster = std::make_unique<Raycaster>(
|
||||||
|
40.f, 300.f, map->getCollisionMap(), mapData->tileSize);
|
||||||
auto ai = std::make_shared<AI>(entity.get(), std::move(rayCaster));
|
auto ai = std::make_shared<AI>(entity.get(), std::move(rayCaster));
|
||||||
ai->setTarget(player.get());
|
ai->setTarget(player.get());
|
||||||
ai->attachBehaviourScript(std::move(behaviour));
|
ai->attachBehaviourScript(std::move(behaviour));
|
||||||
|
|
@ -129,46 +115,34 @@ void Scene::loadDebugShooterScene()
|
||||||
}
|
}
|
||||||
|
|
||||||
physicsEngine->loadCollisionMap(map->getCollisionMap(), mapData->tileSize);
|
physicsEngine->loadCollisionMap(map->getCollisionMap(), mapData->tileSize);
|
||||||
|
|
||||||
// Setup map and other entities...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<GameActor> Scene::getPlayer() const
|
std::shared_ptr<GameActor> Scene::getPlayer() const {
|
||||||
{
|
|
||||||
return (!player) ? nullptr : player;
|
return (!player) ? nullptr : player;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::update(double deltaTime)
|
void Scene::update(double deltaTime) {
|
||||||
{
|
|
||||||
|
|
||||||
for (const auto& [id, e] : entities)
|
for (const auto &[id, e] : entities) {
|
||||||
{
|
|
||||||
e->update(deltaTime);
|
e->update(deltaTime);
|
||||||
if (camera->getTarget() == e.get())
|
|
||||||
e->setLocalPosition(camera->worldToLocal(e->getPosition()));
|
|
||||||
}
|
}
|
||||||
physicsEngine->update(deltaTime);
|
physicsEngine->update(deltaTime);
|
||||||
camera->update(deltaTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::render(std::shared_ptr<Renderer> renderer)
|
void Scene::render(std::shared_ptr<Renderer> renderer) {
|
||||||
{
|
|
||||||
renderer->clear();
|
renderer->clear();
|
||||||
|
|
||||||
renderer->setProjAndViewMatrix(camera->getProjectionMatrix(), camera->getViewMatrix());
|
|
||||||
renderer->addDrawable(RenderLayer::Map, map.get());
|
renderer->addDrawable(RenderLayer::Map, map.get());
|
||||||
if (background) {
|
if (background) {
|
||||||
renderer->addDrawable(RenderLayer::Background, static_cast<Drawable*>(background));
|
renderer->addDrawable(RenderLayer::Background,
|
||||||
|
static_cast<Drawable *>(background));
|
||||||
}
|
}
|
||||||
//map->draw();
|
for (auto &[id, e] : entities) {
|
||||||
for (auto& [id, e] : entities)
|
|
||||||
{
|
|
||||||
//e->draw();
|
|
||||||
renderer->addDrawable(RenderLayer::GameObjects, e.get());
|
renderer->addDrawable(RenderLayer::GameObjects, e.get());
|
||||||
if (e->getHeldWeapon()) {
|
if (e->getHeldWeapon()) {
|
||||||
renderer->addDrawable(RenderLayer::GameObjects, e->getHeldWeapon());
|
renderer->addDrawable(RenderLayer::GameObjects, e->getHeldWeapon());
|
||||||
const auto& weapons = e->getAllWeapons();
|
const auto &weapons = e->getAllWeapons();
|
||||||
for (auto& w : weapons) {
|
for (auto &w : weapons) {
|
||||||
for (auto b : w->getBulletManager()->getBullets()) {
|
for (auto b : w->getBulletManager()->getBullets()) {
|
||||||
renderer->addDrawable(RenderLayer::GameObjects, b.get());
|
renderer->addDrawable(RenderLayer::GameObjects, b.get());
|
||||||
}
|
}
|
||||||
|
|
@ -177,53 +151,22 @@ void Scene::render(std::shared_ptr<Renderer> renderer)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer->render();
|
renderer->render();
|
||||||
/*
|
DEBUG_TEXT(glm::vec3(10.f, 10.f, 0.f), glm::vec4(0.f, 0.f, 0.f, 1.f), 0.5f,
|
||||||
for (const auto& bullet : player->getHeldWeapon()->getBulletManager()->getBullets()) {
|
"{} / {}", getPlayer()->getHeldWeapon()->getMagazine(),
|
||||||
DebugDrawer::getInstance().addLine(player->getCenter(), bullet->getCenter(), glm::vec4(1.f, 0.f, 0.f, 0.f));
|
getPlayer()->getHeldWeapon()->getAmmo());
|
||||||
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);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
DebugDrawer::getInstance().draw(camera->getProjectionMatrix() * camera->getViewMatrix());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::unloadScene()
|
void Scene::unloadScene() {
|
||||||
{
|
// xmlLoader.reset();
|
||||||
//xmlLoader.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::hookSceneEvents()
|
void Scene::hookSceneEvents() {
|
||||||
{
|
|
||||||
std::weak_ptr<Scene> weakSelf = shared_from_this();
|
std::weak_ptr<Scene> weakSelf = shared_from_this();
|
||||||
eventManager->subscribe<BulletCollideEvent>([weakSelf](const BulletCollideEvent& e) {
|
eventManager->subscribe<BulletCollideEvent>(
|
||||||
|
[weakSelf](const BulletCollideEvent &e) {
|
||||||
if (auto self = weakSelf.lock()) {
|
if (auto self = weakSelf.lock()) {
|
||||||
GameActor* shooter = self->getGameActorByID(e.ownerID);
|
GameActor *shooter = self->getGameActorByID(e.ownerID);
|
||||||
GameActor* target = self->getGameActorByID(e.victimID);
|
GameActor *target = self->getGameActorByID(e.victimID);
|
||||||
if (shooter && target)
|
if (shooter && target)
|
||||||
if (auto weapon = shooter->getHeldWeapon())
|
if (auto weapon = shooter->getHeldWeapon())
|
||||||
weapon->onHitCallback(target, e.bullet.get(), e.normal);
|
weapon->onHitCallback(target, e.bullet.get(), e.normal);
|
||||||
|
|
@ -231,18 +174,16 @@ void Scene::hookSceneEvents()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
GameActor* Scene::getGameActorByID(const unsigned int ID)
|
GameActor *Scene::getGameActorByID(const unsigned int ID) {
|
||||||
{
|
|
||||||
auto iterator = entities.find(ID);
|
auto iterator = entities.find(ID);
|
||||||
if (iterator == entities.end())
|
if (iterator == entities.end())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return iterator->second.get();
|
return iterator->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::span<std::weak_ptr<GameActor>> Scene::getAllEntities() const
|
std::span<std::weak_ptr<GameActor>> Scene::getAllEntities() const {
|
||||||
{
|
|
||||||
entityCache.clear();
|
entityCache.clear();
|
||||||
for (const auto& [_, entity] : entities) {
|
for (const auto &[_, entity] : entities) {
|
||||||
entityCache.push_back(entity);
|
entityCache.push_back(entity);
|
||||||
}
|
}
|
||||||
return entityCache;
|
return entityCache;
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,47 @@
|
||||||
#include "gameplay/weapons/weapon.h"
|
#include "gameplay/weapons/weapon.h"
|
||||||
#include "gameplay/weapons/bulletmanager.h"
|
|
||||||
#include "gameplay/weapons/bullet.h"
|
|
||||||
#include "gameplay/gameactor.h"
|
#include "gameplay/gameactor.h"
|
||||||
#include "gameplay/physics.h"
|
#include "gameplay/physics.h"
|
||||||
|
#include "gameplay/weapons/bullet.h"
|
||||||
|
#include "gameplay/weapons/bulletmanager.h"
|
||||||
#include <SDL_timer.h>
|
#include <SDL_timer.h>
|
||||||
|
|
||||||
#include "utility/debugdraw.h"
|
|
||||||
#include "utility/component.h"
|
#include "utility/component.h"
|
||||||
|
#include "utility/debugdraw.h"
|
||||||
#include "utility/events.h"
|
#include "utility/events.h"
|
||||||
|
#include "utility/logger.h"
|
||||||
#include "utility/resourcemanager.h"
|
#include "utility/resourcemanager.h"
|
||||||
#include "utility/script.h"
|
#include "utility/script.h"
|
||||||
#include "utility/logger.h"
|
|
||||||
|
|
||||||
// TODO: Regular clean up, make this mess readable!
|
// TODO: Regular clean up, make this mess readable!
|
||||||
|
|
||||||
Weapon::Weapon(const WeaponData* data, const unsigned weaponShaderID, const unsigned bulletShaderID, ResourceManager* resourceManager)
|
Weapon::Weapon(const WeaponData *data, const unsigned weaponShaderID,
|
||||||
:
|
const unsigned bulletShaderID, ResourceManager *resourceManager)
|
||||||
Entity (weaponShaderID),
|
: Entity(weaponShaderID), weaponType(data->id),
|
||||||
weaponType (data->id),
|
weaponSize(glm::vec2(data->sizeX, data->sizeY)),
|
||||||
weaponSize (glm::vec2(data->sizeX, data->sizeY)),
|
weaponOffset(glm::vec2(data->offsetX, data->offsetY)),
|
||||||
weaponOffset (glm::vec2(data->offsetX, data->offsetY)),
|
weaponMag(data->clipSize), weaponMagSize(data->clipSize),
|
||||||
weaponMag (data->clipSize),
|
weaponAmmo(data->maxAmmo), bulletSpeed(data->bulletSpeed),
|
||||||
weaponMagSize (data->clipSize),
|
bulletDrop(data->bulletDrop), fireSpeed(data->fireSpeed),
|
||||||
weaponAmmo (data->maxAmmo),
|
bulletSize(glm::vec2(data->bulletSizeX, data->bulletSizeY)),
|
||||||
bulletSpeed (data->bulletSpeed),
|
bulletShaderID(bulletShaderID),
|
||||||
bulletDrop (data->bulletDrop),
|
bulletManager(std::make_shared<BulletManager>()),
|
||||||
fireSpeed (data->fireSpeed),
|
bulletSpread(std::make_unique<UTIL::RandomGenerator>(-data->bulletSpread,
|
||||||
bulletSize (glm::vec2(data->bulletSizeX, data->bulletSizeY)),
|
data->bulletSpread)),
|
||||||
bulletShaderID (bulletShaderID),
|
bulletModifer(
|
||||||
bulletManager (std::make_shared<BulletManager>()),
|
std::make_unique<UTIL::RandomGenerator>(data->modMin, data->modMax)) {
|
||||||
bulletSpread (std::make_unique<UTIL::RandomGenerator>(-data->bulletSpread, data->bulletSpread)),
|
|
||||||
bulletModifer (std::make_unique<UTIL::RandomGenerator>(data->modMin, data->modMax))
|
|
||||||
{
|
|
||||||
if (data->bulletAnimated)
|
if (data->bulletAnimated)
|
||||||
bulletSprite = std::make_unique<AnimationComponent>(resourceManager->loadAnimationSet(data->bulletGraphic, entityid));
|
bulletSprite = std::make_unique<AnimationComponent>(
|
||||||
|
resourceManager->loadAnimationSet(data->bulletGraphic, entityid));
|
||||||
else
|
else
|
||||||
bulletSprite = std::make_unique<SpriteComponent>(resourceManager->loadSpriteStatic(data->bulletGraphic));
|
bulletSprite = std::make_unique<SpriteComponent>(
|
||||||
|
resourceManager->loadSpriteStatic(data->bulletGraphic));
|
||||||
|
|
||||||
if (data->animated)
|
if (data->animated) {
|
||||||
{
|
addComponent(std::make_unique<AnimationComponent>(
|
||||||
addComponent(std::make_unique<AnimationComponent>(resourceManager->loadAnimationSet(data->id, entityid)));
|
resourceManager->loadAnimationSet(data->id, entityid)));
|
||||||
}
|
} else
|
||||||
else
|
addComponent(std::make_unique<SpriteComponent>(
|
||||||
addComponent(std::make_unique<SpriteComponent>(resourceManager->loadSpriteStatic(data->graphic)));
|
resourceManager->loadSpriteStatic(data->graphic)));
|
||||||
this->setScale(glm::vec3(weaponSize.x, weaponSize.y, 1.0f));
|
this->setScale(glm::vec3(weaponSize.x, weaponSize.y, 1.0f));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -50,82 +49,71 @@ void Weapon::addComponent(std::unique_ptr<Component> comp) {
|
||||||
components.push_back(std::move(comp));
|
components.push_back(std::move(comp));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weapon::reload()
|
void Weapon::reload() {
|
||||||
{
|
if (auto event = eventManager.lock()) {
|
||||||
if (auto event = eventManager.lock())
|
event->notify<EntityReloadEvent>(
|
||||||
{
|
{entityid, wielder->getPosition(), weaponType});
|
||||||
event->notify<EntityReloadEvent>({ entityid, wielder->getPosition(), weaponType });
|
|
||||||
reloading = true;
|
reloading = true;
|
||||||
if (weaponAmmo < weaponMagSize) {
|
if (weaponAmmo < weaponMagSize) {
|
||||||
weaponMag = weaponAmmo;
|
weaponMag = weaponAmmo;
|
||||||
weaponAmmo = 0;
|
weaponAmmo = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
weaponMag = weaponMagSize;
|
weaponMag = weaponMagSize;
|
||||||
weaponAmmo -= weaponMagSize;
|
weaponAmmo -= weaponMagSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Weapon::shoot()
|
bool Weapon::shoot() {
|
||||||
{
|
|
||||||
bool shotsFired = false;
|
bool shotsFired = false;
|
||||||
if (wielder)
|
if (wielder) {
|
||||||
{
|
|
||||||
Uint32 currentTime = SDL_GetTicks();
|
Uint32 currentTime = SDL_GetTicks();
|
||||||
if (currentTime - lastFireTime >= fireSpeed && !reloading)
|
if (currentTime - lastFireTime >= fireSpeed && !reloading) {
|
||||||
{
|
if (weaponMag > 0) {
|
||||||
if (weaponMag > 0)
|
|
||||||
{
|
|
||||||
shotsFired = true;
|
shotsFired = true;
|
||||||
if (auto event = eventManager.lock())
|
if (auto event = eventManager.lock())
|
||||||
event->notify<EntityFireEvent>({entityid, fireSpeed, wielder->getPosition(), weaponType});
|
event->notify<EntityFireEvent>(
|
||||||
if (!weaponScript || !weaponScript->lua["onShoot"].valid())
|
{entityid, fireSpeed, wielder->getPosition(), weaponType});
|
||||||
{
|
if (!weaponScript || !weaponScript->lua["onShoot"].valid()) {
|
||||||
// create bullet using this generated data
|
// create bullet using this generated data
|
||||||
BulletData b = genBulletData();
|
BulletData b = genBulletData();
|
||||||
createBullet(b);
|
createBullet(b);
|
||||||
weaponMag -= 1;
|
weaponMag -= 1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
auto result = weaponScript->lua["onShoot"]();
|
auto result = weaponScript->lua["onShoot"]();
|
||||||
if (!result.valid())
|
if (!result.valid()) {
|
||||||
{
|
|
||||||
sol::error err = result;
|
sol::error err = result;
|
||||||
std::cerr << "lua error: " << err.what() << std::endl;
|
std::cerr << "lua error: " << err.what() << std::endl;
|
||||||
}
|
}
|
||||||
// auto reload
|
// auto reload
|
||||||
if ((weaponMag -= 1) <= 0) reload();
|
if ((weaponMag -= 1) <= 0)
|
||||||
|
reload();
|
||||||
}
|
}
|
||||||
}
|
} else if (weaponMag <= 0)
|
||||||
else if (weaponMag <= 0) reload();
|
reload();
|
||||||
lastFireTime = currentTime;
|
lastFireTime = currentTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return shotsFired;
|
return shotsFired;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weapon::hookEventManager(std::weak_ptr<EventManager> eventManager)
|
void Weapon::hookEventManager(std::weak_ptr<EventManager> eventManager) {
|
||||||
{
|
|
||||||
this->eventManager = eventManager;
|
this->eventManager = eventManager;
|
||||||
|
|
||||||
for (auto& component : components)
|
for (auto &component : components) {
|
||||||
{
|
if (component->getType() == Component::TYPE::ANIMATION) {
|
||||||
if (component->getType() == Component::TYPE::ANIMATION)
|
auto animComponent = static_cast<AnimationComponent *>(component.get());
|
||||||
{
|
|
||||||
auto animComponent = static_cast<AnimationComponent*>(component.get());
|
|
||||||
animComponent->getAnimationSet()->attachEventManager(eventManager);
|
animComponent->getAnimationSet()->attachEventManager(eventManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto event = this->eventManager.lock()) {
|
if (auto event = this->eventManager.lock()) {
|
||||||
auto self = this;
|
auto self = this;
|
||||||
event->subscribe<AnimationFinishedEvent>([self](const AnimationFinishedEvent& e) {
|
event->subscribe<AnimationFinishedEvent>(
|
||||||
|
[self](const AnimationFinishedEvent &e) {
|
||||||
if (self) {
|
if (self) {
|
||||||
if (e.entityid == self->entityid && e.animType == "reload")
|
if (e.entityid == self->entityid && e.animType == "reload") {
|
||||||
{
|
if (self->reloading) {
|
||||||
if (self->reloading)
|
|
||||||
{
|
|
||||||
self->reloading = false;
|
self->reloading = false;
|
||||||
self->wasReloading = true;
|
self->wasReloading = true;
|
||||||
}
|
}
|
||||||
|
|
@ -137,39 +125,33 @@ void Weapon::hookEventManager(std::weak_ptr<EventManager> eventManager)
|
||||||
bulletManager->hookEventManager(eventManager);
|
bulletManager->hookEventManager(eventManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weapon::attachScript(std::unique_ptr<WeaponScript> script)
|
void Weapon::attachScript(std::unique_ptr<WeaponScript> script) {
|
||||||
{
|
|
||||||
weaponScript = std::move(script);
|
weaponScript = std::move(script);
|
||||||
weaponScript->lua["weapon"] = this;
|
weaponScript->lua["weapon"] = this;
|
||||||
LOG(DEBUG, "Weapon state bound", NULL);
|
LOG(DEBUG, "Weapon state bound", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weapon::onHitCallback(GameActor* target, PhysicsComponent* bullet, const glm::vec2& normal)
|
void Weapon::onHitCallback(GameActor *target, PhysicsComponent *bullet,
|
||||||
{
|
const glm::vec2 &normal) {
|
||||||
if (weaponScript && weaponScript->lua["onHit"].valid())
|
if (weaponScript && weaponScript->lua["onHit"].valid()) {
|
||||||
{
|
|
||||||
auto result = weaponScript->lua["onHit"](target, bullet, normal);
|
auto result = weaponScript->lua["onHit"](target, bullet, normal);
|
||||||
if (!result.valid())
|
if (!result.valid()) {
|
||||||
{
|
|
||||||
sol::error err = result;
|
sol::error err = result;
|
||||||
std::cerr << "lua error: " << err.what() << std::endl;
|
std::cerr << "lua error: " << err.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weapon::update(double deltaTime)
|
void Weapon::update(double deltaTime) {
|
||||||
{
|
|
||||||
Entity::update(deltaTime);
|
Entity::update(deltaTime);
|
||||||
if (wielded)
|
if (wielded) {
|
||||||
{
|
|
||||||
// move the weapon into place as the wielder rotates and moves
|
// move the weapon into place as the wielder rotates and moves
|
||||||
if (wielder)
|
if (wielder)
|
||||||
adjustWeapon();
|
adjustWeapon();
|
||||||
|
|
||||||
for (auto& component : components)
|
for (auto &component : components)
|
||||||
component->update();
|
component->update();
|
||||||
if (wasReloading)
|
if (wasReloading) {
|
||||||
{
|
|
||||||
wasReloading = false;
|
wasReloading = false;
|
||||||
if (auto event = eventManager.lock()) {
|
if (auto event = eventManager.lock()) {
|
||||||
event->notify<EntityFinishReloadEvent>({entityid});
|
event->notify<EntityFinishReloadEvent>({entityid});
|
||||||
|
|
@ -179,33 +161,27 @@ void Weapon::update(double deltaTime)
|
||||||
bulletManager->update(deltaTime);
|
bulletManager->update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weapon::draw()
|
void Weapon::draw() {
|
||||||
{
|
|
||||||
Entity::draw();
|
Entity::draw();
|
||||||
if (wielded)
|
if (wielded) {
|
||||||
{
|
for (auto &component : components) {
|
||||||
for (auto& component : components)
|
|
||||||
{
|
|
||||||
component->play();
|
component->play();
|
||||||
component->bind();
|
component->bind();
|
||||||
component->render();
|
component->render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//bulletManager->draw();
|
// bulletManager->draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weapon::adjustWeapon()
|
void Weapon::adjustWeapon() {
|
||||||
{
|
|
||||||
float rotation = glm::radians(wielder->getRotation());
|
float rotation = glm::radians(wielder->getRotation());
|
||||||
|
|
||||||
glm::vec3 offset = glm::vec3(
|
glm::vec3 offset = glm::vec3(
|
||||||
cos(rotation) * ((wielder->getScale().x) - weaponSize.x * 0.5f),
|
cos(rotation) * ((wielder->getScale().x) - weaponSize.x * 0.5f),
|
||||||
sin(rotation) * ((wielder->getScale().y) - weaponSize.y * 0.5f),
|
sin(rotation) * ((wielder->getScale().y) - weaponSize.y * 0.5f), 0.0f);
|
||||||
0.0f
|
|
||||||
);
|
|
||||||
glm::vec3 origin = wielder->getCenter() + offset;
|
glm::vec3 origin = wielder->getCenter() + offset;
|
||||||
//origin.x += (weaponSize.x) * 0.25f;
|
// origin.x += (weaponSize.x) * 0.25f;
|
||||||
//origin.y += (weaponSize.y) * 0.25f;
|
// origin.y += (weaponSize.y) * 0.25f;
|
||||||
|
|
||||||
// Flip the texture if the weapon is facing upwards or downwards
|
// Flip the texture if the weapon is facing upwards or downwards
|
||||||
Direction d = getDirectionFromRotation(glm::degrees(rotation));
|
Direction d = getDirectionFromRotation(glm::degrees(rotation));
|
||||||
|
|
@ -221,16 +197,14 @@ void Weapon::adjustWeapon()
|
||||||
lastDir = getDirectionFromRotation(glm::degrees(rotation));
|
lastDir = getDirectionFromRotation(glm::degrees(rotation));
|
||||||
}
|
}
|
||||||
|
|
||||||
Weapon::BulletData Weapon::genBulletData()
|
Weapon::BulletData Weapon::genBulletData() {
|
||||||
{
|
|
||||||
BulletData b;
|
BulletData b;
|
||||||
float rotation = glm::radians(wielder->getRotation());
|
float rotation = glm::radians(wielder->getRotation());
|
||||||
float spreadOffset = glm::radians(static_cast<float>(bulletSpread->genFloat()));
|
float spreadOffset =
|
||||||
|
glm::radians(static_cast<float>(bulletSpread->genFloat()));
|
||||||
b.mass = 0.1f;
|
b.mass = 0.1f;
|
||||||
glm::vec2 facing = glm::vec2(
|
glm::vec2 facing =
|
||||||
cos(rotation + spreadOffset),
|
glm::vec2(cos(rotation + spreadOffset), sin(rotation + spreadOffset));
|
||||||
sin(rotation + spreadOffset)
|
|
||||||
);
|
|
||||||
b.direction = glm::normalize(facing);
|
b.direction = glm::normalize(facing);
|
||||||
b.sizeMod = bulletModifer->genFloat();
|
b.sizeMod = bulletModifer->genFloat();
|
||||||
b.speedMod = bulletModifer->genFloat();
|
b.speedMod = bulletModifer->genFloat();
|
||||||
|
|
@ -240,52 +214,36 @@ Weapon::BulletData Weapon::genBulletData()
|
||||||
|
|
||||||
b.origin = glm::vec3(
|
b.origin = glm::vec3(
|
||||||
// x offset from the wielder
|
// x offset from the wielder
|
||||||
wielder->getCenter().x + cos(rotation) * radius - sin(rotation) * weaponOffset.y,
|
wielder->getCenter().x + cos(rotation) * radius -
|
||||||
|
sin(rotation) * weaponOffset.y,
|
||||||
// y offset from the wielder
|
// y offset from the wielder
|
||||||
wielder->getCenter().y + sin(rotation) * radius + cos(rotation) * weaponOffset.y,
|
wielder->getCenter().y + sin(rotation) * radius +
|
||||||
0.0f
|
cos(rotation) * weaponOffset.y,
|
||||||
);
|
0.0f);
|
||||||
b.origin.x -= ((bulletSize.x) * b.sizeMod) * 0.5f;
|
b.origin.x -= ((bulletSize.x) * b.sizeMod) * 0.5f;
|
||||||
b.origin.y -= ((bulletSize.y) * b.sizeMod) * 0.5f;
|
b.origin.y -= ((bulletSize.y) * b.sizeMod) * 0.5f;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weapon::createBullet(const Weapon::BulletData& data)
|
void Weapon::createBullet(const Weapon::BulletData &data) {
|
||||||
{
|
auto bullet = std::make_shared<Bullet>(wielder->getEntityID(), bulletShaderID,
|
||||||
auto bullet = std::make_shared<Bullet>(wielder->getEntityID(), bulletShaderID, data.origin, data.direction, bulletSpeed, bulletDrop, bulletSize);
|
data.origin, data.direction,
|
||||||
|
bulletSpeed, bulletDrop, bulletSize);
|
||||||
bullet->addComponent(bulletSprite.get());
|
bullet->addComponent(bulletSprite.get());
|
||||||
bullet->addPhysicsComponent(std::make_shared<PhysicsComponent>(PhysicsComponentFactory::makeBullet(wielder->getEntityID(), data.origin, data.mass, bulletSize.x / 2)));
|
bullet->addPhysicsComponent(
|
||||||
bullet->getPhysicsComponent()->rigidBody.velocity += bulletSpeed * data.direction / data.mass;
|
std::make_shared<PhysicsComponent>(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())
|
if (auto event = eventManager.lock())
|
||||||
event->notify<BulletFiredEvent>({bullet});
|
event->notify<BulletFiredEvent>({bullet});
|
||||||
bulletManager->addBullet(bullet);
|
bulletManager->addBullet(bullet);
|
||||||
}
|
}
|
||||||
|
|
||||||
Weapon::~Weapon()
|
Weapon::~Weapon() {
|
||||||
{
|
|
||||||
if (weaponScript) {
|
if (weaponScript) {
|
||||||
weaponScript->lua["onShoot"] = sol::nil;
|
weaponScript->lua["onShoot"] = sol::nil;
|
||||||
weaponScript->lua.collect_gc();
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
||||||
28
YuppleMayham/src/graphics/glwindow.cpp
Normal file
28
YuppleMayham/src/graphics/glwindow.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include "graphics/glwindow.h"
|
||||||
|
#include <SDL_error.h>
|
||||||
|
#include <SDL_video.h>
|
||||||
|
|
||||||
|
bool GLWindow::Init() {
|
||||||
|
window = SDL_CreateWindow(name, SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL);
|
||||||
|
if (!window) {
|
||||||
|
LOG(ERROR, "Failed to create window! {}", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glContext = SDL_GL_CreateContext(window);
|
||||||
|
if (!glContext) {
|
||||||
|
LOG(ERROR, "Failed to create opengl context! {}", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLWindow::resizeWindow(size_t width, size_t height) {
|
||||||
|
w = width;
|
||||||
|
h = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLWindow::~GLWindow() {
|
||||||
|
SDL_GL_DeleteContext(glContext);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
}
|
||||||
|
|
@ -1,44 +1,41 @@
|
||||||
#include "graphics/renderer.h"
|
#include "graphics/renderer.h"
|
||||||
#include "graphics/shader.h"
|
#include "graphics/shader.h"
|
||||||
#include "utility/resourcemanager.h"
|
|
||||||
#include "utility/logger.h"
|
|
||||||
#include "utility/events.h"
|
#include "utility/events.h"
|
||||||
|
#include "utility/logger.h"
|
||||||
|
#include "utility/resourcemanager.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
#include <graphics/postprocess.h>
|
#include <graphics/postprocess.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
Renderer::Renderer(const std::shared_ptr<ResourceManager>& r)
|
Renderer::Renderer(const std::shared_ptr<ResourceManager> &r,
|
||||||
: resourceManager(r)
|
const std::shared_ptr<GLWindow> &w)
|
||||||
{
|
: resourceManager(r), glWindow(w) {
|
||||||
initFrameBuffers();
|
initFrameBuffers();
|
||||||
initUniformBuffers();
|
initUniformBuffers();
|
||||||
screenQuad = std::make_unique<ScreenQuad>();
|
screenQuad = std::make_unique<ScreenQuad>();
|
||||||
postProcessor = std::make_unique<Postprocessor>(r);
|
postProcessor = std::make_unique<Postprocessor>(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::hookEventManager(std::weak_ptr<EventManager> eventManager)
|
void Renderer::hookEventManager(std::weak_ptr<EventManager> eventManager) {
|
||||||
{
|
|
||||||
if (auto e = eventManager.lock()) {
|
if (auto e = eventManager.lock()) {
|
||||||
e->subscribe<ScreenShakeEvent>([this](const ScreenShakeEvent& event) {
|
e->subscribe<ScreenShakeEvent>([this](const ScreenShakeEvent &event) {
|
||||||
postProcessor->ApplyEffect(Postprocessor::SHAKE,
|
postProcessor->ApplyEffect(Postprocessor::SHAKE, event.intensity,
|
||||||
event.intensity,
|
event.duration);
|
||||||
event.duration
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
e->subscribe<ScreenBlurEvent>([this](const ScreenBlurEvent& event) {
|
e->subscribe<ScreenBlurEvent>([this](const ScreenBlurEvent &event) {
|
||||||
postProcessor->ApplyEffect(Postprocessor::BLUR,
|
postProcessor->ApplyEffect(Postprocessor::BLUR, event.intensity,
|
||||||
event.intensity,
|
event.duration);
|
||||||
event.duration
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
e->subscribe<WindowResizeEvent>(
|
||||||
|
[this](const WindowResizeEvent &event) { resizeFrameBuffers(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the framebuffers used by the renderer to allow for post-processing effects
|
// Initialize the framebuffers used by the renderer to allow for post-processing
|
||||||
void Renderer::initFrameBuffers()
|
// effects
|
||||||
{
|
void Renderer::initFrameBuffers() {
|
||||||
glGenFramebuffers(1, &worldBuffer.frame);
|
glGenFramebuffers(1, &worldBuffer.frame);
|
||||||
glGenFramebuffers(1, &hudBuffer.frame);
|
glGenFramebuffers(1, &hudBuffer.frame);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, worldBuffer.frame);
|
glBindFramebuffer(GL_FRAMEBUFFER, worldBuffer.frame);
|
||||||
|
|
@ -46,17 +43,20 @@ void Renderer::initFrameBuffers()
|
||||||
// World buffer creation
|
// World buffer creation
|
||||||
glGenTextures(1, &worldBuffer.texture);
|
glGenTextures(1, &worldBuffer.texture);
|
||||||
glBindTexture(GL_TEXTURE_2D, worldBuffer.texture);
|
glBindTexture(GL_TEXTURE_2D, worldBuffer.texture);
|
||||||
// !!! NEED TO CREATE STATIC WINDOW SIZING !!!
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glWindow->Width(), glWindow->Height(),
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800, 600, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
//Attaching empty texture as color buffer for framebuffer
|
// Attaching empty texture as color buffer for framebuffer
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, worldBuffer.texture, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||||
|
worldBuffer.texture, 0);
|
||||||
|
|
||||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
LOG(ERROR, "Failed to complete world framebuffer: {}", glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
LOG(ERROR, "Failed to complete world framebuffer: {}",
|
||||||
|
glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
||||||
assert(1 == 0); // force crash
|
assert(1 == 0); // force crash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,15 +68,18 @@ void Renderer::initFrameBuffers()
|
||||||
|
|
||||||
glGenTextures(1, &hudBuffer.texture);
|
glGenTextures(1, &hudBuffer.texture);
|
||||||
glBindTexture(GL_TEXTURE_2D, hudBuffer.texture);
|
glBindTexture(GL_TEXTURE_2D, hudBuffer.texture);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800, 600, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glWindow->Width(), glWindow->Height(),
|
||||||
|
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hudBuffer.texture, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||||
|
hudBuffer.texture, 0);
|
||||||
|
|
||||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
LOG(ERROR, "Failed to complete hud framebuffer: {}", glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
LOG(ERROR, "Failed to complete hud framebuffer: {}",
|
||||||
|
glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
||||||
assert(1 == 0); // force crash
|
assert(1 == 0); // force crash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,8 +89,16 @@ void Renderer::initFrameBuffers()
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::initUniformBuffers()
|
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);
|
glGenBuffers(1, &uboMatrices);
|
||||||
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
|
glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
|
||||||
|
|
@ -95,39 +106,38 @@ void Renderer::initUniformBuffers()
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboMatrices);
|
glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboMatrices);
|
||||||
//glBindBufferRange(GL_UNIFORM_BUFFER, 0, uboMatrices, 0, 2 * sizeof(glm::mat4));
|
// glBindBufferRange(GL_UNIFORM_BUFFER, 0, uboMatrices, 0, 2 *
|
||||||
|
// sizeof(glm::mat4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::setProjAndViewMatrix(const glm::mat4& proj, const glm::mat4& view)
|
void Renderer::setProjAndViewMatrix(const glm::mat4 &proj,
|
||||||
{
|
const glm::mat4 &view) {
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
|
glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
|
||||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(proj));
|
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4),
|
||||||
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view));
|
glm::value_ptr(proj));
|
||||||
|
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4),
|
||||||
|
glm::value_ptr(view));
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::addDrawable(RenderLayer renderLayer, Drawable *drawable)
|
void Renderer::addDrawable(RenderLayer renderLayer, Drawable *drawable) {
|
||||||
{
|
|
||||||
if (renderLayer == RenderLayer::HUD || renderLayer == RenderLayer::Menu)
|
if (renderLayer == RenderLayer::HUD || renderLayer == RenderLayer::Menu)
|
||||||
HUDLayerPool[renderLayer].push_back(drawable);
|
HUDLayerPool[renderLayer].push_back(drawable);
|
||||||
else
|
else
|
||||||
worldLayerPool[renderLayer].push_back(drawable);
|
worldLayerPool[renderLayer].push_back(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::removeDrawable(RenderLayer renderLayer, Drawable *drawable)
|
void Renderer::removeDrawable(RenderLayer renderLayer, Drawable *drawable) {
|
||||||
{
|
auto erase = [&](auto &pool) {
|
||||||
auto erase = [&](auto& pool) {
|
|
||||||
pool.erase(std::remove(pool.begin(), pool.end(), drawable), pool.end());
|
pool.erase(std::remove(pool.begin(), pool.end(), drawable), pool.end());
|
||||||
};
|
};
|
||||||
if (renderLayer == RenderLayer::HUD || renderLayer == RenderLayer::Menu) {
|
if (renderLayer == RenderLayer::HUD || renderLayer == RenderLayer::Menu) {
|
||||||
erase(HUDLayerPool[renderLayer]);
|
erase(HUDLayerPool[renderLayer]);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
erase(worldLayerPool[renderLayer]);
|
erase(worldLayerPool[renderLayer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::render()
|
void Renderer::render() {
|
||||||
{
|
|
||||||
// Bind the world frame buffer
|
// Bind the world frame buffer
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, worldBuffer.frame);
|
glBindFramebuffer(GL_FRAMEBUFFER, worldBuffer.frame);
|
||||||
// clear color and depth buffer
|
// clear color and depth buffer
|
||||||
|
|
@ -147,17 +157,16 @@ void Renderer::render()
|
||||||
screenQuad->draw();
|
screenQuad->draw();
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, hudBuffer.texture);
|
glBindTexture(GL_TEXTURE_2D, hudBuffer.texture);
|
||||||
postProcessor->applyPostProcess(1);
|
// postProcessor->applyPostProcess(1);
|
||||||
screenQuad->draw();
|
screenQuad->draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::renderPool(auto& layerPool)
|
void Renderer::renderPool(auto &layerPool) {
|
||||||
{
|
|
||||||
sortLayerPool(layerPool);
|
sortLayerPool(layerPool);
|
||||||
Shader* curShader = nullptr;
|
Shader *curShader = nullptr;
|
||||||
for (const auto& layer : renderingOrder) {
|
for (const auto &layer : renderingOrder) {
|
||||||
unsigned curShaderID = static_cast<unsigned>(-1);
|
unsigned curShaderID = static_cast<unsigned>(-1);
|
||||||
for (const auto& item : layerPool[layer]) {
|
for (const auto &item : layerPool[layer]) {
|
||||||
if (item->getShaderID() != curShaderID) {
|
if (item->getShaderID() != curShaderID) {
|
||||||
curShaderID = item->getShaderID();
|
curShaderID = item->getShaderID();
|
||||||
curShader = resourceManager->getShaderByID(curShaderID);
|
curShader = resourceManager->getShaderByID(curShaderID);
|
||||||
|
|
@ -175,46 +184,43 @@ void Renderer::renderPool(auto& layerPool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::clear()
|
void Renderer::clear() {
|
||||||
{
|
|
||||||
worldLayerPool.clear();
|
worldLayerPool.clear();
|
||||||
HUDLayerPool.clear();
|
HUDLayerPool.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::uploadUniforms(const unsigned shaderID, const std::vector<Uniform>& uniforms)
|
void Renderer::uploadUniforms(const unsigned shaderID,
|
||||||
{
|
const std::vector<Uniform> &uniforms) {
|
||||||
Shader *shader = resourceManager->getShaderByID(shaderID);
|
Shader *shader = resourceManager->getShaderByID(shaderID);
|
||||||
if (shader == nullptr) {
|
if (shader == nullptr) {
|
||||||
LOG(ERROR, "No shader found with id {} !", shaderID);
|
LOG(ERROR, "No shader found with id {} !", shaderID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const auto& uniform : uniforms) {
|
for (const auto &uniform : uniforms) {
|
||||||
std::visit([&](auto&& arg) {
|
std::visit(
|
||||||
|
[&](auto &&arg) {
|
||||||
using T = std::decay_t<decltype(arg)>;
|
using T = std::decay_t<decltype(arg)>;
|
||||||
if constexpr (std::is_same_v<T, bool>) {
|
if constexpr (std::is_same_v<T, bool>) {
|
||||||
shader->setBool(uniform.name, arg);
|
shader->setBool(uniform.name, arg);
|
||||||
}
|
} else if constexpr (std::is_same_v<T, int>) {
|
||||||
else if constexpr (std::is_same_v<T, int>) {
|
|
||||||
shader->setInt(uniform.name, arg);
|
shader->setInt(uniform.name, arg);
|
||||||
}
|
} else if constexpr (std::is_same_v<T, float>) {
|
||||||
else if constexpr (std::is_same_v<T, float>) {
|
|
||||||
shader->setFloat(uniform.name, arg);
|
shader->setFloat(uniform.name, arg);
|
||||||
}
|
} else if constexpr (std::is_same_v<T, glm::vec2>) {
|
||||||
else if constexpr (std::is_same_v<T, glm::vec2>) {
|
|
||||||
shader->setVec2(uniform.name, glm::value_ptr(arg));
|
shader->setVec2(uniform.name, glm::value_ptr(arg));
|
||||||
}
|
} else if constexpr (std::is_same_v<T, glm::mat4>) {
|
||||||
else if constexpr (std::is_same_v<T, glm::mat4>) {
|
|
||||||
shader->setMatrix4f(uniform.name, glm::value_ptr(arg));
|
shader->setMatrix4f(uniform.name, glm::value_ptr(arg));
|
||||||
}
|
}
|
||||||
}, uniform.value);
|
},
|
||||||
|
uniform.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Renderer::sortLayerPool(auto& layerPool)
|
void Renderer::sortLayerPool(auto &layerPool) {
|
||||||
{
|
// Sort by shader id, this works to batch shaders together to avoid shader
|
||||||
// Sort by shader id, this works to batch shaders together to avoid shader switching too much
|
// switching too much
|
||||||
for (auto& [_,pool] : layerPool) {
|
for (auto &[_, pool] : layerPool) {
|
||||||
std::sort(pool.begin(), pool.end(),
|
std::sort(pool.begin(), pool.end(),
|
||||||
[](const Drawable* a, const Drawable* b) {
|
[](const Drawable *a, const Drawable *b) {
|
||||||
return a->getShaderID() < b->getShaderID();
|
return a->getShaderID() < b->getShaderID();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,22 @@
|
||||||
#undef GLM_FORCE_FAST_MATH
|
|
||||||
#define GLM_FORCE_PURE
|
|
||||||
#define GLM_FORCE_CTOR_INIT
|
|
||||||
#define GLM_FORCE_COLUMN_MAJOR
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_events.h>
|
#include <SDL_events.h>
|
||||||
#include <SDL_image.h>
|
#include <SDL_image.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
// TODO: Fix circular dependency issues, mostly with input.h needing gameactor.h and command.h
|
|
||||||
#include "gameplay/game.h"
|
#include "gameplay/game.h"
|
||||||
|
#include "utility/logger.h"
|
||||||
const float vertices[] = {
|
|
||||||
0.0f, 0.5f, 0.0f,
|
|
||||||
-0.5f, -0.5f, 0.0f,
|
|
||||||
0.5f, -0.5f, 0.0f
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char* args[])
|
int main(int argc, char* args[])
|
||||||
{
|
{
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||||
|
LOG(ERROR, "Failed to initialize SDL!", NULL);
|
||||||
return -1;
|
return -1;
|
||||||
if (IMG_Init(IMG_INIT_PNG) < 0)
|
}
|
||||||
|
if (IMG_Init(IMG_INIT_PNG) < 0) {
|
||||||
|
LOG(ERROR, "Could not initialize png library", NULL);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||||
|
|
@ -31,13 +25,13 @@ int main(int argc, char* args[])
|
||||||
Game* game = new Game();
|
Game* game = new Game();
|
||||||
if (!game->init())
|
if (!game->init())
|
||||||
{
|
{
|
||||||
std::cout << "Failed to init game!" << std::endl;
|
LOG(ERROR, "Failed to init game!", NULL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!game->loadDebugScene())
|
if (!game->loadDebugScene())
|
||||||
{
|
{
|
||||||
std::cout << "Failed to load debug scene!" << std::endl;
|
LOG(ERROR, "Failed to load debug scene!", NULL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue