-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b77e6cd
Showing
25 changed files
with
1,861 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
|
||
#ifndef _BLOCK_H_ | ||
#define _BLOCK_H_ | ||
|
||
#include "Renderer.h" | ||
|
||
class Block; | ||
typedef std::shared_ptr<Block> BlockPtr; | ||
typedef std::shared_ptr<const Block> ConstBlockPtr; | ||
|
||
const int BLOCK_SIZE_X = 42; | ||
const int BLOCK_SIZE_Y = 42; | ||
const int BOARD_POS_X = 330; | ||
const int BOARD_POS_Y = 105; | ||
|
||
struct NotImplementedException : public std::exception | ||
{ | ||
}; | ||
|
||
class Block | ||
{ | ||
struct impl; | ||
std::unique_ptr<impl> pimpl; | ||
public: | ||
Block(Renderer &r); | ||
~Block(); | ||
|
||
void init(int boardX, int boardY, TextureID texture); | ||
|
||
bool isInside(int x, int y) const; | ||
bool isSelected() const; | ||
bool isDead() const; | ||
bool canMove() const; | ||
bool isNeighbor(BlockPtr block) const; | ||
|
||
int getBoardX() const; | ||
int getBoardY() const; | ||
//return some numeric block type or -1 for empty/inactive block | ||
int getType() const; | ||
//return best swap direction given mouse coordinates | ||
//sets (dx, dy) to one of (-1, 0), (1, 0), (0, -1), (0, 1) | ||
void getSwapDirection(const int x, const int y, int &dx, int &dy) const; | ||
|
||
void mark(unsigned int currentTime); | ||
void unmark(unsigned int currentTime); | ||
void select(unsigned int currentTime); | ||
void unselect(const unsigned int currentTime); | ||
|
||
void swapWith(unsigned int currentTime, BlockPtr block); | ||
void kill(unsigned int currentTime); | ||
void fallTo(unsigned int currentTime, const int targetX, const int targetY); | ||
|
||
void simulate(unsigned int currentTime); | ||
|
||
void render(unsigned int currentTime) const; | ||
void renderOverlay(unsigned int currentTime) const; | ||
}; | ||
|
||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
#include "GameImpl.h" | ||
#include <ctime> | ||
#include <memory> | ||
|
||
Board::Board(Renderer &r) : | ||
renderer(r) | ||
{ | ||
rng.seed((unsigned int)std::time(0)); | ||
} | ||
|
||
void Board::applyToAllBlocks(const std::function<void (BlockPtr&)> &f) | ||
{ | ||
for(int i = 0; i < NUM_BLOCK_ROWS; ++i) | ||
{ | ||
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j) | ||
{ | ||
if(!blocks[i][j]) | ||
{ | ||
continue; | ||
} | ||
f(blocks[i][j]); | ||
} | ||
} | ||
} | ||
|
||
BlockPtr Board::findBlock(const std::function<bool (BlockPtr)> &predicate) | ||
{ | ||
for(int i = 0; i < NUM_BLOCK_ROWS; ++i) | ||
{ | ||
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j) | ||
{ | ||
if(!blocks[i][j]) | ||
{ | ||
continue; | ||
} | ||
if(predicate(blocks[i][j])) | ||
{ | ||
return blocks[i][j]; | ||
} | ||
} | ||
} | ||
return nullptr; | ||
} | ||
|
||
void Board::generate() | ||
{ | ||
std::uniform_int<> block_dist(TID_BLOCK_1, TID_BLOCK_1 + NUM_BLOCK_TYPES - 1); | ||
|
||
for(int i = 0; i < NUM_BLOCK_ROWS; ++i) | ||
{ | ||
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j) | ||
{ | ||
BlockPtr block = std::make_shared<Block>(renderer); | ||
block->init(j, i, (TextureID)block_dist(rng)); | ||
blocks[i][j] = block; | ||
} | ||
} | ||
} | ||
|
||
int Board::simulateKills(const unsigned int currentTime) | ||
{ | ||
KillCalculator killCalculator(*this); | ||
killCalculator.calculateKills(); | ||
|
||
int killCount = 0; | ||
applyToAllBlocks([&] (BlockPtr b) { | ||
if(killCalculator.hasKillAt(b->getBoardX(), b->getBoardY())) | ||
{ | ||
b->kill(currentTime); | ||
killCount++; | ||
} | ||
}); | ||
return killCount; | ||
} | ||
|
||
void Board::removeDeadBlocks() | ||
{ | ||
applyToAllBlocks([] (BlockPtr &b) { | ||
if(b->isDead()) | ||
{ | ||
b = nullptr; | ||
} | ||
}); | ||
} | ||
|
||
void Board::simulateFalling(const unsigned int currentTime) | ||
{ | ||
std::uniform_int<> block_dist(TID_BLOCK_1, TID_BLOCK_1 + NUM_BLOCK_TYPES - 1); | ||
int numBlocksGenerated[NUM_BLOCK_COLUMNS]; | ||
for(int i = 0; i < NUM_BLOCK_COLUMNS; ++i) | ||
{ | ||
numBlocksGenerated[i] = 0; | ||
} | ||
for(int i = 0; i < NUM_BLOCK_ROWS; ++i) | ||
{ | ||
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j) | ||
{ | ||
|
||
int reverseRowIndex = NUM_BLOCK_ROWS - i - 1; | ||
if(blocks[reverseRowIndex][j]) | ||
{ | ||
continue; | ||
} | ||
//search for block that can fall to this position | ||
bool blockFound = false; | ||
int testRow; | ||
for(testRow = reverseRowIndex - 1; testRow >= 0; --testRow) | ||
{ | ||
if(!blocks[testRow][j]) | ||
{ | ||
continue; | ||
} | ||
if(blocks[testRow][j]->canMove()) | ||
{ | ||
blockFound = true; | ||
break; | ||
} | ||
} | ||
if(blockFound) | ||
{ | ||
blocks[testRow][j]->fallTo(currentTime, j, reverseRowIndex); | ||
blocks[reverseRowIndex][j] = blocks[testRow][j]; | ||
blocks[testRow][j] = nullptr; | ||
} | ||
else if(testRow == -1) | ||
{ | ||
//generate new | ||
BlockPtr block(new Block(renderer)); | ||
block->init(j, -(numBlocksGenerated[j] + 1), (TextureID)block_dist(rng)); | ||
numBlocksGenerated[j]++; | ||
block->fallTo(currentTime, j, reverseRowIndex); | ||
blocks[reverseRowIndex][j] = block; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#ifndef _BOARD_H_ | ||
#define _BOARD_H_ | ||
|
||
template<typename SrcT, typename DstT> | ||
void mapTable(SrcT mapFrom[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS], | ||
DstT mapTo[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS], | ||
const std::function<DstT (const SrcT&)> &f) | ||
{ | ||
for(int i = 0; i < NUM_BLOCK_ROWS; ++i) | ||
{ | ||
for(int j = 0; j < NUM_BLOCK_COLUMNS; ++j) | ||
{ | ||
mapTo[i][j] = f(mapFrom[i][j]); | ||
} | ||
} | ||
} | ||
|
||
struct Board | ||
{ | ||
Renderer &renderer; | ||
std::mt19937 rng; | ||
|
||
BlockPtr blocks[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS]; | ||
BlockPtr mouseDownBlock; | ||
|
||
Board(Renderer &renderer); | ||
|
||
void applyToAllBlocks(const std::function<void (BlockPtr&)> &f); | ||
BlockPtr findBlock(const std::function<bool (BlockPtr)> &predicate); | ||
|
||
template<typename T> | ||
void mapBlocks(T mapTo[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS], | ||
const std::function<T (const BlockPtr&)> &f) const | ||
{ | ||
mapTable<const BlockPtr, T>(blocks, mapTo, f); | ||
} | ||
|
||
//board logic | ||
void generate(); | ||
//return number of blocks killed | ||
int simulateKills(unsigned int currentTime); | ||
void removeDeadBlocks(); | ||
//check for falling blocks/new blocks | ||
void simulateFalling(unsigned int currentTime); | ||
}; | ||
|
||
typedef std::shared_ptr<Board> BoardPtr; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#include "GameImpl.h" | ||
#include "SDL.h" | ||
#include <sstream> | ||
|
||
Game::impl::impl(Renderer &r) : | ||
renderer(r), | ||
board(new Board(r)), | ||
gameStarted(false), | ||
gameStartTime(0), | ||
gameStopTime(0), | ||
timeLeftSeconds(TIME_LIMIT), | ||
score(0), | ||
firstGame(true) | ||
{ | ||
} | ||
|
||
Game::impl::~impl() | ||
{ | ||
} | ||
|
||
void Game::impl::render(const unsigned int currentTime) | ||
{ | ||
renderer.clear(); | ||
renderer.drawBackground(TID_BACKGROUND); | ||
|
||
renderer.setClipRect(BOARD_POS_X, BOARD_POS_Y, NUM_BLOCK_COLUMNS * BLOCK_SIZE_X, NUM_BLOCK_ROWS * BLOCK_SIZE_Y); | ||
|
||
board->applyToAllBlocks([&] (BlockPtr b) { | ||
b->simulate(currentTime); | ||
b->render(currentTime); | ||
}); | ||
|
||
|
||
board->applyToAllBlocks([&] (BlockPtr b) { | ||
b->renderOverlay(currentTime); | ||
}); | ||
|
||
renderer.resetClipRect(); | ||
|
||
std::ostringstream timeStream; | ||
timeStream << "Time: " << timeLeftSeconds; | ||
renderer.drawText(timeStream.str().c_str(), 25, 125); | ||
|
||
std::ostringstream scoreStream; | ||
scoreStream << "Score: " << score; | ||
renderer.drawText(scoreStream.str().c_str(), 25, 175); | ||
|
||
renderer.present(); | ||
} | ||
|
||
void Game::impl::runEventLoop() | ||
{ | ||
board->generate(); | ||
|
||
bool quit = false; | ||
|
||
while(!quit) | ||
{ | ||
unsigned int currentTime = SDL_GetTicks(); | ||
|
||
if(pollEvents(currentTime)) | ||
{ | ||
quit = true; | ||
} | ||
|
||
simulate(currentTime); | ||
|
||
render(currentTime); | ||
} | ||
} | ||
|
||
Game::Game(Renderer &r) | ||
{ | ||
pimpl = std::unique_ptr<impl>(new impl(r)); | ||
} | ||
|
||
Game::~Game() | ||
{ | ||
} | ||
|
||
void Game::runEventLoop() | ||
{ | ||
pimpl->runEventLoop(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
|
||
#ifndef _GAME_H_ | ||
#define _GAME_H_ | ||
|
||
#include "Block.h" | ||
|
||
const int NUM_BLOCK_TYPES = 5; | ||
const int NUM_BLOCK_COLUMNS = 8; | ||
const int NUM_BLOCK_ROWS = 8; | ||
|
||
class Game | ||
{ | ||
struct impl; | ||
std::unique_ptr<impl> pimpl; | ||
public: | ||
Game(Renderer &r); | ||
~Game(); | ||
|
||
void runEventLoop(); | ||
}; | ||
|
||
#endif |
Oops, something went wrong.