diff --git a/OneLoneCoder_LudumDare42.cpp b/OneLoneCoder_LudumDare42.cpp new file mode 100644 index 0000000..d2d98e8 --- /dev/null +++ b/OneLoneCoder_LudumDare42.cpp @@ -0,0 +1,452 @@ +/* +OneLoneCoder.com - Ludum Dare 42 - Running Out Of Space +"What's all this about Fish?" - @Javidx9 + +License +~~~~~~~ +One Lone Coder Console Game Engine Copyright (C) 2018 Javidx9 +This program comes with ABSOLUTELY NO WARRANTY. +This is free software, and you are welcome to redistribute it +under certain conditions; See license for details. +Original works located at: +https://www.github.com/onelonecoder +https://www.onelonecoder.com +https://www.youtube.com/javidx9 +GNU GPLv3 +https://github.com/OneLoneCoder/videos/blob/master/LICENSE + +From Javidx9 :) +~~~~~~~~~~~~~~~ +Hello! Ultimately I don't care what you use this for. It's intended to be +educational, and perhaps to the oddly minded - a little bit of fun. +Please hack this, change it and use it in any way you see fit. You acknowledge +that I am not responsible for anything bad that happens as a result of +your actions. However this code is protected by GNU GPLv3, see the license in the +github repo. This means you must attribute me if you use it. You can view this +license here: https://github.com/OneLoneCoder/videos/blob/master/LICENSE +Cheers! + +Background +~~~~~~~~~~ +Ludum Dare 42 - A quick and lazy speedcode following the theme of "Running Out Of Space" + +OBJECTIVE: Stay Alive! Use Arrow Keys to move player. Press space to deploy bombs +to blow up encroaching walls. Collect bombs when they appear. Stay away from the +blasts, and dont get trapped in the walls! + + +Video +~~~~~ +https://www.twitch.tv/videos/295730019 + +Author +~~~~~~ +Twitter: @javidx9 +Blog: http://www.onelonecoder.com +Discord: https://discord.gg/WhwHUMV + + +Last Updated: 11/08/2018 +*/ + + +// For Windows 7 +//#include "olcConsoleGameEngineGL.h" + +// For Windows +#include "olcConsoleGameEngine.h" + +// For Linux +//#include "olcConsoleGameEngineSDL.h" + +#include +#include +using namespace std; + + +class LudumDare42 : public olcConsoleGameEngine +{ +public: + LudumDare42() + { + m_sAppName = L"Ludum Dare 42 - Running Out Of Space"; + } + + +private: + int nWorldWidth = 60; + int nWorldHeight = 60; + + int *world = nullptr; + + int nBlocksPlaced = 0; + + float fBlockTimeElapsed = 0.0f; + float fBlockTime = 0.02f; + + int nPlayerX; + int nPlayerY; + + + + float fSurvivalTime = 0.0f; + + enum + { + EMPTY, + BORDER, + BLOCK, + }; + + + struct sParticle + { + float px, py; + float vx, vy; + float lifetime; + bool dead = false; + }; + + struct sBomb + { + int px, py; + float fuse; + }; + + + list listParticles; + list listBombs; + + int nBombPickupX = 20; + int nBombPickupY = 20; + bool bBombsVisible = true; + int nBoomsticks = 1; + + int nPlayerHealth = 100; + float fHighScore = 0.0f; + + bool bReset = true; + +public: + bool OnUserCreate() override + { + world = new int[nWorldWidth * nWorldHeight]{ 0 }; + bReset = true; + return true; + } + + + void Boom(int xc, int yc, int r) + { + // Taken from wikipedia + int x = 0; + int y = r; + int p = 3 - 2 * r; + if (!r) return; + + auto drawline = [&](int sx, int ex, int ny) + { + if (ny <= 0 || ny >= nWorldHeight) return; + sx = max(sx, 0); + ex = min(ex, nWorldWidth); + for (int i = sx; i <= ex; i++) + { + + if (world[ny * nWorldWidth + i] != BORDER) + { + world[ny * nWorldWidth + i] = 0; + nBlocksPlaced--; + } + } + }; + + while (y >= x) + { + // Modified to draw scan-lines instead of edges + drawline(xc - x, xc + x, yc - y); + drawline(xc - y, xc + y, yc - x); + drawline(xc - x, xc + x, yc + y); + drawline(xc - y, xc + y, yc + x); + if (p < 0) p += 4 * x++ + 6; + else p += 4 * (x++ - y--) + 10; + } + }; + + bool OnUserUpdate(float fElapsedTime) override + { + if (bReset) + { + for (int x = 0; x= fBlockTime) + { + fBlockTimeElapsed -= fBlockTime; + // TODO: perfect ! + // May come back to this later to make it optimal + if (nBlocksPlaced < (nWorldWidth * nWorldHeight) - 2 * (nWorldWidth - 2) - 2 * (nWorldHeight - 2) - 4) // hmmm maybe? :D + { + bool bBlockPlaced = false; + while (!bBlockPlaced) + { + int x = (rand() % (nWorldWidth - 2) + 1); + int y = (rand() % (nWorldHeight - 2) + 1); + + // Check if location is suitable, it is + // if neighbouring cell is not empty + + if (!Get(x, y) && + (Get(x - 1, y) || Get(x + 1, y) || Get(x, y - 1) || Get(x, y + 1))) + { + Set(x, y, BLOCK); + bBlockPlaced = true; + nBlocksPlaced++; + } + } + } + + if (!bBombsVisible && nBoomsticks == 0) + { + bool bBlockPlaced = false; + while (!bBlockPlaced) + { + int x = (rand() % (nWorldWidth - 2) + 1); + int y = (rand() % (nWorldHeight - 2) + 1); + if (!Get(x, y)) + { + bBlockPlaced = true; + nBombPickupX = x; + nBombPickupY = y; + bBombsVisible = true; + } + } + } + + + // Handle Player + if (IsFocused()) + { + if (GetKey(VK_UP).bHeld) + { + if (!Get(nPlayerX, nPlayerY - 1)) + nPlayerY--; + } + + if (GetKey(VK_DOWN).bHeld) + { + if (!Get(nPlayerX, nPlayerY + 1)) + nPlayerY++; + } + + if (GetKey(VK_LEFT).bHeld) + { + if (!Get(nPlayerX - 1, nPlayerY)) + nPlayerX--; + } + + if (GetKey(VK_RIGHT).bHeld) + { + if (!Get(nPlayerX + 1, nPlayerY)) + nPlayerX++; + } + + if (bBombsVisible && (pow(nPlayerX-nBombPickupX,2) + pow(nPlayerY-nBombPickupY, 2)) <= 6) + { + bBombsVisible = false; + nBoomsticks += 5; + } + + // Check if player is trapped + if (Get(nPlayerX - 1, nPlayerY) && Get(nPlayerX + 1, nPlayerY) && + Get(nPlayerX, nPlayerY - 1) && Get(nPlayerX, nPlayerY + 1)) + { + if (nBoomsticks == 0) + nPlayerHealth = 0; + } + } + } + + // Update Particles + for (auto &p : listParticles) + { + p.vy += 100.0f * fElapsedTime; + + p.px += p.vx * fElapsedTime; + p.py += p.vy * fElapsedTime; + + if (p.px < 0 || p.px >= nWorldWidth || p.py < 0 || p.py >= nWorldHeight) + { + p.dead = true; + } + } + + listParticles.remove_if([&](const sParticle &p) { return p.dead; }); + + + // Update Bombs + for (auto &b : listBombs) + { + b.fuse -= fElapsedTime; + if (b.fuse < 0) + { + // Boom! if boomsticks are available + Boom(b.px, b.py, 5); + + // Some sort of visual effect for explosion + for (int i = 0; i < 20; i++) + { + sParticle p; + p.px = b.px + (2.5f * (((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f)); + p.py = b.py + (2.5f * (((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f)); + p.vx = 1.1f * 50.0f * (((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f); + p.vy = 1.1f * 50.0f * (((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f); + p.dead = false; + + listParticles.push_back(p); + } + + // Injure player + nPlayerHealth -= max(0, 4 * (5 - sqrtf(pow(nPlayerX - b.px, 2) + pow(nPlayerY - b.py, 2)))); + + } + } + + listBombs.remove_if([&](const sBomb &b) { return b.fuse < 0; }); + + if (IsFocused() && GetKey(VK_SPACE).bReleased) + { + if (nBoomsticks > 0) + { + listBombs.push_back({ nPlayerX, nPlayerY, 5.0f }); + nBoomsticks--; + } + } + + // Clear Screen + Fill(0, 0, ScreenWidth(), ScreenHeight(), PIXEL_SOLID, FG_BLACK); + + // Draw World + for (int x = 0; x < nWorldWidth; x++) + { + for (int y = 0; y < nWorldHeight; y++) + { + switch (world[y*nWorldWidth + x]) + { + case BORDER: + Draw(x, y, PIXEL_SOLID, FG_WHITE); + break; + + case BLOCK: + Draw(x, y, PIXEL_SOLID, FG_RED); + break; + } + } + } + + // Draw Boom + for (auto &p : listParticles) + { + Draw(p.px, p.py, PIXEL_QUARTER, FG_YELLOW); + } + + // Draw Bombs + for (auto &b : listBombs) + { + Draw(b.px - 1, b.py, PIXEL_SOLID, FG_GREEN); + Draw(b.px + 1, b.py, PIXEL_SOLID, FG_GREEN); + Draw(b.px, b.py - 1, PIXEL_SOLID, FG_GREEN); + Draw(b.px, b.py + 1, PIXEL_SOLID, FG_GREEN); + DrawString(b.px, b.py, to_wstring((int)b.fuse + 1)); + } + + // Draw Bomb Pickup + if (bBombsVisible) + { + Fill(nBombPickupX - 1, nBombPickupY - 1, nBombPickupX + 2, nBombPickupY + 2, PIXEL_SOLID, FG_MAGENTA); + Draw(nBombPickupX, nBombPickupY, PIXEL_SOLID, FG_GREY); + } + + + fHighScore = max(fHighScore, fSurvivalTime); + + // Draw Player + Draw(nPlayerX, nPlayerY, L'P', FG_CYAN); + + DrawString(2, ScreenHeight() - 2, L"Survived: " + to_wstring((int)fSurvivalTime)); + DrawString(18, ScreenHeight() - 2, L"Bombs: " + to_wstring(nBoomsticks)); + DrawString(30, ScreenHeight() - 2, L"Health: " + to_wstring(nPlayerHealth)); + DrawString(45, ScreenHeight() - 2, L"High Score: " + to_wstring((int)fHighScore)); + + return true; + } + +}; + + + + +int main() +{ + LudumDare42 demo; + if (demo.ConstructConsole(60, 63, 14, 14)) + demo.Start(); + return 0; +} +