From afeadd3e6c46466c816eab292cbb9886ec13e4d1 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Mon, 10 Apr 2023 12:01:18 -0500 Subject: [PATCH] Implement movement and collision for the player. --- Faceball2030/Editor.cpp | 164 ++-- Faceball2030/Editor.h | 10 +- Faceball2030/Faceball2030.vcxproj | 3 +- Faceball2030/Faceball2030.vcxproj.filters | 3 + Faceball2030/assets/dot.png | Bin 5861 -> 565 bytes Faceball2030/assets/map/map1.map | 40 +- Faceball2030/geometry2d.h | 1050 +++++++++++++++++++++ Faceball2030/main.cpp | 244 ++--- Faceball2030/main.h | 28 +- 9 files changed, 1364 insertions(+), 178 deletions(-) create mode 100644 Faceball2030/geometry2d.h diff --git a/Faceball2030/Editor.cpp b/Faceball2030/Editor.cpp index f044a1d..824bba2 100644 --- a/Faceball2030/Editor.cpp +++ b/Faceball2030/Editor.cpp @@ -1,16 +1,26 @@ - #include "pixelGameEngine.h" #include "main.h" using namespace olc; extern FaceBall* game; +Editor::Editor() { + map = LoadLevel(this->level); + MAP_SIZE = { (int)map[0].size(),(int)map.size() }; +} + void Editor::Update(float fElapsedTime){ MouseWheelEnemySelection(); RenderLevel(); WaveLayerSelection(); game->DrawStringDecal({ 2,16 }, "Selected Enemy ("+std::to_string(selectedEnemy) + "): " + game->GetData(selectedEnemy).name, WHITE, {3,3}); game->DrawStringDecal({ 2,(float)game->ScreenHeight() - 50 }, "Layer " + std::to_string(waveLayer), WHITE, { 5,5 }); + if (!game->IsTextEntryEnabled()) { + if (game->GetKey(F3).bPressed) { + SaveLevel(); + std::cout << "Level " << level << " Saved!" << std::endl; + } + } LoadLevelHandling(); } @@ -88,37 +98,38 @@ void Editor::RenderLevel() vf2d squarePos = vf2d{ (float)x,(float)y }*GRID_SIZE + center; if (game->GetMouseX() >= squarePos.x && game->GetMouseX() <= squarePos.x + GRID_SIZE.x && game->GetMouseY() >= squarePos.y && game->GetMouseY() <= squarePos.y + GRID_SIZE.y) { - if (game->GetKey(W).bPressed) { - t.wallN = !t.wallN; - if (y > 0) { - Tile& neighbor = map[y - 1][x]; - neighbor.wallS = t.wallN; + if (!game->IsTextEntryEnabled()) { + if (game->GetKey(W).bPressed) { + t.wallN = !t.wallN; + if (y > 0) { + Tile& neighbor = map[y - 1][x]; + neighbor.wallS = t.wallN; + } } - } - if (game->GetKey(D).bPressed) { - t.wallE = !t.wallE; - if (x < MAP_SIZE.x - 1) { - Tile& neighbor = map[y][x + 1]; - neighbor.wallW = t.wallE; + if (game->GetKey(D).bPressed) { + t.wallE = !t.wallE; + if (x < MAP_SIZE.x - 1) { + Tile& neighbor = map[y][x + 1]; + neighbor.wallW = t.wallE; + } } - } - if (game->GetKey(S).bPressed) { - t.wallS = !t.wallS; - if (y < MAP_SIZE.y - 1) { - Tile& neighbor = map[y + 1][x]; - neighbor.wallN = t.wallS; + if (game->GetKey(S).bPressed) { + t.wallS = !t.wallS; + if (y < MAP_SIZE.y - 1) { + Tile& neighbor = map[y + 1][x]; + neighbor.wallN = t.wallS; + } } - } - if (game->GetKey(A).bPressed) { - t.wallW = !t.wallW; - if (x > 0) { - Tile& neighbor = map[y][x - 1]; - neighbor.wallE = t.wallW; + if (game->GetKey(A).bPressed) { + t.wallW = !t.wallW; + if (x > 0) { + Tile& neighbor = map[y][x - 1]; + neighbor.wallE = t.wallW; + } } - } - if (game->GetMouse(0).bPressed) { - t.enemyId = selectedEnemy; - switch (waveLayer) { + if (game->GetMouse(0).bPressed) { + t.enemyId = selectedEnemy; + switch (waveLayer) { case 0: { t.wave1 = true; }break; @@ -128,13 +139,13 @@ void Editor::RenderLevel() case 2: { t.wave3 = true; }break; + } + if (t.enemyId == EnemyID::NONE) { + t.wave1 = t.wave2 = t.wave3 = false; + } } - if (t.enemyId == EnemyID::NONE) { - t.wave1 = t.wave2 = t.wave3 = false; - } - } - if (game->GetMouse(1).bPressed) { - switch (waveLayer) { + if (game->GetMouse(1).bPressed) { + switch (waveLayer) { case 0: { t.wave1 = false; }break; @@ -144,22 +155,23 @@ void Editor::RenderLevel() case 2: { t.wave3 = false; }break; + } + if (!(t.wave1 || t.wave2 || t.wave3)) { + t.enemyId = EnemyID::NONE; + } } - if (!(t.wave1 || t.wave2 || t.wave3)) { - t.enemyId = EnemyID::NONE; + if (game->GetKey(DOWN).bHeld) { + t.facingDir = FacingDirection::SOUTH; + } + if (game->GetKey(RIGHT).bHeld) { + t.facingDir = FacingDirection::EAST; + } + if (game->GetKey(UP).bHeld) { + t.facingDir = FacingDirection::NORTH; + } + if (game->GetKey(LEFT).bHeld) { + t.facingDir = FacingDirection::WEST; } - } - if (game->GetKey(DOWN).bHeld) { - t.facingDir = FacingDirection::SOUTH; - } - if (game->GetKey(RIGHT).bHeld) { - t.facingDir = FacingDirection::EAST; - } - if (game->GetKey(UP).bHeld) { - t.facingDir = FacingDirection::NORTH; - } - if (game->GetKey(LEFT).bHeld) { - t.facingDir = FacingDirection::WEST; } game->FillRectDecal(squarePos, GRID_SIZE, { 0,0,255,64 }); } @@ -201,15 +213,43 @@ void Editor::RenderLevel() void Editor::WaveLayerSelection() { - if (game->GetKey(K1).bPressed) { - waveLayer = 0; - } - if (game->GetKey(K2).bPressed) { - waveLayer = 1; + if (!game->IsTextEntryEnabled()) { + if (game->GetKey(K1).bPressed) { + waveLayer = 0; + } + if (game->GetKey(K2).bPressed) { + waveLayer = 1; + } + if (game->GetKey(K3).bPressed) { + waveLayer = 2; + } } - if (game->GetKey(K3).bPressed) { - waveLayer = 2; +} + +void Editor::SaveLevel() +{ + std::ofstream file("assets/map/map" + std::to_string(level) + ".map"); + file << MAP_SIZE.x << std::endl; + file << MAP_SIZE.y << std::endl; + for (int y = 0; y < MAP_SIZE.y; y++) { + for (int x = 0; x < MAP_SIZE.x; x++) { + int databits=0; + Tile& t = map[y][x]; + databits = + t.blink << 15 | + int(t.facingDir) << 13 | + int(t.enemyId) << 7 | + t.wave3 << 6 | + t.wave2 << 5 | + t.wave1 << 4 | + t.wallN << 3 | + t.wallE << 2 | + t.wallS << 1 | + t.wallW; + file << databits << std::endl; + } } + file.close(); } void Editor::OnTextEntryComplete(const std::string& sText) { @@ -222,7 +262,8 @@ void Editor::OnTextEntryComplete(const std::string& sText) { game->TextEntryEnable(false); promptState = PromptState::NONE; this->level = input; - LoadLevel(); + map = LoadLevel(this->level); + MAP_SIZE = { (int)map[0].size(),(int)map.size() }; } else { reEnableTextEntry = true; @@ -294,7 +335,8 @@ void Editor::OnTextEntryComplete(const std::string& sText) { } -void Editor::LoadLevel() { +std::vector> Editor::LoadLevel(int level) { + std::vector> map; std::ifstream file("assets/map/map"+std::to_string(level)+".map"); if (file.good()) { while (file.good()) { @@ -303,7 +345,7 @@ void Editor::LoadLevel() { int width = std::atoi(line.c_str()); std::getline(file, line); int height = std::atoi(line.c_str()); - MAP_SIZE = { width,height }; + vi2d MAP_SIZE = { width,height }; map.clear(); for (int y = 0; y < MAP_SIZE.y; y++) { std::vectorrow; @@ -325,11 +367,14 @@ void Editor::LoadLevel() { } map.push_back(row); } + goto loopDone; } + loopDone: + int a; } else { std::cout << "Map Level " << level << " does not exist. Creating default map."<row; @@ -339,4 +384,5 @@ void Editor::LoadLevel() { map.push_back(row); } } + return map; } \ No newline at end of file diff --git a/Faceball2030/Editor.h b/Faceball2030/Editor.h index 3316e1c..5a62a1c 100644 --- a/Faceball2030/Editor.h +++ b/Faceball2030/Editor.h @@ -58,8 +58,8 @@ struct Tile { }; class Editor { - int level; - vi2d MAP_SIZE; + int level=1; + vi2d MAP_SIZE = { 1,1 }; bool reEnableTextEntry; //We must set this to true to cause Text Entry to reappear due to how the callback works. std::vector> map; const vi2d GRID_SIZE = { 32,32 }; @@ -67,12 +67,14 @@ class Editor { PromptState promptState = PromptState::NONE; int waveLayer = 0; public: - Editor() {} + Editor(); void Update(float fElapsedTime); + std::vector> LoadLevel(int level); void OnTextEntryComplete(const std::string& sText); - void LoadLevel(); + private: void LoadLevelHandling(); void MouseWheelEnemySelection(); void RenderLevel(); void WaveLayerSelection(); + void SaveLevel(); }; \ No newline at end of file diff --git a/Faceball2030/Faceball2030.vcxproj b/Faceball2030/Faceball2030.vcxproj index cb2ba81..43c66da 100644 --- a/Faceball2030/Faceball2030.vcxproj +++ b/Faceball2030/Faceball2030.vcxproj @@ -104,7 +104,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - stdcpp14 + stdcpp17 Console @@ -133,6 +133,7 @@ + diff --git a/Faceball2030/Faceball2030.vcxproj.filters b/Faceball2030/Faceball2030.vcxproj.filters index 65b2820..8b60ef9 100644 --- a/Faceball2030/Faceball2030.vcxproj.filters +++ b/Faceball2030/Faceball2030.vcxproj.filters @@ -32,5 +32,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/Faceball2030/assets/dot.png b/Faceball2030/assets/dot.png index c4a2634fcff19fb046fe3167ac0586e2090d379a..2cad3f19ca46729bbc965523c9d3bc5bb8eac503 100644 GIT binary patch delta 512 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 Ibl4O3Z#Zus`~Uy| diff --git a/Faceball2030/assets/map/map1.map b/Faceball2030/assets/map/map1.map index 70f56f3..749765c 100644 --- a/Faceball2030/assets/map/map1.map +++ b/Faceball2030/assets/map/map1.map @@ -1,6 +1,34 @@ -2 -2 -41126 -41126 -41126 -41126 \ No newline at end of file +8 +4 +33195 +32778 +8200 +8204 +8203 +8202 +8200 +8204 +40969 +32776 +0 +8194 +8618 +8202 +8198 +8197 +8193 +8192 +8198 +8617 +8200 +8202 +8202 +8198 +8195 +16662 +8207 +8195 +8194 +8202 +8202 +8206 diff --git a/Faceball2030/geometry2d.h b/Faceball2030/geometry2d.h new file mode 100644 index 0000000..c34649c --- /dev/null +++ b/Faceball2030/geometry2d.h @@ -0,0 +1,1050 @@ +/* + OneLoneCoder - Geometry 2D v1.01 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + A collection of 2D Geometric primitives and functions to work with + and between them. + + + License (OLC-3) + ~~~~~~~~~~~~~~~ + + Copyright 2018 - 2022 OneLoneCoder.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions or derivations of source code must retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions or derivative works in binary form must reproduce + the above copyright notice. This list of conditions and the following + disclaimer must be reproduced in the documentation and/or other + materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Links + ~~~~~ + YouTube: https://www.youtube.com/javidx9 + Discord: https://discord.gg/WhwHUMV + Twitter: https://www.twitter.com/javidx9 + Twitch: https://www.twitch.tv/javidx9 + GitHub: https://www.github.com/onelonecoder + Homepage: https://www.onelonecoder.com + + Author + ~~~~~~ + David Barr, aka javidx9, �OneLoneCoder 2019, 2020, 2021, 2022 + + Changes: + v1.01: +Made constants inline + +Header guards (lol... sigh...) + +*/ + +#pragma once +#include "pixelGameEngine.h" + +namespace olc::utils::geom2d +{ + // Lemon Meringue + inline const double pi = 3.141592653589793238462643383279502884; + + // Floating point error margin + inline const double epsilon = 0.001; + + //https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c + template + constexpr int sgn(T val) { return (T(0) < val) - (val < T(0)); } + + // Defines a line segment + template + struct line + { + olc::v2d_generic start; + olc::v2d_generic end; + + inline line(const olc::v2d_generic& s = { T(0), T(0) }, + const olc::v2d_generic& e = { T(0), T(0) }) + : start(s), end(e) + { } + + + // Get length of line + inline constexpr T length() + { + return (end - start).mag(); + } + + // Get length of line^2 + inline constexpr T length2() + { + return (end - start).mag2(); + } + + inline constexpr olc::v2d_generic vector() const + { + return (end - start); + } + + // Given a real distance, get point along line + inline constexpr olc::v2d_generic rpoint(const T& distance) const + { + return start + (end - start).norm() * distance; + } + + // Given a unit distance, get point along line + inline constexpr olc::v2d_generic upoint(const T& distance) const + { + return start + (end - start) * distance; + } + + // Return which side of the line does a point lie + inline constexpr int32_t side(const olc::v2d_generic& point) const + { + double d = (end - start).cross(point - start); + if (d < 0) + return -1; + else + if (d > 0) + return 1; + else + return 0; + } + }; + + template + struct ray + { + olc::v2d_generic origin; + olc::v2d_generic direction; + }; + + template + struct rect + { + olc::v2d_generic pos; + olc::v2d_generic size; + + inline rect(const olc::v2d_generic& p = { T(0), T(0) }, + const olc::v2d_generic& s = { T(1), T(1) }) + : pos(p), size(s) + { } + + inline olc::v2d_generic middle() const + { + return pos + (size * double(0.5)); + } + + // Get line segment from top side of rectangle + inline line top() const + { + return { pos, {pos.x + size.x, pos.y } }; + } + + // Get line segment from bottom side of rectangle + inline line bottom() const + { + return { {pos.x, pos.y + size.y}, pos + size }; + } + + // Get line segment from left side of rectangle + inline line left() const + { + return { pos, {pos.x, pos.y + size.y} }; + } + + // Get line segment from right side of rectangle + inline line right() const + { + return { {pos.x + size.x, pos.y }, pos + size }; + } + + // Get a line from an indexed side, starting top, going clockwise + inline line side(const size_t i) const + { + if (i & 0b11 == 0) return top(); + if (i & 0b11 == 1) return right(); + if (i & 0b11 == 2) return bottom(); + if (i & 0b11 == 3) return left(); + } + + // Get area of rectangle + inline constexpr T area() const + { + return size.x * size.y; + } + + // Get perimeter of rectangle + inline constexpr T perimeter() const + { + return T(2) * (size.x + size.y); + } + }; + + + template + struct circle + { + olc::v2d_generic pos; + T radius = T(0); + + inline circle(const olc::v2d_generic& p = { T(0), T(0) }, const T r = T(0)) + : pos(p), radius(r) + { } + + // Get area of circle + inline constexpr T area() const + { + return T(pi) * radius * radius; + } + + // Get circumference of circle + inline constexpr T perimeter() const + { + return T(2.0 * pi) * radius; + } + + // Get circumference of circle + inline constexpr T circumference() const + { + return perimeter(); + } + + friend std::ostream& operator << (std::ostream& os, const circle& rhs) { os << rhs.pos << "(r:" << rhs.radius << ")"; return os; } + }; + + + template + struct triangle + { + std::array, 3> pos; + + inline triangle( + const olc::v2d_generic& p0 = { T(0), T(0) }, + const olc::v2d_generic& p1 = { T(0), T(0) }, + const olc::v2d_generic& p2 = { T(0), T(0) }) + : pos{ p0,p1,p2 } + { } + + // Get a line from an indexed side, starting top, going clockwise + inline line side(const size_t i) const + { + return line(pos[i % 3], pos[(i + 1) % 3]); + } + + // Get area of triangle + inline constexpr T area() const + { + return double(0.5) * std::abs( + (pos[0].x * (pos[1].y - pos[2].y)) + + (pos[1].x * (pos[2].y - pos[0].y)) + + (pos[2].x * (pos[0].y - pos[1].y))); + } + + // Get perimeter of triangle + inline constexpr T perimeter() const + { + return line(pos[0], pos[1]).length() + + line(pos[1], pos[2]).length() + + line(pos[2], pos[0]).length(); + } + }; + + + template + struct polygon + { + std::vector> vPoints; + }; + + + // ========================================================================================================================= + // Closest(shape, point) =================================================================================================== + + // Returns closest point to point + template + inline olc::v2d_generic closest(const olc::v2d_generic& p1, const olc::v2d_generic& p2) + { + return p1; + } + + // Returns closest point on line to point + template + inline olc::v2d_generic closest(const line& l, const olc::v2d_generic& p) + { + auto d = l.vector(); + double u = std::clamp(double(d.dot(p - l.start)) / d.mag2(), 0.0, 1.0); + return l.start + u * d; + } + + // Returns closest point on circle to point + template + inline olc::v2d_generic closest(const circle& c, const olc::v2d_generic& p) + { + return c.pos + olc::vd2d(p - c.pos).norm() * c.radius; + } + + // Returns closest point on rectangle to point + template + inline olc::v2d_generic closest(const rect& r, const olc::v2d_generic& p) + { + // This could be a "constrain" function hmmmm + // TODO: Not quite what i wanted, should restrain to boundary + return olc::v2d_generic{ std::clamp(p.x, r.pos.x, r.pos.x + r.size.x), std::clamp(p.y, r.pos.y, r.pos.y + r.size.y) }; + + } + + // Returns closest point on triangle to point + template + inline olc::v2d_generic closest(const triangle& t, const olc::v2d_generic& p) + { + olc::utils::geom2d::line l{ t.pos[0], t.pos[1] }; + auto p0 = closest(l, p); + auto d0 = (p0 - p).mag2(); + + l.end = t.pos[2]; + auto p1 = closest(l, p); + auto d1 = (p1 - p).mag2(); + + l.start = t.pos[1]; + auto p2 = closest(l, p); + auto d2 = (p2 - p).mag2(); + + if ((d0 <= d1) && (d0 <= d2)) { + return p0; + } + else if ((d1 <= d0) && (d1 <= d2)) { + return p1; + } + else { + return p2; + } + } + + + + + + + + + + + + // ================================================================================================================ + // POINT ========================================================================================================== + + // Checks if point contains point + template + inline constexpr bool contains(const olc::v2d_generic& p1, const olc::v2d_generic& p2) + { + return (p1 - p2).mag2() < epsilon; + } + + // Checks if line contains point + template + inline constexpr bool contains(const line& l, const olc::v2d_generic& p) + { + double d = ((p.x - l.start.x) * (l.end.y - l.start.y) - (p.y - l.start.y) * (l.end.x - l.start.x)); + if (std::abs(d) < epsilon) + { + // point is on line + double u = l.vector().dot(p - l.start) / l.vector().mag2(); + return (u >= double(0.0) && u <= double(1.0)); + } + + return false; + } + + // Checks if rectangle contains point + template + inline constexpr bool contains(const rect& r, const olc::v2d_generic& p) + { + return !(p.x < r.pos.x || p.y < r.pos.y || + p.x >(r.pos.x + r.size.x) || p.y >(r.pos.y + r.size.y)); + } + + // Checks if circle contains a point + template + inline constexpr bool contains(const circle& c, const olc::v2d_generic& p) + { + return (c.pos - p).mag2() < (c.radius * c.radius); + } + + // Checks if triangle contains a point + template + inline constexpr bool contains(const triangle& t, const olc::v2d_generic& p) + { + // http://jsfiddle.net/PerroAZUL/zdaY8/1/ + T2 A = T2(0.5) * (-t.pos[1].y * t.pos[2].x + t.pos[0].y * (-t.pos[1].x + t.pos[2].x) + t.pos[0].x * (t.pos[1].y - t.pos[2].y) + t.pos[1].x * t.pos[2].y); + T2 sign = A < T2(0) ? T2(-1) : T2(1); + T2 s = (t.pos[0].y * t.pos[2].x - t.pos[0].x * t.pos[2].y + (t.pos[2].y - t.pos[0].y) * p.x + (t.pos[0].x - t.pos[2].x) * p.y) * sign; + T2 v = (t.pos[0].x * t.pos[1].y - t.pos[0].y * t.pos[1].x + (t.pos[0].y - t.pos[1].y) * p.x + (t.pos[1].x - t.pos[0].x) * p.y) * sign; + return s > T2(0) && v > T2(0) && (s + v) < T2(2) * A * sign; + } + + + + + // Check if point overlaps with point (analagous to contains()) + template + inline constexpr bool overlaps(const olc::v2d_generic& p1, const olc::v2d_generic& p2) + { + return contains(p1, p2); + } + + // Checks if line segment overlaps with point + template + inline constexpr bool overlaps(const line& l, const olc::v2d_generic& p) + { + return contains(l, p); + } + + // Checks if rectangle overlaps with point + template + inline constexpr bool overlaps(const rect& r, const olc::v2d_generic& p) + { + return contains(r, p); + } + + // Checks if circle overlaps with point + template + inline constexpr bool overlaps(const circle& c, const olc::v2d_generic& p) + { + return contains(c, p); + } + + // Checks if triangle overlaps with point + template + inline constexpr bool overlaps(const triangle& t, const olc::v2d_generic& p) + { + return contains(t, p); + } + + + + + // Get intersection points where point intersects with point + template + inline std::vector> intersects(const olc::v2d_generic& p1, const olc::v2d_generic& p2) + { + if (contains(p1, p2)) + return { p1 }; + else + return {}; + } + + // Get intersection points where line segment intersects with point + template + inline std::vector> intersects(const line& l, const olc::v2d_generic& p) + { + if (contains(l, p)) + return { p }; + else + return {}; + } + + // Get intersection points where rectangle intersects with point + template + inline std::vector> intersects(const rect& r, const olc::v2d_generic& p) + { + std::vector> vPoints; + if (contains(r.top(), p)) vPoints.push_back(p); + if (contains(r.bottom(), p)) vPoints.push_back(p); + if (contains(r.left(), p)) vPoints.push_back(p); + if (contains(r.right(), p)) vPoints.push_back(p); + return vPoints; + } + + // Get intersection points where circle intersects with point + template + inline std::vector> intersects(const circle& c, const olc::v2d_generic& p) + { + if (std::abs((p - c.pos).mag2() - (c.radius * c.radius)) <= epsilon) + return { p }; + else + return {}; + } + + // Get intersection points where triangle intersects with point + template + inline std::vector> intersects(const triangle& r, const olc::v2d_generic& p) + { + // TODO: + return {}; + } + + + + + + + + + + + + + // ================================================================================================================ + // LINE =========================================================================================================== + + // Check if point contains line segment + template + inline constexpr bool contains(const olc::v2d_generic& p, const line& l) + { + return false; // It can't! + } + + // Check if line segment contains line segment + template + inline constexpr bool contains(const line& l1, const line& l2) + { + // TODO: Check if segments are colinear, and l1 exists within bounds of l2 + return false; + } + + // Check if rectangle contains line segment + template + inline constexpr bool contains(const rect& r, const line& l) + { + return contains(r, l.start) && contains(r, l.end); + } + + // Check if circle contains line segment + template + inline constexpr bool contains(const circle& c1, const line& l) + { + return contains(c1, l.start) && contains(c1, l.end); + } + + // Check if triangle contains line segment + template + inline constexpr bool contains(const triangle& t, const line& l) + { + return contains(t, l.start) && contains(t, l.end); + } + + + + + // Check if point overlaps line segment + template + inline constexpr bool overlaps(const olc::v2d_generic& p, const line& l) + { + return contains(l, p); + } + + // Check if line segment overlaps line segment + template + inline constexpr bool overlaps(const line& l1, const line& l2) + { + // TODO: + return false; + } + + // Check if rectangle overlaps line segment + template + inline constexpr bool overlaps(const rect& r, const line& l) + { + return contains(r, l.start) + || contains(r, l.end); + + // TODO: This method is no good, it cant detect lines whose start and end + // points are outside the rectangle + } + + // Check if circle overlaps line segment + template + inline constexpr bool overlaps(const circle& c, const line& l) + { + // TODO: + return false; + } + + // Check if triangle overlaps line segment + template + inline constexpr bool overlaps(const triangle& t, const line& l) + { + return overlaps(t, l.start) || overlaps(t, l.end); + + // TODO: This method is no good, it cant detect lines whose start and end + // points are outside the triangle + } + + + + + // Get intersection points where point intersects with line segment + template + inline std::vector> intersects(const olc::v2d_generic& p, const line& l) + { + // TODO: + return {}; + } + + // Get intersection points where line segment intersects with line segment + template + inline std::vector> intersects(const line& l1, const line& l2) + { + // TODO: + return {}; + } + + // Get intersection points where rectangle intersects with line segment + template + inline std::vector> intersects(const rect& r, const line& l) + { + // TODO: + return {}; + } + + // Get intersection points where circle intersects with line segment + template + inline std::vector> intersects(const circle& c, const line& l) + { + // TODO: + return {}; + } + + // Get intersection points where triangle intersects with line segment + template + inline std::vector> intersects(const triangle& t, const line& l) + { + // TODO: + return {}; + } + + + + + + + + + + + + + // ================================================================================================================ + // RECTANGLE ====================================================================================================== + + // Check if point contains rectangle + template + inline constexpr bool contains(const olc::v2d_generic& p, const rect& r) + { + return false; // It can't! + } + + // Check if line segment contains rectangle + template + inline constexpr bool contains(const line& l, const rect& r) + { + return false; // It can't + } + + // Check if rectangle contains rectangle + template + inline constexpr bool contains(const rect& r1, const rect& r2) + { + return (r2.pos.x >= r1.pos.x) && (r2.pos.x + r2.size.x < r1.pos.x + r1.size.x) && + (r2.pos.y >= r1.pos.y) && (r2.pos.y + r2.size.y < r1.pos.y + r1.size.y); + } + + // Check if circle contains rectangle + template + inline constexpr bool contains(const circle& c, const rect& r) + { + return contains(c, r.pos) + && contains(c, olc::v2d_generic{ r.pos.x + r.size.x, r.pos.y }) + && contains(c, olc::v2d_generic{ r.pos.x, r.pos.y + r.size.y }) + && contains(c, r.pos + r.size); + } + + // Check if triangle contains rectangle + template + inline constexpr bool contains(const triangle& t, const rect& r) + { + return contains(t, r.pos) + && contains(t, r.pos + r.size) + && contains(t, olc::v2d_generic{ r.pos.x + r.size.x, r.pos.y }) + && contains(t, olc::v2d_generic{ r.pos.x, r.pos.y + r.size.y }); + } + + + + + // Check if point overlaps rectangle + template + inline constexpr bool overlaps(const olc::v2d_generic& p, const rect& r) + { + return overlaps(r, p); + } + + // Check if line segment overlaps rectangle + template + inline constexpr bool overlaps(const line& l, const rect& r) + { + return overlaps(r, l); + } + + // Check if rectangle overlaps rectangle + template + inline constexpr bool overlaps(const rect& r1, const rect& r2) + { + return (r1.pos.x < r2.pos.x + r2.size.x && r1.pos.x + r1.size.x >= r2.pos.x && + r1.pos.y < r2.pos.y + r2.size.y && r1.pos.y + r1.size.y >= r2.pos.y); + } + + // Check if circle overlaps rectangle + template + inline constexpr bool overlaps(const circle& c, const rect& r) + { + // Inspired by this (very clever btw) + // https://stackoverflow.com/questions/45370692/circle-rectangle-collision-response + // But modified to work :P + T2 overlap = (olc::v2d_generic{ std::clamp(c.pos.x, r.pos.x, r.pos.x + r.size.x), std::clamp(c.pos.y, r.pos.y, r.pos.y + r.size.y) } - c.pos).mag2(); + if (std::isnan(overlap)) overlap = T2(0); + return (overlap - (c.radius * c.radius)) < T2(0); + } + + // Check if triangle overlaps rectangle + template + inline constexpr bool overlaps(const triangle& t, const rect& r) + { + return contains(t, r.pos) + || contains(t, r.pos + r.size) + || contains(t, olc::v2d_generic{ r.pos.x + r.size.x, r.pos.y }) + || contains(t, olc::v2d_generic{ r.pos.x, r.pos.y + r.size.y }); + + // TODO: This method is no good, consider rectangle with all vertices + // outside of triangle, but edges still crossing + } + + + + + // Get intersection points where point intersects with rectangle + template + inline std::vector> intersects(const olc::v2d_generic& p, const rect& r) + { + return intersects(r, p); + } + + // Get intersection points where line segment intersects with rectangle + template + inline std::vector> intersects(const line& l, const rect& r) + { + // TODO: + return {}; + } + + // Get intersection points where rectangle intersects with rectangle + template + inline std::vector> intersects(const rect& r1, const rect& r2) + { + // TODO: + return {}; + } + + // Get intersection points where circle intersects with rectangle + template + inline std::vector> intersects(const circle& c, const rect& r) + { + // TODO: + return {}; + } + + // Get intersection points where triangle intersects with rectangle + template + inline std::vector> intersects(const triangle& t, const rect& r) + { + // TODO: + return {}; + } + + + + + + + + + + + + + + // ================================================================================================================ + // CIRCLE ========================================================================================================= + + // Check if point contains circle + template + inline constexpr bool contains(const olc::v2d_generic& p, const circle& c) + { + return false; // It can't! + } + + // Check if line segment contains circle + template + inline constexpr bool contains(const line& l, const circle& c) + { + return false; // It can't! + } + + // Check if rectangle contains circle + template + inline constexpr bool contains(const rect& r, const circle& c) + { + // TODO: + return false; + } + + // Check if circle contains circle + template + inline constexpr bool contains(const circle& c1, const circle& c2) + { + return (c1.pos - c2.pos).mag2() <= (c1.radius - c2.radius) * (c1.radius - c2.radius); + } + + // Check if triangle contains circle + template + inline constexpr bool contains(const triangle& t, const circle& c) + { + // TODO: + return false; + } + + + + + // Check if point overlaps circle + template + inline constexpr bool overlaps(const olc::v2d_generic& p, const circle& c) + { + return overlaps(c, p); + } + + // Check if line segment overlaps circle + template + inline constexpr bool overlaps(const line& l, const circle& c) + { + return overlaps(c, l); + } + + // Check if rectangle overlaps circle + template + inline constexpr bool overlaps(const rect& r, const circle& c) + { + return overlaps(c, r); + } + + // Check if circle overlaps circle + template + inline constexpr bool overlaps(const circle& c1, const circle& c2) + { + return (c1.pos - c2.pos).mag2() <= (c1.radius + c2.radius) * (c1.radius + c2.radius); + } + + // Check if triangle overlaps circle + template + inline constexpr bool overlaps(const triangle& t, const circle& c) + { + // TODO: + return false; + } + + + + + // Get intersection points where point intersects with circle + template + inline std::vector> intersects(const olc::v2d_generic& p, const circle& c) + { + // TODO: + return {}; + } + + // Get intersection points where line segment intersects with circle + template + inline std::vector> intersects(const line& l, const circle& c) + { + // TODO: + return {}; + } + + // Get intersection points where rectangle intersects with circle + template + inline std::vector> intersects(const rect& r, const circle& c) + { + // TODO: + return {}; + } + + // Get intersection points where circle intersects with circle + template + inline std::vector> intersects(const circle& c1, const circle& c2) + { + // TODO: + return {}; + } + + // Get intersection points where triangle intersects with circle + template + inline std::vector> intersects(const triangle& t, const circle& c) + { + // TODO: + return {}; + } + + + + + + + + + + + + + + // ================================================================================================================ + // TRIANGLE ======================================================================================================= + + // Check if point contains triangle + template + inline constexpr bool contains(const olc::v2d_generic& p, const triangle& t) + { + return false; // It can't! + } + + // Check if line segment contains triangle + template + inline constexpr bool contains(const line& l, const triangle& t) + { + return false; // It can't + } + + // Check if rectangle contains triangle + template + inline constexpr bool contains(const rect& r, const triangle& t) + { + // TODO: + return false; + } + + // Check if circle contains triangle + template + inline constexpr bool contains(const circle& c, const triangle& t) + { + // TODO: + return false; + } + + // Check if triangle contains triangle + template + inline constexpr bool contains(const triangle& t1, const triangle& t2) + { + // TODO: + return false; + } + + + + + // Check if point overlaps triangle + template + inline constexpr bool overlaps(const olc::v2d_generic& p, const triangle& t) + { + return overlaps(t, p); + } + + // Check if line segment overlaps triangle + template + inline constexpr bool overlaps(const line& l, const triangle& t) + { + return overlaps(t, l); + } + + // Check if rectangle overlaps triangle + template + inline constexpr bool overlaps(const rect& r, const triangle& t) + { + return overlaps(t, r); + } + + // Check if circle overlaps triangle + template + inline constexpr bool overlaps(const circle& c, const triangle& t) + { + return overlaps(t, c); + } + + // Check if triangle overlaps triangle + template + inline constexpr bool overlaps(const triangle& t1, const triangle& t2) + { + // TODO: + return false; + } + + + + + // Get intersection points where point intersects with triangle + template + inline std::vector> intersects(const olc::v2d_generic& p, const triangle& t) + { + // TODO: + return {}; + } + + // Get intersection points where line segment intersects with triangle + template + inline std::vector> intersects(const line& l, const triangle& t) + { + // TODO: + return {}; + } + + // Get intersection points where rectangle intersects with triangle + template + inline std::vector> intersects(const rect& r, const triangle& t) + { + // TODO: + return {}; + } + + // Get intersection points where circle intersects with triangle + template + inline std::vector> intersects(const circle& c, const triangle& t) + { + // TODO: + return {}; + } + + // Get intersection points where triangle intersects with triangle + template + inline std::vector> intersects(const triangle& t1, const triangle& t2) + { + // TODO: + return {}; + } + +} \ No newline at end of file diff --git a/Faceball2030/main.cpp b/Faceball2030/main.cpp index 6f0968f..a311624 100644 --- a/Faceball2030/main.cpp +++ b/Faceball2030/main.cpp @@ -1,5 +1,6 @@ #define OLC_PGE_APPLICATION #include "pixelGameEngine.h" +#include "geometry2d.h" #include #include #include "main.h" @@ -23,6 +24,113 @@ void FaceBall::InitializeEnemyData() { enemyData[AREA_MAP] = { "Map",GREEN }; } +void FaceBall::LoadLevel(int level) +{ + this->level = level; + std::vector>mapData = editor.LoadLevel(level); + MAP_SIZE = { (int)mapData[0].size(),(int)mapData.size() }; + map.clear(); + mapMesh.tris.clear(); + objects.clear(); + for (int y = 0; y < MAP_SIZE.y; y++) { + std::vectorrow; + for (int x = 0; x < MAP_SIZE.x; x++) { + row.push_back({}); + mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y}},{{0,0},{1,0},{0,1}},BLUE }); + mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y + 1}},{{0,0},{1,0},{0,1}},BLUE }); + } + map.push_back(row); + } + for (int y = 0; y < MAP_SIZE.y; y++) { + for (int x = 0; x < MAP_SIZE.x; x++) { + int wallData = 0; + if (mapData[y][x].wallN) { + wallData |= NORTH; + } + if (mapData[y][x].wallE) { + wallData |= EAST; + } + if (mapData[y][x].wallS) { + wallData |= SOUTH; + } + if (mapData[y][x].wallW) { + wallData |= WEST; + } + AddWall(wallData, { x,y }); + if (map[y][x].wallN != NULL) { + mapMesh.tris.push_back({ {{(float)x,1,(float)y},{(float)x,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},YELLOW }); + mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x + 1,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},YELLOW }); + } + if (map[y][x].wallS != NULL) { + mapMesh.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x,0,(float)y + 1},{(float)x,1,(float)y + 1}},{{0,0},{1,0},{0,1}},DARK_RED }); + mapMesh.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x + 1,0,(float)y + 1},{(float)x,0,(float)y + 1}},{{0,0},{1,0},{0,1}},DARK_RED }); + } + if (map[y][x].wallW != NULL) { + mapMesh.tris.push_back({ {{(float)x,1,(float)y},{(float)x,1,(float)y + 1}, {(float)x,0,(float)y + 1}},{{0,0},{1,0},{0,1}},MAGENTA }); + mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x,1,(float)y}, {(float)x,0,(float)y + 1}}, {{0,0},{1,0},{0,1}},MAGENTA }); + } + if (map[y][x].wallE != NULL) { + mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y + 1},{(float)x + 1,1,(float)y + 1},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},CYAN }); + mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y + 1} ,{(float)x + 1,1,(float)y},{(float)x + 1,0,(float)y}},{{0,0},{1,0},{0,1}},CYAN }); + } + } + } + objects.push_back({ mapMesh }); +} + +bool FaceBall::CheckCollision(vec3d movementVector){ + utils::geom2d::circlenewPos{ {player.GetPos().x + movementVector.x,player.GetPos().z + movementVector.z},player.GetRadius() }; + bool collisionOccured = false; + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + int offsetX = (int)player.GetPos().x + x; + int offsetY = (int)player.GetPos().z + y; + if (offsetX >= 0 && offsetX < MAP_SIZE.x && offsetY >= 0 && offsetY < MAP_SIZE.y) { + MapSquare tile = map[offsetY][offsetX]; + if (tile.wallN != NULL) { + utils::geom2d::linewall{ {(float)offsetX,(float)offsetY},{(float)offsetX+1,(float)offsetY} }; + if (((int)(newPos.pos.x-player.GetRadius())==offsetX|| + (int)(newPos.pos.x + player.GetRadius()) == offsetX) + && + newPos.pos.y > wall.start.y && wall.start.y > newPos.pos.y - player.GetRadius()) { + collisionOccured = true; + goto breakOutOfCollisionLoop; + } + } + if (tile.wallE != NULL) { + utils::geom2d::linewall{ {(float)offsetX+1,(float)offsetY},{(float)offsetX + 1,(float)offsetY+1} }; + if (((int)(newPos.pos.y - player.GetRadius()) == offsetY || + (int)(newPos.pos.y + player.GetRadius()) == offsetY) + && newPos.pos.xwall{ {(float)offsetX,(float)offsetY+1},{(float)offsetX + 1,(float)offsetY+1} }; + if (((int)(newPos.pos.x - player.GetRadius()) == offsetX || + (int)(newPos.pos.x + player.GetRadius()) == offsetX) + && newPos.pos.y < wall.start.y && wall.start.y < newPos.pos.y + player.GetRadius()) { + collisionOccured = true; + goto breakOutOfCollisionLoop; + } + } + if (tile.wallW != NULL) { + utils::geom2d::linewall{ {(float)offsetX,(float)offsetY},{(float)offsetX,(float)offsetY + 1} }; + if (((int)(newPos.pos.y - player.GetRadius()) == offsetY || + (int)(newPos.pos.y + player.GetRadius()) == offsetY) + && newPos.pos.x > wall.start.x && wall.start.x > newPos.pos.x - player.GetRadius()) { + collisionOccured = true; + goto breakOutOfCollisionLoop; + } + } + } + } + } + breakOutOfCollisionLoop: + return collisionOccured; +} + EnemyData FaceBall::GetData(EnemyID id) { return enemyData[id]; @@ -364,8 +472,8 @@ void FaceBall::RenderWorld() { vec3d vTarget = { 0,sinf(pitch),cosf(pitch) }; mat4x4 matCameraRot = Matrix_MakeRotationY(fYaw); vLookDir = Matrix_MultiplyVector(matCameraRot, vTarget); - vTarget = Vector_Add(vCamera, vLookDir); - mat4x4 matCamera = Matrix_PointAt(vCamera, vTarget, vUp); + vTarget = Vector_Add(player.GetPos(), vLookDir); + mat4x4 matCamera = Matrix_PointAt(player.GetPos(), vTarget, vUp); mat4x4 matView = Matrix_QuickInverse(matCamera); std::vectorvecTrianglesToRaster; @@ -397,7 +505,7 @@ void FaceBall::RenderWorld() { normal = Vector_CrossProduct(line1, line2); normal = Vector_Normalise(normal); - vec3d vCameraRay = Vector_Sub(triTransformed.p[0], vCamera); + vec3d vCameraRay = Vector_Sub(triTransformed.p[0], player.GetPos()); if (Vector_DotProduct(normal, vCameraRay) < 0) { vec3d light_dir = Vector_Mul(vLookDir, -1); @@ -545,23 +653,38 @@ void FaceBall::RenderWorld() { } void FaceBall::HandleKeys(float fElapsedTime) { - vec3d vForward = Vector_Mul(vLookDir, 2 * fElapsedTime); + vec3d vForward = Vector_Mul(vLookDir, std::min(player.GetRadius()-0.00001f,2*fElapsedTime)); if (freeRoam) { - if (GetKey(olc::DOWN).bHeld) { + if (GetKey(DOWN).bHeld) { pitch -= 1 * fElapsedTime; } - if (GetKey(olc::UP).bHeld) { + if (GetKey(UP).bHeld) { pitch += 1 * fElapsedTime; } } else { pitch = 0; } - if (GetKey(olc::W).bHeld) { - vCamera = Vector_Add(vCamera, vForward); + if (GetKey(W).bHeld) { + if (!CheckCollision({ vForward.x,0,0 })) { + vec3d xMovement{ vForward.x,0,0 }; + player.UpdatePos(Vector_Add(player.GetPos(), xMovement)); + } + if (!CheckCollision({0,0,vForward.z})) { + vec3d zMovement{ 0,0,vForward.z }; + player.UpdatePos(Vector_Add(player.GetPos(), zMovement)); + } } - if (GetKey(olc::S).bHeld) { - vCamera = Vector_Sub(vCamera, vForward); + if (GetKey(S).bHeld) { + vec3d vReverse = { -vForward.x,-vForward.y,-vForward.z }; + if (!CheckCollision({ vReverse.x,0,0 })) { + vec3d xMovement{ vReverse.x,0,0 }; + player.UpdatePos(Vector_Add(player.GetPos(), xMovement)); + } + if (!CheckCollision({ 0,0,vReverse.z })) { + vec3d zMovement{ 0,0,vReverse.z }; + player.UpdatePos(Vector_Add(player.GetPos(), zMovement)); + } } if (GetKey(olc::A).bHeld) { fYaw -= 2 * fElapsedTime; @@ -574,7 +697,7 @@ void FaceBall::HandleKeys(float fElapsedTime) { } } -void FaceBall::AddWall(Direction dir, vi2d gridSquare) { +void FaceBall::AddWall(int dir, vi2d gridSquare) { if (dir & NORTH) { map[gridSquare.y][gridSquare.x].wallN = dot; if (gridSquare.y > 0) { @@ -615,99 +738,8 @@ bool FaceBall::OnUserCreate() Mesh testEnemy("assets/enemies/ShootMe.obj", enemy_ShootMe_tex); mapMesh.texture = dot; - for (int i = 0; i < 75; i++) { - Object newEnemy({ testEnemy,{ float(rand() % 20),float(rand() % 20) }, (rand() % 1000) / 1000.f * 2 * PI }); - objects.push_back(newEnemy); - } - - for (int y = 0; y < MAP_SIZE.y; y++) { - std::vectorrow; - for (int x = 0; x < MAP_SIZE.x; x++) { - row.push_back({}); - mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y}},{{0,0},{1,0},{0,1}},BLUE }); - mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y + 1}},{{0,0},{1,0},{0,1}},BLUE }); - } - map.push_back(row); - } - - for (int y = 0; y < MAP_SIZE.y; y++) { - for (int x = 0; x < MAP_SIZE.x; x++) { - switch (rand() % 16) { - case 0: {//No Wall. - - }break; - case 1: {//North Wall. - AddWall(NORTH, { x,y }); - }break; - case 2: {//East Wall. - AddWall(EAST, { x,y }); - }break; - case 3: {//South Wall. - AddWall(SOUTH, { x,y }); - }break; - case 4: {//West Wall. - AddWall(WEST, { x,y }); - }break; - case 5: {//NE Wall. - AddWall(Direction(NORTH | EAST), { x,y }); - }break; - case 6: { - AddWall(Direction(NORTH | WEST), { x,y }); - }break; - case 7: { - AddWall(Direction(SOUTH | EAST), { x,y }); - }break; - case 8: { - AddWall(Direction(SOUTH | WEST), { x,y }); - }break; - case 9: { - AddWall(Direction(NORTH | SOUTH), { x,y }); - }break; - case 10: { - AddWall(Direction(EAST | WEST), { x,y }); - }break; - case 11: { - AddWall(Direction(NORTH | WEST | EAST), { x,y }); - }break; - case 12: { - AddWall(Direction(NORTH | WEST | SOUTH), { x,y }); - }break; - case 13: { - AddWall(Direction(WEST | SOUTH | EAST), { x,y }); - }break; - case 14: { - AddWall(Direction(SOUTH | EAST | NORTH), { x,y }); - }break; - case 15: { - AddWall(Direction(SOUTH | EAST | NORTH | WEST), { x,y }); - }break; - } - } - } - AddWall(Direction(SOUTH | EAST | NORTH | WEST), { 0,0 }); - - for (int y = 0; y < MAP_SIZE.y; y++) { - for (int x = 0; x < MAP_SIZE.x; x++) { - if (map[y][x].wallN != NULL) { - mapMesh.tris.push_back({ {{(float)x,1,(float)y},{(float)x,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},YELLOW }); - mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x + 1,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},YELLOW }); - } - if (map[y][x].wallS != NULL) { - mapMesh.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x,0,(float)y + 1},{(float)x,1,(float)y + 1}},{{0,0},{1,0},{0,1}},DARK_RED }); - mapMesh.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x + 1,0,(float)y + 1},{(float)x,0,(float)y + 1}},{{0,0},{1,0},{0,1}},DARK_RED }); - } - if (map[y][x].wallW != NULL) { - mapMesh.tris.push_back({ {{(float)x,1,(float)y},{(float)x,1,(float)y + 1}, {(float)x,0,(float)y + 1}},{{0,0},{1,0},{0,1}},MAGENTA }); - mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x,1,(float)y}, {(float)x,0,(float)y + 1}}, {{0,0},{1,0},{0,1}},MAGENTA }); - } - if (map[y][x].wallE != NULL) { - mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y + 1},{(float)x + 1,1,(float)y + 1},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},CYAN }); - mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y + 1} ,{(float)x + 1,1,(float)y},{(float)x + 1,0,(float)y}},{{0,0},{1,0},{0,1}},CYAN }); - } - } - } - //objects.push_back(mapMesh); + LoadLevel(1); return true; } @@ -716,9 +748,6 @@ bool FaceBall::OnUserUpdate(float fElapsedTime) { switch (mode) { case GAME: { - for (Object& o : objects) { - o.rot += PI / 8 * fElapsedTime; - } HandleKeys(fElapsedTime); RenderWorld(); }break; @@ -728,6 +757,9 @@ bool FaceBall::OnUserUpdate(float fElapsedTime) } if (GetKey(olc::F5).bPressed) { mode = (GAMEMODE)!(mode&1); + if (mode == GAMEMODE::GAME) { + LoadLevel(level); + } } return true; } diff --git a/Faceball2030/main.h b/Faceball2030/main.h index 4e080e8..9208b15 100644 --- a/Faceball2030/main.h +++ b/Faceball2030/main.h @@ -1,6 +1,7 @@ #pragma once #include "pixelGameEngine.h" #include "Editor.h" +#include "geometry2d.h" using namespace olc; const float PI = 3.14159f; @@ -31,6 +32,25 @@ struct vec3d float y = 0; float z = 0; float w = 1; + friend std::ostream& operator << (std::ostream& os, const vec3d& rhs) { os << rhs.x << "," << rhs.y << "," << rhs.z; return os; } +}; + +struct Player { + private: + vec3d pos; + olc::utils::geom2d::circle playerR; + public: + Player(vec3d pos,olc::utils::geom2d::circler):pos(pos), playerR(r) {} + void UpdatePos(vec3d pos) { + this->pos = pos; + playerR.pos = { pos.x,pos.z }; + } + float GetRadius() { + return playerR.radius; + } + vec3d&GetPos() { + return pos; + } }; struct Triangle @@ -160,10 +180,10 @@ class FaceBall : public PixelGameEngine std::vectorobjects; GAMEMODE mode=GAMEMODE::GAME; Editor editor; + int level=1; mat4x4 matProj; - vec3d vCamera = { 5,0.5,5 }; vec3d vLookDir; float zOffset = 2; @@ -172,6 +192,8 @@ class FaceBall : public PixelGameEngine float fYaw = 0; float pitch = -PI / 6; + Player player = { {3.7,0.3,0.7}, {{0.5,0.5},0.2} }; + vec3d Matrix_MultiplyVector(mat4x4& m, vec3d& i); mat4x4 Matrix_MakeIdentity(); mat4x4 Matrix_MakeRotationX(float fAngleRad); @@ -194,9 +216,11 @@ class FaceBall : public PixelGameEngine int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& in_tri, Triangle& out_tri1, Triangle& out_tri2); void RenderWorld(); void HandleKeys(float fElapsedTime); - void AddWall(Direction dir, vi2d gridSquare); + void AddWall(int dir, vi2d gridSquare); bool OnUserCreate() override; bool OnUserUpdate(float fElapsedTime) override; void OnTextEntryComplete(const std::string& sText) override; void InitializeEnemyData(); + void LoadLevel(int level); + bool CheckCollision(vec3d movementVector); }; \ No newline at end of file