Browse Source

refactoring, improved jump, slope physics, collision normals

Kajetan Johannes Hammerle 3 months ago
parent
commit
70c69daab9
13 changed files with 399 additions and 243 deletions
  1. 77 0
      Engine.cpp
  2. 12 0
      Engine.h
  3. 0 21
      Entity.cpp
  4. 0 24
      Entity.h
  5. 262 64
      Game.cpp
  6. 4 22
      Game.h
  7. 3 77
      Main.cpp
  8. 14 6
      input/Controller.cpp
  9. 15 15
      input/Controller.h
  10. 1 1
      meson.build
  11. 2 2
      rendering/ColorRenderer.h
  12. 7 9
      rendering/Renderer.cpp
  13. 2 2
      rendering/Renderer.h

+ 77 - 0
Engine.cpp

@@ -0,0 +1,77 @@
+#include <getopt.h>
+
+#include "Engine.h"
+#include "Game.h"
+#include "input/Controller.h"
+#include "rendering/Shader.h"
+#include "rendering/Window.h"
+
+static Window window;
+static Shader shader;
+
+static bool parseArgs(int argAmount, char* const* args,
+                      WindowOptions& options) {
+    while(true) {
+        switch(getopt(argAmount, args, "fv")) {
+            case '?': return true;
+            case 'f': options.fullscreen = true; break;
+            case 'v': options.vsync = true; break;
+            case -1: return false;
+        }
+    }
+}
+
+bool Engine::init(int argAmount, char* const* args) {
+    WindowOptions options(3, 0, {800, 480}, true, "Pigine");
+    if(parseArgs(argAmount, args, options)) {
+        return true;
+    }
+    Error error = window.open(options);
+    if(error.has()) {
+        error.message.printLine();
+        return true;
+    }
+    error = shader.compile("resources/shader/vertex.vs",
+                           "resources/shader/fragment.fs");
+    if(error.has()) {
+        error.message.printLine();
+        return true;
+    }
+    Controller::init(window.buttons);
+    return false;
+}
+
+struct Loop {
+    Renderer renderer{shader};
+
+    void tick() {
+        Game::tick();
+    }
+
+    void render(float lag) {
+        GL::clear();
+        const Size& size = window.getSize();
+        GL::setViewport(size.width, size.height);
+
+        Matrix view;
+        view.scale(Vector3(2.0f / size.width, -2.0f / size.height, 1.0f));
+        view.translate(Vector3(-1.0f, 1.0f, 0.0f));
+        shader.setMatrix("view", view.getValues());
+
+        Game::render(lag, renderer);
+        GL::printError("GL-Error");
+    }
+
+    bool isRunning() const {
+        return Game::isRunning();
+    }
+};
+
+void Engine::start() {
+    Loop loop;
+    window.run(loop, 10'000'000);
+}
+
+const Size& Engine::getSize() {
+    return window.getSize();
+}

+ 12 - 0
Engine.h

@@ -0,0 +1,12 @@
+#ifndef ENGINE_H
+#define ENGINE_H
+
+#include "utils/Size.h"
+
+namespace Engine {
+    bool init(int argAmount, char* const* args);
+    void start();
+    const Size& getSize();
+}
+
+#endif

+ 0 - 21
Entity.cpp

@@ -1,21 +0,0 @@
-#include "Entity.h"
-
-Entity::Entity(const Vector2& size, float mass)
-    : size(size), inverseMass(1.0f / mass), onGround(false), jumpTicks(0) {
-}
-
-void Entity::addForce(const Vector2& force) {
-    acceleration += force * inverseMass;
-}
-
-void Entity::preTick() {
-    lastPosition = position;
-    // start off with gravity for the next frame
-    acceleration = Vector2(0.0f, -0.5f);
-}
-
-void Entity::tick() {
-    // euler integration, timestep is constant
-    velocity += acceleration;
-    position += velocity;
-}

+ 0 - 24
Entity.h

@@ -1,24 +0,0 @@
-#ifndef ENTITY_H
-#define ENTITY_H
-
-#include "math/Vector.h"
-
-struct Entity {
-    Vector2 lastPosition;
-    Vector2 position;
-    Vector2 size;
-    Vector2 velocity;
-    Vector2 acceleration;
-    Vector2 force;
-    float inverseMass;
-    bool onGround;
-    int jumpTicks;
-
-    Entity(const Vector2& size, float mass);
-
-    void addForce(const Vector2& force);
-    void preTick();
-    void tick();
-};
-
-#endif

+ 262 - 64
Game.cpp

@@ -1,93 +1,291 @@
 #include "Game.h"
-#include "rendering/Renderer.h"
-#include "utils/StringBuffer.h"
+#include "Engine.h"
+#include "input/Controller.h"
+#include "utils/List.h"
 #include "utils/Utils.h"
 
-Game::Game(Controller& c, const Clock& fps, const Clock& tps, const Size& size)
-    : controller(c), fps(fps), tps(tps), size(size), physicsToggle(true),
-      player(Vector2(50.0f, 50.0f), 5.0f) {
+struct Line final {
+    Vector2 a;
+    Vector2 b;
+};
+
+static List<Line> lines;
+
+static constexpr float SPEED = 2.5f;
+static constexpr float GRAVITY = 0.5f;
+static constexpr float COLLISION_STEP = 0.005f;
+
+static Vector2 windowSize;
+static Vector2 lastPosition;
+static Vector2 position{150.0f, 50.0f};
+static Vector2 size{50.0f, 50.0f};
+static Vector2 velocity;
+static Vector2 acceleration;
+static Vector2 drag;
+static float mass = 5.0f;
+static bool onGround = false;
+static float jumpPower = 0.0f;
+static float steepness = 0.0f;
+
+static bool physicsToggle = true;
+
+static Vector2 waterPosition;
+static Vector2 waterSize;
+
+static void addForce(const Vector2& force) {
+    acceleration += force / mass;
 }
 
-void Game::tick() {
-    if(controller.start.wasReleased()) {
-        physicsToggle = !physicsToggle;
-    }
-    player.preTick();
+static void addMovement() {
+    physicsToggle = physicsToggle ^ Controller::start.wasReleased();
+    float movement = Controller::right.isDown() - Controller::left.isDown();
+    float actualSpeed = SPEED * (1.0f - steepness * onGround);
     if(physicsToggle) {
-        // forces from the player
-        if(controller.a.isDown() && player.onGround) {
-            player.jumpTicks = 10;
-            player.onGround = false;
-        }
-        if(controller.right.isDown()) {
-            player.addForce(Vector2(2.5f, 0.0f));
-        }
-        if(controller.left.isDown()) {
-            player.addForce(Vector2(-2.5f, 0.0f));
-        }
-        if(player.jumpTicks > 0) {
-            player.jumpTicks--;
-            player.addForce(Vector2(0.0f, 10.0f));
+        addForce(Vector2(actualSpeed, 0.0f) * movement);
+    } else {
+        // movement by velocity should have the same terminal velocity as
+        // movement by force
+        float terminalFactor = 1.0f / ((1.0 - drag[0]) * drag[0]);
+        velocity[0] = (actualSpeed / mass) * terminalFactor * movement;
+    }
+}
+
+static bool isIn(const Vector2& posA, const Vector2& sizeA, const Vector2& posB,
+                 const Vector2& sizeB) {
+    Vector2 maxA = posA + sizeA;
+    Vector2 maxB = posB + sizeB;
+    return posA[0] < maxB[0] && maxA[0] > posB[0] && posA[1] < maxB[1] &&
+           maxA[1] > posB[1];
+}
+
+float ERROR = 1.0f / 512.0f;
+
+static bool isBetween(float y, float y1, float y2) {
+    return y >= std::min(y1, y2) && y <= std::max(y1, y2);
+}
+
+static bool compareFloats(float a, float b) {
+    return std::abs(a - b) < ERROR;
+}
+
+static bool intersect(float x11, float y11, float x12, float y12, float x21,
+                      float y21, float x22, float y22) {
+    if(compareFloats(x11, x12)) {
+        if(compareFloats(x21, x22)) {
+            return false;
+        } else {
+            if(!isBetween(x11, x21, x22)) {
+                return false;
+            }
+            float k = (y21 - y22) / (x21 - x22);
+            float d = y22 - k * x22;
+            float y = d + x11 * k;
+            return isBetween(y, y11, y12) && isBetween(y, y21, y22);
         }
-        player.jumpTicks *= controller.a.isDown();
-        // pseudo drag
-        player.addForce(Vector2(-player.velocity[0] * 0.5f, 0.0f));
     } else {
-        player.velocity[0] = 0.0f;
-        if(controller.a.isDown() && player.onGround) {
-            player.velocity[1] = 15.0f;
-            player.onGround = false;
+        if(compareFloats(x21, x22)) {
+            if(!isBetween(x21, x11, x12)) {
+                return false;
+            }
+            float k = (y11 - y12) / (x11 - x12);
+            float d = y12 - k * x12;
+            float y = d + x21 * k;
+            return isBetween(y, y11, y12) && isBetween(y, y21, y22);
+        } else {
+            float k1 = (y11 - y12) / (x11 - x12);
+            float k2 = (y21 - y22) / (x21 - x22);
+            if(compareFloats(k1, k2)) {
+                return false;
+            }
+            float d1 = y12 - k1 * x12;
+            float d2 = y22 - k2 * x22;
+
+            float x = (d1 - d2) / (k2 - k1);
+            if(!isBetween(x, x11, x12) || !isBetween(x, x21, x22)) {
+                return false;
+            }
+            float y = k1 * x + d1;
+            return isBetween(y, y11, y12) && isBetween(y, y21, y22);
         }
-        if(controller.right.isDown()) {
-            player.velocity[0] = 5.0f;
+    }
+}
+
+static bool areColliding(const Line& a, const Line& b) {
+    return intersect(a.a[0], a.a[1], a.b[0], a.b[1], b.a[0], b.a[1], b.b[0],
+                     b.b[1]);
+}
+
+static bool doesPlayerCollide() {
+    Vector2 posX = position + Vector2(size[0], 0.0f);
+    Vector2 posY = position + Vector2(0.0f, size[1]);
+    Vector2 posXY = position + size;
+    for(const Line& line : lines) {
+        if(areColliding(line, {position, posX}) ||
+           areColliding(line, {position, posY}) ||
+           areColliding(line, {posX, posXY}) ||
+           areColliding(line, {posY, posXY})) {
+            return true;
         }
-        if(controller.left.isDown()) {
-            player.velocity[0] = -5.0f;
+    }
+    return false;
+}
+
+static float slopeSteepness() {
+    Line left{position - Vector2(0.0f, 10.0f * COLLISION_STEP),
+              position + Vector2(0.0f, size[1])};
+    Line right{position + Vector2(size[0], -10.0f * COLLISION_STEP),
+               position + size};
+    float min = 100.0f;
+    float value = 100.0f;
+    for(const Line& line : lines) {
+        if(areColliding(line, left) || areColliding(line, right)) {
+            float f = (line.a[1] - line.b[1]) / (line.a[0] - line.b[0]);
+            if(std::abs(f) < min) {
+                min = std::abs(f);
+                value = f;
+            }
         }
     }
-    player.tick();
-
-    // collision detection
-    // floor crush
-    if(player.position[1] < 0.0f) {
-        player.position[1] = 0.0f;
-        player.velocity[1] = 0.0f;
-        player.onGround = true;
+    return value;
+}
+
+static void applyDrag() {
+    waterPosition = windowSize * Vector2(0.5f, 0.0f);
+    waterSize = windowSize * Vector2(0.5f, 0.125f);
+    drag = Vector2(0.1f, 0.1f);
+    if(isIn(position, size, waterPosition, waterSize)) {
+        drag *= 4.0f;
     }
-    // right wall
-    if(player.position[0] + player.size[0] > size.width) {
-        player.position[0] = size.width - player.size[0];
-        // player.velocity[0] = 0.0f;
+    acceleration -= velocity * drag;
+}
+
+static void applyGravity() {
+    acceleration -= Vector2(0.0f, GRAVITY);
+}
+
+static void handleJump() {
+    bool justJumped = false;
+    if(Controller::a.isDown() && onGround) {
+        jumpPower = 15.0f;
+        onGround = false;
+        justJumped = true;
     }
-    // left wall
-    if(player.position[0] < 0.0f) {
-        player.position[0] = 0.0f;
-        // player.velocity[0] = 0.0f;
+    addForce(Vector2(0.0f, jumpPower));
+    jumpPower *= 0.9f;
+    jumpPower *= Controller::a.isDown() && (velocity[1] > 0.0f || justJumped);
+}
+
+void Game::tick() {
+    windowSize = Vector2(static_cast<float>(Engine::getSize().width),
+                         static_cast<float>(Engine::getSize().height));
+    lastPosition = position;
+    acceleration = Vector2();
+
+    applyGravity();
+    addMovement();
+    handleJump();
+    applyDrag();
+
+    if(steepness != 100.0f) {
+        if(steepness < -1.0f) {
+            acceleration[0] += 0.1f;
+        } else if(steepness > 1.0f) {
+            acceleration[0] -= 0.1f;
+        }
+    }
+
+    lines.clear();
+    lines.add({{0.0f, 0.0f}, windowSize * Vector2(1.0f, 0.0f)});
+    lines.add({{0.0f, 0.0f}, windowSize * Vector2(0.0f, 1.0f)});
+    lines.add({windowSize, windowSize * Vector2(1.0f, 0.0f)});
+    lines.add(
+        {windowSize * Vector2(0.75f, 0.0f), windowSize * Vector2(1.0f, 0.5f)});
+    lines.add({{0.0f, 30.0f}, {400.0f, 0.0f}});
+    lines.add({{0.0f, 60.0f}, {300.0f, 0.0f}});
+    lines.add({{0.0f, 90.0f}, {200.0f, 0.0f}});
+    lines.add({{0.0f, 120.0f}, {100.0f, 0.0f}});
+    lines.add({{100.0f, 180.0f}, {200.0f, 180.0f}});
+    lines.add({{200.0f, 180.0f}, {600.0f, 380.0f}});
+
+    velocity += acceleration;
+
+    onGround = false;
+    Vector2 energy = velocity;
+    while(energy[0] != 0.0f || energy[1] != 0.0f) {
+        for(int i = 0; i < 2; i++) {
+            if(energy[i] != 0.0f) {
+                float old = position[i];
+                if(energy[i] > COLLISION_STEP) {
+                    position[i] += COLLISION_STEP;
+                    energy[i] -= COLLISION_STEP;
+                } else if(energy[i] < -COLLISION_STEP) {
+                    position[i] -= COLLISION_STEP;
+                    energy[i] += COLLISION_STEP;
+                } else {
+                    position[i] += energy[i];
+                    energy[i] = 0.0f;
+                }
+                if(doesPlayerCollide()) {
+                    if(i == 0) {
+                        float oldY = position[1];
+                        position[1] += COLLISION_STEP;
+                        if(!doesPlayerCollide()) {
+                            continue;
+                        }
+                        position[1] = oldY;
+                    }
+                    energy[i] = 0.0f;
+                    velocity[i] = 0.0f;
+                    position[i] = old;
+                }
+            }
+        }
+    }
+    steepness = slopeSteepness();
+    onGround = std::abs(steepness) < 1.0f;
+    if(onGround) {
+        velocity[1] = 0.0f;
     }
 }
 
-void Game::render(float lag, Renderer& r) const {
+void Game::render(float lag, Renderer& r) {
     r.translateTo(0.0f, 0.0f)
         .scale(1.0f, -1.0f)
-        .translateY(size.height)
+        .translateY(Engine::getSize().height)
         .update();
-    Vector2 pos = Utils::interpolate(player.lastPosition, player.position, lag);
-    r.drawRectangle(pos, player.size, Color4(0xFF, 0x00, 0x00, 0xFF));
+    r.drawRectangle(waterPosition, waterSize, Color4(0x00, 0x00, 0xFF, 0xFF));
+
+    Vector2 pos = Utils::interpolate(lastPosition, position, lag);
+    r.drawRectangle(pos, size, Color4(0xFF, 0x00, 0x00, 0xFF));
+
+    for(const Line& line : lines) {
+        Vector2 dir = line.b - line.a;
+        Vector2 normal(dir[1], -dir[0]);
+        normal.normalize();
+        normal *= 2.0f;
+        Vector2 ap = line.a + normal;
+        Vector2 bp = line.b + normal;
+        Vector2 an = line.a - normal;
+        Vector2 bn = line.b - normal;
+        r.drawTriangle(ap, bp, an, Color4(0xFF, 0xFF, 0xFF, 0xFF));
+        r.drawTriangle(bp, an, bn, Color4(0xFF, 0xFF, 0xFF, 0xFF));
+    }
 
     r.translateTo(0.0f, 0.0f).update();
     r.setStringSize(2);
-    StringBuffer<100> s("FPS: ");
-    s.append(fps.getUpdatesPerSecond()).append(" ");
-    s.append("%6.2f", tps.getUpdatesPerSecond()).append(" ");
-    s.append(physicsToggle ? "Force Physics" : "Velocity Physics");
+
     float y = 10.0f;
+    y = r.drawString(10.0f, y,
+                     physicsToggle ? "Force Physics" : "Velocity Physics");
+    StringBuffer<100> s("a = ");
+    s.append(acceleration).append(" before collision");
     y = r.drawString(10.0f, y, s);
-    s.clear().append("a = ").append(player.acceleration);
+    s.clear().append("v = ").append(velocity).append(" after collision");
     y = r.drawString(10.0f, y, s);
-    s.clear().append("v = ").append(player.velocity);
+    s.clear().append("Ground = ").append(onGround);
     y = r.drawString(10.0f, y, s);
 }
 
-bool Game::isRunning() const {
-    return !controller.select.isDown();
-}
+bool Game::isRunning() {
+    return !Controller::select.isDown();
+}

+ 4 - 22
Game.h

@@ -1,30 +1,12 @@
 #ifndef GAME_H
 #define GAME_H
 
-#include "Entity.h"
-#include "input/Buttons.h"
-#include "input/Controller.h"
 #include "rendering/Renderer.h"
-#include "utils/Clock.h"
-#include "utils/Size.h"
-
-class Game final {
-    const Controller& controller;
-    const Clock& fps;
-    const Clock& tps;
-    const Size& size;
-
-    bool physicsToggle;
-
-    Entity player;
-
-public:
-    Game(Controller& c, const Clock& fps, const Clock& tps, const Size& size);
 
+namespace Game {
     void tick();
-    void render(float lag, Renderer& renderer) const;
-
-    bool isRunning() const;
-};
+    void render(float lag, Renderer& renderer);
+    bool isRunning();
+}
 
 #endif

+ 3 - 77
Main.cpp

@@ -1,83 +1,9 @@
-#include <iostream>
-
-#include <getopt.h>
-
-#include "Game.h"
-#include "rendering/Renderer.h"
-#include "rendering/Shader.h"
-#include "rendering/Window.h"
-#include "rendering/WindowOptions.h"
-#include "utils/Clock.h"
-#include "wrapper/GL.h"
-
-bool parseArgs(int argAmount, char* const* args, WindowOptions& options) {
-    while(true) {
-        switch(getopt(argAmount, args, "fv")) {
-            case '?': return true;
-            case 'f': options.fullscreen = true; break;
-            case 'v': options.vsync = true; break;
-            case -1: return false;
-        }
-    }
-}
+#include "Engine.h"
 
 int main(int argAmount, char* const* args) {
-    Size size(800, 480);
-    WindowOptions options(3, 0, size, true, "Pigine");
-    if(parseArgs(argAmount, args, options)) {
-        return 0;
-    }
-    Window w;
-    Error error = w.open(options);
-    if(error.has()) {
-        error.message.printLine();
-        return 0;
-    }
-
-    Shader cubeShader;
-    error = cubeShader.compile("resources/shader/vertex.vs",
-                               "resources/shader/fragment.fs");
-    if(error.has()) {
-        error.message.printLine();
+    if(Engine::init(argAmount, args)) {
         return 0;
     }
-
-    Controller controller(w.buttons);
-    static Game game(controller, w.getFrameClock(), w.getTickClock(), size);
-
-    struct GameBase {
-        Window& window;
-        Game& game;
-        Shader& shader;
-        Renderer renderer;
-
-        GameBase(Window& w, Game& g, Shader& s)
-            : window(w), game(g), shader(s), renderer(s) {
-        }
-
-        void tick() {
-            game.tick();
-        }
-
-        void render(float lag) {
-            GL::clear();
-            const Size& size = window.getSize();
-            GL::setViewport(size.width, size.height);
-
-            Matrix view;
-            view.scale(Vector3(2.0f / size.width, -2.0f / size.height, 1.0f));
-            view.translate(Vector3(-1.0f, 1.0f, 0.0f));
-            shader.setMatrix("view", view.getValues());
-
-            game.render(lag, renderer);
-            GL::printError("GL-Error");
-        }
-
-        bool isRunning() const {
-            return game.isRunning();
-        }
-    };
-    GameBase base(w, game, cubeShader);
-    w.run(base, 10'000'000);
+    Engine::start();
     return 0;
 }

+ 14 - 6
input/Controller.cpp

@@ -1,11 +1,19 @@
 #include "input/Controller.h"
 
-Controller::Controller(Buttons& bs)
-    : a(GLFW_KEY_A, "A"), b(GLFW_KEY_S, "B"), x(GLFW_KEY_X, "X"),
-      y(GLFW_KEY_Z, "Y"), l(GLFW_KEY_Q, "L"), r(GLFW_KEY_W, "R"),
-      start(GLFW_KEY_E, "Start"), select(GLFW_KEY_D, "Select"),
-      left(GLFW_KEY_LEFT, "Left"), right(GLFW_KEY_RIGHT, "Right"),
-      up(GLFW_KEY_UP, "Up"), down(GLFW_KEY_DOWN, "Down") {
+Button Controller::a{GLFW_KEY_A, "A"};
+Button Controller::b{GLFW_KEY_S, "B"};
+Button Controller::x{GLFW_KEY_X, "X"};
+Button Controller::y{GLFW_KEY_Z, "Y"};
+Button Controller::l{GLFW_KEY_Q, "L"};
+Button Controller::r{GLFW_KEY_W, "R"};
+Button Controller::start{GLFW_KEY_E, "Start"};
+Button Controller::select{GLFW_KEY_D, "Select"};
+Button Controller::left{GLFW_KEY_LEFT, "Left"};
+Button Controller::right{GLFW_KEY_RIGHT, "Right"};
+Button Controller::up{GLFW_KEY_UP, "Up"};
+Button Controller::down{GLFW_KEY_DOWN, "Down"};
+
+void Controller::init(Buttons& bs) {
     bs.add(a);
     bs.add(b);
     bs.add(x);

+ 15 - 15
input/Controller.h

@@ -3,21 +3,21 @@
 
 #include "input/Buttons.h"
 
-struct Controller {
-    Button a;
-    Button b;
-    Button x;
-    Button y;
-    Button l;
-    Button r;
-    Button start;
-    Button select;
-    Button left;
-    Button right;
-    Button up;
-    Button down;
+namespace Controller {
+    extern Button a;
+    extern Button b;
+    extern Button x;
+    extern Button y;
+    extern Button l;
+    extern Button r;
+    extern Button start;
+    extern Button select;
+    extern Button left;
+    extern Button right;
+    extern Button up;
+    extern Button down;
 
-    Controller(Buttons& buttons);
-};
+    void init(Buttons& buttons);
+}
 
 #endif

+ 1 - 1
meson.build

@@ -3,7 +3,7 @@ project('pigine', 'cpp')
 src = [
     'Main.cpp', 
     'Game.cpp',
-    'Entity.cpp',
+    'Engine.cpp',
     'input/Controller.cpp',
     'rendering/Renderer.cpp',
     'rendering/ColorRenderer.cpp',

+ 2 - 2
rendering/ColorRenderer.h

@@ -1,13 +1,13 @@
 #ifndef COLORRENDERER_H
 #define COLORRENDERER_H
 
+#include "math/Vector.h"
 #include "rendering/VertexBuffer.h"
 #include "utils/Color.h"
 
 struct ColorRenderer final {
     struct Vertex {
-        float x;
-        float y;
+        Vector2 xy;
         Color4 color;
     };
 

+ 7 - 9
rendering/Renderer.cpp

@@ -88,17 +88,15 @@ void Renderer::drawTriangle(const ColorRenderer::Vertex& v1,
     colorRenderer.draw(v1, v2, v3);
 }
 
-void Renderer::drawTriangle(float x1, float y1, float x2, float y2, float x3,
-                            float y3, Color4 color) {
-    ColorRenderer::Vertex v2 = {x2, y2, color};
-    ColorRenderer::Vertex v3 = {x3, y3, color};
-    drawTriangle({x1, y1, color}, v2, v3);
+void Renderer::drawTriangle(const Vector2& v1, const Vector2& v2,
+                            const Vector2& v3, Color4 color) {
+    drawTriangle({v1, color}, {v2, color}, {v3, color});
 }
 
 void Renderer::drawRectangle(const Vector2& pos, const Vector2& size,
                              Color4 color) {
-    drawTriangle(pos[0], pos[1], pos[0] + size[0], pos[1], pos[0],
-                 pos[1] + size[1], color);
-    drawTriangle(pos[0] + size[0], pos[1], pos[0], pos[1] + size[1],
-                 pos[0] + size[0], pos[1] + size[1], color);
+    drawTriangle({pos[0], pos[1]}, {pos[0] + size[0], pos[1]},
+                 {pos[0], pos[1] + size[1]}, color);
+    drawTriangle({pos[0] + size[0], pos[1]}, {pos[0], pos[1] + size[1]},
+                 {pos[0] + size[0], pos[1] + size[1]}, color);
 }

+ 2 - 2
rendering/Renderer.h

@@ -37,8 +37,8 @@ public:
     void drawTriangle(const ColorRenderer::Vertex& v1,
                       const ColorRenderer::Vertex& v2,
                       const ColorRenderer::Vertex& v3);
-    void drawTriangle(float x1, float y1, float x2, float y2, float x3,
-                      float y3, Color4 color);
+    void drawTriangle(const Vector2& v1, const Vector2& v2, const Vector2& v3,
+                      Color4 color);
     void drawRectangle(const Vector2& pos, const Vector2& size, Color4 color);
 
 private: