parent
7571cd4f12
commit
75cd9d66a0
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,376 @@ |
|||||||
|
/*
|
||||||
|
OneLoneCoder.com - Upgraded Command Line First Person Shooter (FPS) Engine |
||||||
|
"Bricks and Lamps people, bricks and lamps..." - @Javidx9 |
||||||
|
|
||||||
|
Disclaimer |
||||||
|
~~~~~~~~~~ |
||||||
|
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. BUT, you acknowledge that I am not responsible for anything |
||||||
|
bad that happens as a result of your actions. However, if good stuff happens, I |
||||||
|
would appreciate a shout out, or at least give the blog some publicity for me. |
||||||
|
Cheers! |
||||||
|
|
||||||
|
Background |
||||||
|
~~~~~~~~~~ |
||||||
|
The FPS video was one of my first youtube videos, and I feel one of my better |
||||||
|
ones, but its not had the popularity it deserves. So I'm upgrading the engine |
||||||
|
to make it more appealling. |
||||||
|
|
||||||
|
IMPORTANT!! |
||||||
|
~~~~~~~~~~~ |
||||||
|
You'll need the FPSSprites folder too! |
||||||
|
|
||||||
|
|
||||||
|
Author |
||||||
|
~~~~~~ |
||||||
|
Twitter: @javidx9 |
||||||
|
Blog: www.onelonecoder.com |
||||||
|
|
||||||
|
Video: |
||||||
|
~~~~~~
|
||||||
|
https://youtu.be/HEb2akswCcw
|
||||||
|
|
||||||
|
Last Updated: 23/10/2017 |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
#include <string> |
||||||
|
#include <algorithm> |
||||||
|
using namespace std; |
||||||
|
|
||||||
|
#include "olcConsoleGameEngine.h" |
||||||
|
|
||||||
|
class OneLoneCoder_UltimateFPS : public olcConsoleGameEngine |
||||||
|
{ |
||||||
|
public: |
||||||
|
OneLoneCoder_UltimateFPS() |
||||||
|
{ |
||||||
|
m_sAppName = L"Ultimate First Person Shooter"; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
int nMapWidth = 32; // World Dimensions
|
||||||
|
int nMapHeight = 32; |
||||||
|
|
||||||
|
float fPlayerX = 14.7f; // Player Start Position
|
||||||
|
float fPlayerY = 8;// 5.09f;
|
||||||
|
float fPlayerA = -3.14159f / 2.0f; // Player Start Rotation
|
||||||
|
float fFOV = 3.14159f / 4.0f; // Field of View
|
||||||
|
float fDepth = 16.0f; // Maximum rendering distance
|
||||||
|
float fSpeed = 5.0f; // Walking Speed
|
||||||
|
wstring map; |
||||||
|
|
||||||
|
olcSprite *spriteWall; |
||||||
|
olcSprite *spriteLamp; |
||||||
|
olcSprite *spriteFireBall; |
||||||
|
|
||||||
|
float *fDepthBuffer = nullptr; |
||||||
|
|
||||||
|
struct sObject |
||||||
|
{ |
||||||
|
float x; |
||||||
|
float y; |
||||||
|
float vx; |
||||||
|
float vy; |
||||||
|
bool bRemove; |
||||||
|
olcSprite *sprite; |
||||||
|
}; |
||||||
|
|
||||||
|
list<sObject> listObjects; |
||||||
|
|
||||||
|
protected: |
||||||
|
virtual bool OnUserCreate() |
||||||
|
{ |
||||||
|
map += L"#########.......#########......."; |
||||||
|
map += L"#...............#..............."; |
||||||
|
map += L"#.......#########.......########"; |
||||||
|
map += L"#..............##..............#"; |
||||||
|
map += L"#......##......##......##......#"; |
||||||
|
map += L"#......##..............##......#"; |
||||||
|
map += L"#..............##..............#"; |
||||||
|
map += L"###............####............#"; |
||||||
|
map += L"##.............###.............#"; |
||||||
|
map += L"#............####............###"; |
||||||
|
map += L"#..............................#"; |
||||||
|
map += L"#..............##..............#"; |
||||||
|
map += L"#..............##..............#"; |
||||||
|
map += L"#...........#####...........####"; |
||||||
|
map += L"#..............................#"; |
||||||
|
map += L"###..####....########....#######"; |
||||||
|
map += L"####.####.......######.........."; |
||||||
|
map += L"#...............#..............."; |
||||||
|
map += L"#.......#########.......##..####"; |
||||||
|
map += L"#..............##..............#"; |
||||||
|
map += L"#......##......##.......#......#"; |
||||||
|
map += L"#......##......##......##......#"; |
||||||
|
map += L"#..............##..............#"; |
||||||
|
map += L"###............####............#"; |
||||||
|
map += L"##.............###.............#"; |
||||||
|
map += L"#............####............###"; |
||||||
|
map += L"#..............................#"; |
||||||
|
map += L"#..............................#"; |
||||||
|
map += L"#..............##..............#"; |
||||||
|
map += L"#...........##..............####"; |
||||||
|
map += L"#..............##..............#"; |
||||||
|
map += L"################################"; |
||||||
|
|
||||||
|
|
||||||
|
spriteWall = new olcSprite(L"FPSSprites/fps_wall1.spr"); |
||||||
|
spriteLamp = new olcSprite(L"FPSSprites/fps_lamp1.spr"); |
||||||
|
spriteFireBall = new olcSprite(L"FPSSprites/fps_fireball1.spr"); |
||||||
|
fDepthBuffer = new float[ScreenWidth()]; |
||||||
|
|
||||||
|
listObjects = {
|
||||||
|
{ 8.5f, 8.5f, 0.0f, 0.0f, false, spriteLamp }, |
||||||
|
{ 7.5f, 7.5f, 0.0f, 0.0f, false, spriteLamp }, |
||||||
|
{ 10.5f, 3.5f, 0.0f, 0.0f, false, spriteLamp },
|
||||||
|
}; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
virtual bool OnUserUpdate(float fElapsedTime) |
||||||
|
{ |
||||||
|
// Handle CCW Rotation
|
||||||
|
if (m_keys[L'A'].bHeld) |
||||||
|
fPlayerA -= (fSpeed * 0.5f) * fElapsedTime; |
||||||
|
|
||||||
|
// Handle CW Rotation
|
||||||
|
if (m_keys[L'D'].bHeld) |
||||||
|
fPlayerA += (fSpeed * 0.5f) * fElapsedTime; |
||||||
|
|
||||||
|
// Handle Forwards movement & collision
|
||||||
|
if (m_keys[L'W'].bHeld) |
||||||
|
{ |
||||||
|
fPlayerX += sinf(fPlayerA) * fSpeed * fElapsedTime;; |
||||||
|
fPlayerY += cosf(fPlayerA) * fSpeed * fElapsedTime;; |
||||||
|
if (map.c_str()[(int)fPlayerX * nMapWidth + (int)fPlayerY] == '#') |
||||||
|
{ |
||||||
|
fPlayerX -= sinf(fPlayerA) * fSpeed * fElapsedTime;; |
||||||
|
fPlayerY -= cosf(fPlayerA) * fSpeed * fElapsedTime;; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Handle backwards movement & collision
|
||||||
|
if (m_keys[L'S'].bHeld) |
||||||
|
{ |
||||||
|
fPlayerX -= sinf(fPlayerA) * fSpeed * fElapsedTime;; |
||||||
|
fPlayerY -= cosf(fPlayerA) * fSpeed * fElapsedTime;; |
||||||
|
if (map.c_str()[(int)fPlayerX * nMapWidth + (int)fPlayerY] == '#') |
||||||
|
{ |
||||||
|
fPlayerX += sinf(fPlayerA) * fSpeed * fElapsedTime;; |
||||||
|
fPlayerY += cosf(fPlayerA) * fSpeed * fElapsedTime;; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Handle Strafe Right movement & collision
|
||||||
|
if (m_keys[L'E'].bHeld) |
||||||
|
{ |
||||||
|
fPlayerX += cosf(fPlayerA) * fSpeed * fElapsedTime; |
||||||
|
fPlayerY -= sinf(fPlayerA) * fSpeed * fElapsedTime; |
||||||
|
if (map.c_str()[(int)fPlayerX * nMapWidth + (int)fPlayerY] == '#') |
||||||
|
{ |
||||||
|
fPlayerX -= cosf(fPlayerA) * fSpeed * fElapsedTime; |
||||||
|
fPlayerY += sinf(fPlayerA) * fSpeed * fElapsedTime; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Handle Strafe Left movement & collision
|
||||||
|
if (m_keys[L'Q'].bHeld) |
||||||
|
{ |
||||||
|
fPlayerX -= cosf(fPlayerA) * fSpeed * fElapsedTime; |
||||||
|
fPlayerY += sinf(fPlayerA) * fSpeed * fElapsedTime; |
||||||
|
if (map.c_str()[(int)fPlayerX * nMapWidth + (int)fPlayerY] == '#') |
||||||
|
{ |
||||||
|
fPlayerX += cosf(fPlayerA) * fSpeed * fElapsedTime; |
||||||
|
fPlayerY -= sinf(fPlayerA) * fSpeed * fElapsedTime; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Fire Bullets
|
||||||
|
if (m_keys[VK_SPACE].bReleased) |
||||||
|
{ |
||||||
|
sObject o; |
||||||
|
o.x = fPlayerX; |
||||||
|
o.y = fPlayerY; |
||||||
|
float fNoise = (((float)rand() / (float)RAND_MAX) - 0.5f) * 0.1f; |
||||||
|
o.vx = sinf(fPlayerA + fNoise) * 8.0f; |
||||||
|
o.vy = cosf(fPlayerA + fNoise) * 8.0f; |
||||||
|
o.sprite = spriteFireBall; |
||||||
|
o.bRemove = false; |
||||||
|
listObjects.push_back(o); |
||||||
|
} |
||||||
|
|
||||||
|
for (int x = 0; x < ScreenWidth(); x++) |
||||||
|
{ |
||||||
|
// For each column, calculate the projected ray angle into world space
|
||||||
|
float fRayAngle = (fPlayerA - fFOV / 2.0f) + ((float)x / (float)ScreenWidth()) * fFOV; |
||||||
|
|
||||||
|
// Find distance to wall
|
||||||
|
float fStepSize = 0.01f; // Increment size for ray casting, decrease to increase
|
||||||
|
float fDistanceToWall = 0.0f; // resolution
|
||||||
|
|
||||||
|
bool bHitWall = false; // Set when ray hits wall block
|
||||||
|
bool bBoundary = false; // Set when ray hits boundary between two wall blocks
|
||||||
|
|
||||||
|
float fEyeX = sinf(fRayAngle); // Unit vector for ray in player space
|
||||||
|
float fEyeY = cosf(fRayAngle); |
||||||
|
|
||||||
|
float fSampleX = 0.0f; |
||||||
|
|
||||||
|
bool bLit = false; |
||||||
|
|
||||||
|
// Incrementally cast ray from player, along ray angle, testing for
|
||||||
|
// intersection with a block
|
||||||
|
while (!bHitWall && fDistanceToWall < fDepth) |
||||||
|
{ |
||||||
|
fDistanceToWall += fStepSize; |
||||||
|
int nTestX = (int)(fPlayerX + fEyeX * fDistanceToWall); |
||||||
|
int nTestY = (int)(fPlayerY + fEyeY * fDistanceToWall); |
||||||
|
|
||||||
|
// Test if ray is out of bounds
|
||||||
|
if (nTestX < 0 || nTestX >= nMapWidth || nTestY < 0 || nTestY >= nMapHeight) |
||||||
|
{ |
||||||
|
bHitWall = true; // Just set distance to maximum depth
|
||||||
|
fDistanceToWall = fDepth; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
// Ray is inbounds so test to see if the ray cell is a wall block
|
||||||
|
if (map.c_str()[nTestX * nMapWidth + nTestY] == '#') |
||||||
|
{ |
||||||
|
// Ray has hit wall
|
||||||
|
bHitWall = true; |
||||||
|
|
||||||
|
// Determine where ray has hit wall. Break Block boundary
|
||||||
|
// int 4 line segments
|
||||||
|
float fBlockMidX = (float)nTestX + 0.5f; |
||||||
|
float fBlockMidY = (float)nTestY + 0.5f; |
||||||
|
|
||||||
|
float fTestPointX = fPlayerX + fEyeX * fDistanceToWall; |
||||||
|
float fTestPointY = fPlayerY + fEyeY * fDistanceToWall; |
||||||
|
|
||||||
|
float fTestAngle = atan2f((fTestPointY - fBlockMidY), (fTestPointX - fBlockMidX)); |
||||||
|
|
||||||
|
if (fTestAngle >= -3.14159f * 0.25f && fTestAngle < 3.14159f * 0.25f) |
||||||
|
fSampleX = fTestPointY - (float)nTestY; |
||||||
|
if (fTestAngle >= 3.14159f * 0.25f && fTestAngle < 3.14159f * 0.75f) |
||||||
|
fSampleX = fTestPointX - (float)nTestX; |
||||||
|
if (fTestAngle < -3.14159f * 0.25f && fTestAngle >= -3.14159f * 0.75f) |
||||||
|
fSampleX = fTestPointX - (float)nTestX; |
||||||
|
if (fTestAngle >= 3.14159f * 0.75f || fTestAngle < -3.14159f * 0.75f) |
||||||
|
fSampleX = fTestPointY - (float)nTestY; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Calculate distance to ceiling and floor
|
||||||
|
int nCeiling = (float)(ScreenHeight() / 2.0) - ScreenHeight() / ((float)fDistanceToWall); |
||||||
|
int nFloor = ScreenHeight() - nCeiling; |
||||||
|
|
||||||
|
// Update Depth Buffer
|
||||||
|
fDepthBuffer[x] = fDistanceToWall; |
||||||
|
|
||||||
|
for (int y = 0; y < ScreenHeight(); y++) |
||||||
|
{ |
||||||
|
// Each Row
|
||||||
|
if (y <= nCeiling) |
||||||
|
Draw(x, y, L' '); |
||||||
|
else if (y > nCeiling && y <= nFloor) |
||||||
|
{ |
||||||
|
// Draw Wall
|
||||||
|
if (fDistanceToWall < fDepth) |
||||||
|
{ |
||||||
|
float fSampleY = ((float)y - (float)nCeiling) / ((float)nFloor - (float)nCeiling); |
||||||
|
Draw(x, y, spriteWall->SampleGlyph(fSampleX, fSampleY), spriteWall->SampleColour(fSampleX, fSampleY)); |
||||||
|
} |
||||||
|
else |
||||||
|
Draw(x, y, PIXEL_SOLID, 0); |
||||||
|
} |
||||||
|
else // Floor
|
||||||
|
{ |
||||||
|
Draw(x, y, PIXEL_SOLID, FG_DARK_GREEN); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Update & Draw Objects
|
||||||
|
for (auto &object : listObjects) |
||||||
|
{ |
||||||
|
// Update Object Physics
|
||||||
|
object.x += object.vx * fElapsedTime; |
||||||
|
object.y += object.vy * fElapsedTime; |
||||||
|
|
||||||
|
// Check if object is inside wall - set flag for removal
|
||||||
|
if (map.c_str()[(int)object.x * nMapWidth + (int)object.y] == '#') |
||||||
|
object.bRemove = true; |
||||||
|
|
||||||
|
// Can object be seen?
|
||||||
|
float fVecX = object.x - fPlayerX; |
||||||
|
float fVecY = object.y - fPlayerY; |
||||||
|
float fDistanceFromPlayer = sqrtf(fVecX*fVecX + fVecY*fVecY); |
||||||
|
|
||||||
|
float fEyeX = sinf(fPlayerA); |
||||||
|
float fEyeY = cosf(fPlayerA); |
||||||
|
|
||||||
|
// Calculate angle between lamp and players feet, and players looking direction
|
||||||
|
// to determine if the lamp is in the players field of view
|
||||||
|
float fObjectAngle = atan2f(fEyeY, fEyeX) - atan2f(fVecY, fVecX); |
||||||
|
if (fObjectAngle < -3.14159f) |
||||||
|
fObjectAngle += 2.0f * 3.14159f; |
||||||
|
if (fObjectAngle > 3.14159f) |
||||||
|
fObjectAngle -= 2.0f * 3.14159f; |
||||||
|
|
||||||
|
bool bInPlayerFOV = fabs(fObjectAngle) < fFOV / 2.0f; |
||||||
|
|
||||||
|
if (bInPlayerFOV && fDistanceFromPlayer >= 0.5f && fDistanceFromPlayer < fDepth && !object.bRemove) |
||||||
|
{ |
||||||
|
float fObjectCeiling = (float)(ScreenHeight() / 2.0) - ScreenHeight() / ((float)fDistanceFromPlayer); |
||||||
|
float fObjectFloor = ScreenHeight() - fObjectCeiling; |
||||||
|
float fObjectHeight = fObjectFloor - fObjectCeiling; |
||||||
|
float fObjectAspectRatio = (float)object.sprite->nHeight / (float)object.sprite->nWidth; |
||||||
|
float fObjectWidth = fObjectHeight / fObjectAspectRatio; |
||||||
|
float fMiddleOfObject = (0.5f * (fObjectAngle / (fFOV / 2.0f)) + 0.5f) * (float)ScreenWidth(); |
||||||
|
|
||||||
|
// Draw Lamp
|
||||||
|
for (float lx = 0; lx < fObjectWidth; lx++) |
||||||
|
{ |
||||||
|
for (float ly = 0; ly < fObjectHeight; ly++) |
||||||
|
{ |
||||||
|
float fSampleX = lx / fObjectWidth; |
||||||
|
float fSampleY = ly / fObjectHeight; |
||||||
|
wchar_t c = object.sprite->SampleGlyph(fSampleX, fSampleY); |
||||||
|
int nObjectColumn = (int)(fMiddleOfObject + lx - (fObjectWidth / 2.0f)); |
||||||
|
if (nObjectColumn >= 0 && nObjectColumn < ScreenWidth()) |
||||||
|
if (c != L' ' && fDepthBuffer[nObjectColumn] >= fDistanceFromPlayer) |
||||||
|
{
|
||||||
|
Draw(nObjectColumn, fObjectCeiling + ly, c, object.sprite->SampleColour(fSampleX, fSampleY)); |
||||||
|
fDepthBuffer[nObjectColumn] = fDistanceFromPlayer; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Remove dead objects from object list
|
||||||
|
listObjects.remove_if([](sObject &o) {return o.bRemove; }); |
||||||
|
|
||||||
|
// Display Map & Player
|
||||||
|
for (int nx = 0; nx < nMapWidth; nx++) |
||||||
|
for (int ny = 0; ny < nMapWidth; ny++) |
||||||
|
Draw(nx+1, ny+1, map[ny * nMapWidth + nx]); |
||||||
|
Draw(1 + (int)fPlayerY, 1 + (int)fPlayerX, L'P'); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
int main() |
||||||
|
{ |
||||||
|
OneLoneCoder_UltimateFPS game; |
||||||
|
game.ConstructConsole(320, 240,4,4); |
||||||
|
game.Start(); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,240 @@ |
|||||||
|
/*
|
||||||
|
OneLoneCoder.com - Sprite Editor |
||||||
|
"Stop Crying about Paint ya big baby" - @Javidx9 |
||||||
|
|
||||||
|
Disclaimer |
||||||
|
~~~~~~~~~~ |
||||||
|
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. BUT, you acknowledge that I am not responsible for anything |
||||||
|
bad that happens as a result of your actions. However, if good stuff happens, I |
||||||
|
would appreciate a shout out, or at least give the blog some publicity for me. |
||||||
|
Cheers! |
||||||
|
|
||||||
|
Background |
||||||
|
~~~~~~~~~~ |
||||||
|
Editing ASCII is not a simple as it should be, especially if you want to |
||||||
|
include all the weird characters |
||||||
|
|
||||||
|
Controls |
||||||
|
~~~~~~~~ |
||||||
|
|
||||||
|
|
||||||
|
Author |
||||||
|
~~~~~~ |
||||||
|
Twitter: @javidx9 |
||||||
|
Blog: www.onelonecoder.com |
||||||
|
|
||||||
|
Video: |
||||||
|
~~~~~~ |
||||||
|
Several... |
||||||
|
|
||||||
|
Last Updated: |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
#include <string> |
||||||
|
using namespace std; |
||||||
|
|
||||||
|
#include "olcConsoleGameEngine.h" |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class OneLoneCoder_SpriteEditor : public olcConsoleGameEngine |
||||||
|
{ |
||||||
|
public: |
||||||
|
OneLoneCoder_SpriteEditor() |
||||||
|
{ |
||||||
|
m_sAppName = L"Sprite Editor"; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
int nPosX = 0; |
||||||
|
int nPosY = 0; |
||||||
|
int nOffsetX = 0; |
||||||
|
int nOffsetY = 0; |
||||||
|
int nZoom = 4; |
||||||
|
int nCurrentGlyph = PIXEL_SOLID; |
||||||
|
int nCurrentColourFG = FG_RED; |
||||||
|
int nCurrentColourBG = FG_BLACK; |
||||||
|
|
||||||
|
olcSprite *sprite = nullptr; |
||||||
|
wstring sCurrentSpriteFile; |
||||||
|
|
||||||
|
protected: |
||||||
|
// Called by olcConsoleGameEngine
|
||||||
|
virtual bool OnUserCreate() |
||||||
|
{ |
||||||
|
sprite = new olcSprite(8, 32); |
||||||
|
sCurrentSpriteFile = L"fps_fireball1.spr"; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// Called by olcConsoleGameEngine
|
||||||
|
virtual bool OnUserUpdate(float fElapsedTime) |
||||||
|
{ |
||||||
|
|
||||||
|
// Zooming
|
||||||
|
if (m_keys[VK_PRIOR].bReleased) |
||||||
|
nZoom <<= 1; |
||||||
|
|
||||||
|
if (m_keys[VK_NEXT].bReleased) |
||||||
|
nZoom >>= 1; |
||||||
|
|
||||||
|
if (nZoom > 32) nZoom = 32; |
||||||
|
if (nZoom < 2) nZoom = 2; |
||||||
|
|
||||||
|
// Brushes
|
||||||
|
if (m_keys[VK_F1].bReleased) nCurrentGlyph = PIXEL_SOLID; |
||||||
|
if (m_keys[VK_F2].bReleased) nCurrentGlyph = PIXEL_THREEQUARTERS; |
||||||
|
if (m_keys[VK_F3].bReleased) nCurrentGlyph = PIXEL_HALF; |
||||||
|
if (m_keys[VK_F4].bReleased) nCurrentGlyph = PIXEL_QUARTER; |
||||||
|
|
||||||
|
// Colours
|
||||||
|
for (int i = 0; i < 8; i++) |
||||||
|
if (m_keys[L"01234567"[i]].bReleased) |
||||||
|
if (m_keys[VK_SHIFT].bHeld) |
||||||
|
nCurrentColourFG = i + 8; |
||||||
|
else |
||||||
|
nCurrentColourFG = i; |
||||||
|
|
||||||
|
|
||||||
|
if (m_keys[VK_F7].bReleased) |
||||||
|
nCurrentColourBG--; |
||||||
|
|
||||||
|
if (m_keys[VK_F8].bReleased) |
||||||
|
nCurrentColourBG++; |
||||||
|
|
||||||
|
if (nCurrentColourBG < 0) nCurrentColourBG = 15; |
||||||
|
if (nCurrentColourBG > 15) nCurrentColourBG = 0; |
||||||
|
|
||||||
|
// Cursing :-)
|
||||||
|
if (m_keys[VK_SHIFT].bHeld) |
||||||
|
{ |
||||||
|
if (m_keys[VK_UP].bReleased) nOffsetY++; |
||||||
|
if (m_keys[VK_DOWN].bReleased) nOffsetY--; |
||||||
|
if (m_keys[VK_LEFT].bReleased) nOffsetX++; |
||||||
|
if (m_keys[VK_RIGHT].bReleased) nOffsetX--; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (m_keys[VK_UP].bReleased) nPosY--; |
||||||
|
if (m_keys[VK_DOWN].bReleased) nPosY++; |
||||||
|
if (m_keys[VK_LEFT].bReleased) nPosX--; |
||||||
|
if (m_keys[VK_RIGHT].bReleased) nPosX++; |
||||||
|
} |
||||||
|
|
||||||
|
if (sprite != nullptr) |
||||||
|
{ |
||||||
|
if (nPosX < 0) nPosX = 0; |
||||||
|
if (nPosX >= sprite->nWidth) nPosX = sprite->nWidth - 1; |
||||||
|
if (nPosY < 0) nPosY = 0; |
||||||
|
if (nPosY >= sprite->nHeight) nPosY = sprite->nHeight - 1; |
||||||
|
|
||||||
|
if (m_keys[VK_SPACE].bReleased) |
||||||
|
{ |
||||||
|
sprite->SetGlyph(nPosX - 0, nPosY - 0, nCurrentGlyph); |
||||||
|
sprite->SetColour(nPosX - 0, nPosY - 0, nCurrentColourFG | (nCurrentColourBG << 4)); |
||||||
|
} |
||||||
|
|
||||||
|
if (m_keys[VK_DELETE].bReleased) |
||||||
|
{ |
||||||
|
sprite->SetGlyph(nPosX - 0, nPosY - 0, L' '); |
||||||
|
sprite->SetColour(nPosX - 0, nPosY - 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
if (m_keys[VK_F9].bReleased) |
||||||
|
{ |
||||||
|
sprite->Load(sCurrentSpriteFile); |
||||||
|
} |
||||||
|
|
||||||
|
if (m_keys[VK_F10].bReleased) |
||||||
|
{ |
||||||
|
sprite->Save(sCurrentSpriteFile); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Erase All
|
||||||
|
Fill(0, 0, ScreenWidth(), ScreenHeight(), L' ', 0); |
||||||
|
|
||||||
|
// Draw Menu
|
||||||
|
DrawString(1, 1, L"F1 = 100% F2 = 75% F3 = 50% F4 = 25% F9 = Load File F10 = Save File"); |
||||||
|
for (int i = 0; i < 8; i++) |
||||||
|
{ |
||||||
|
DrawString(1 + 6 * i, 3, to_wstring(i) + L" = "); |
||||||
|
if (m_keys[VK_SHIFT].bHeld) |
||||||
|
Draw(1 + 6 * i + 4, 3, PIXEL_SOLID, (i + 8)); |
||||||
|
else |
||||||
|
Draw(1 + 6 * i + 4, 3, PIXEL_SOLID, (i)); |
||||||
|
} |
||||||
|
|
||||||
|
DrawString(1, 5, L"Current Brush = "); |
||||||
|
Draw(18, 5, nCurrentGlyph, nCurrentColourFG | (nCurrentColourBG << 4)); |
||||||
|
|
||||||
|
// Draw Canvas
|
||||||
|
for (int x = 9; x < 138; x++) |
||||||
|
{ |
||||||
|
Draw(x, 9); |
||||||
|
Draw(x, 74); |
||||||
|
} |
||||||
|
|
||||||
|
for (int y = 9; y < 75; y++) |
||||||
|
{ |
||||||
|
Draw(9, y); |
||||||
|
Draw(138, y); |
||||||
|
} |
||||||
|
|
||||||
|
// Draw Visible Sprite
|
||||||
|
if (sprite != nullptr) |
||||||
|
{ |
||||||
|
int nVisiblePixelsX = 128 / nZoom; |
||||||
|
int nVisiblePixelsY = 64 / nZoom; |
||||||
|
|
||||||
|
for (int x = 0; x < nVisiblePixelsX; x++) |
||||||
|
for (int y = 0; y < nVisiblePixelsY; y++) |
||||||
|
{ |
||||||
|
if (x - nOffsetX < sprite->nWidth && y - nOffsetY < sprite->nHeight && x - nOffsetX >= 0 && y - nOffsetY >= 0) |
||||||
|
{ |
||||||
|
// Draw Sprite
|
||||||
|
Fill(x * nZoom + 10, y*nZoom + 10, (x + 1)*nZoom + 10, (y + 1)*nZoom + 10, sprite->GetGlyph(x - nOffsetX, y - nOffsetY), sprite->GetColour(x - nOffsetX, y - nOffsetY)); |
||||||
|
|
||||||
|
|
||||||
|
// Draw Pixel Markers
|
||||||
|
if (sprite->GetGlyph(x - nOffsetX, y - nOffsetY) == L' ') |
||||||
|
Draw((x)* nZoom + 10, (y)* nZoom + 10, L'.'); |
||||||
|
} |
||||||
|
|
||||||
|
if (x - nOffsetX == nPosX && y - nOffsetY == nPosY) |
||||||
|
Draw((x)* nZoom + 10, (y)* nZoom + 10, L'O'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Draw Actual Sprite
|
||||||
|
for (int x = 0; x < sprite->nWidth; x++) |
||||||
|
for (int y = 0; y < sprite->nHeight; y++) |
||||||
|
Draw(x + 10, y + 80, sprite->GetGlyph(x, y), sprite->GetColour(x, y)); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
int main() |
||||||
|
{ |
||||||
|
// Use olcConsoleGameEngine derived app
|
||||||
|
OneLoneCoder_SpriteEditor game; |
||||||
|
game.ConstructConsole(160, 100, 8, 8); |
||||||
|
game.Start(); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
Loading…
Reference in new issue