I have been trying to create a top-down game, similar to that of 'realm of the mad gods'. I am having some issues with getting my player movement to behave properly with my player movement.
Some things to keep in mind. There are 4 buffers located on each side of my player which is 1 pixel thick. When the player collides with a wall at a speed of 1 pixel, the player will stop and behaves as expected.
Here is the issue. I want my player to move faster than 1 pixel, but when I increase the player speed to 4 pixels, the player will move into the wall. this makes sense, but I have taken measures to avoid this, but have been unsuccessful so far.
Code sample 1 shows the movement code.
Code sample 2 shows the movement trigger code.
I have put the rest of the code on GitHub, which can be found through the following link: https://github.com/Quinn-R/top-down-tech-demo
Thanks for any help I receive.
EDIT: My player does not completely surpass the wall. Both the player and the wall are 32 pixel boxes.
EDIT2: Code sample 3 is the code that shows the game loop.
Code sample 1
void player::move(std::string direction, std::vector<wall> walls)
{
if(direction == "left")
{
for(int i = 0; i < walls.size(); i++)
{
if(leftBuf.getGlobalBounds().intersects(walls[i].wall1.getGlobalBounds())/* || leftBuf.getGlobalBounds().intersects(walls2[i].wall1.getGlobalBounds())*/)
{
//collideTop = 0;
//collideBottom = 0;
collideLeft = 1;
//collideRight = 0;
}
}
if(collideLeft != 1)
{
character.move(-1, 0);
collideTop = 0;
collideBottom = 0;
collideLeft = 0;
collideRight = 0;
}
}
if(direction == "right")
{
for(int i = 0; i < walls.size(); i++)
{
if(rightBuf.getGlobalBounds().intersects(walls[i].wall1.getGlobalBounds())/* || rightBuf.getGlobalBounds().intersects(walls2[i].wall1.getGlobalBounds())*/)
{
//collideTop = 0;
//collideBottom = 0;
//collideLeft = 0;
collideRight = 1;
}
}
if(collideRight != 1)
{
character.move(1, 0);
collideTop = 0;
collideBottom = 0;
collideLeft = 0;
collideRight = 0;
}
}
if(direction == "up")
{
for(int i = 0; i < walls.size(); i++)
{
if(topBuf.getGlobalBounds().intersects(walls[i].wall1.getGlobalBounds())/* || topBuf.getGlobalBounds().intersects(walls2[i].wall1.getGlobalBounds())*/)
{
collideTop = 1;
//collideBottom = 0;
//collideLeft = 0;
//collideRight = 0;
}
}
if(collideTop != 1)
{
character.move(0, -1);
collideTop = 0;
collideBottom = 0;
collideLeft = 0;
collideRight = 0;
}
}
if(direction == "down")
{
for(int i = 0; i < walls.size(); i++)
{
if(bottomBuf.getGlobalBounds().intersects(walls[i].wall1.getGlobalBounds())/* || bottomBuf.getGlobalBounds().intersects(walls2[i].wall1.getGlobalBounds()*/)
{
//collideTop = 0;
collideBottom = 1;
//collideLeft = 0;
//collideRight = 0;
}
}
if(collideBottom != 1)
{
character.move(0, 1);
collideTop = 0;
collideBottom = 0;
collideLeft = 0;
collideRight = 0;
}
}
}
Code sample 2
void sfml1::buttonPressed()
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
for(int i = 0; i < speed; i++)
{
players[0].move("left", walls);
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
for(int i = 0; i < speed; i++)
{
players[0].move("right", walls);
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
for(int i = 0; i < speed; i++)
{
players[0].move("up", walls);
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
for(int i = 0; i < speed; i++)
{
players[0].move("down", walls);
}
}
}
Code sample 3
void sfml1::sfmlLoop()
{
setWalls();
while(window.isOpen())
{
update();
buttonPressed();
update();
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();
/*if (event.type == sf::Event::Resized)
{
// update the view to the new size of the window
//event.size.width, event.size.height);
//view1.setWidth();
//view1.setViewport(sf::FloatRect(0, 0, 1, 1.5f));
view1.scale(1, 1);
window.setView(view1);
}*/
}
draw();
}
}
While inside the buttonPressed() function, your character's state is defined by its collision buffers. When you make this call:
for(int i = 0; i < speed; i++)
{
players[0].move("right", walls);
}
The move() function has the potential of changing the player's state, but this is not reflected in the player's collision buffer. You move speed times to the right while making the collision check from your initial position speed times.
All you need to do is call bufUpdate() at the end of your move() function. This will ensure that after the movement has been resolved, your collision buffer is updated.
Related
I am doing an assignment where we have to make a sliding tile puzzle. The issue is that my print method for printing the game board is outputting the memory address of my 2D array instead of the actual values, but I have no idea how to fix this. I've tried looking up solutions and all I can find is stuff about vectors which I'm not allowed to use.
code from driver.cpp:
#include <iostream>
#include <conio.h>
#include "Specification.h"
#include <windows.h> //For color in PrintBoard()
using namespace std;
// direction codes (part of the slideTile() interface)
#define SLIDE_UP 1 // pass to slideTile() to trigger UP movement
#define SLIDE_DOWN 2 // pass to slideTile() to trigger DOWN movement
#define SLIDE_LEFT 3 // pass to slideTile() to trigger LEFT movement
#define SLIDE_RIGHT 4 // pass to slideTile() to trigger RIGHT movement
int main() {
int tempHeight;
int tempWidth;
// instantiate the class
cout << "Please enter the height for the board: ";
cin >> tempHeight;
cout << "Please enter the width for the board: ";
cin >> tempWidth;
bool exit = false;
SlidingPuzzle somePuzzle(tempHeight, tempWidth);
char keyStroke = ' ';
somePuzzle.isBoardSolved();
cout << "Press any key to begin..." << endl;
_getch();
cout << endl << "Scrambling the tiles..." << endl;
somePuzzle.ScrambleBoard();
cout << "Scrambling complete, press any key to begin solving." << endl;
_getch();
somePuzzle.isBoardSolved();
do {
cout << endl << "(w = Up, s = Down, a = Left, d = Right, e = Exit Game)" << endl;
cout << "Which way to slide?" << endl;
keyStroke = _getch(); //sets the key used to continue as the move, keys that aren't options do nothing
switch (keyStroke) {
case 'w':
{
somePuzzle.SlideTile(SLIDE_UP);
break;
}
case 's':
{
somePuzzle.SlideTile(SLIDE_DOWN);
break;
}
case 'a':
{
somePuzzle.SlideTile(SLIDE_LEFT);
break;
}
case 'd':
{
somePuzzle.SlideTile(SLIDE_RIGHT);
break;
}
case 'e':
{
exit = true;
somePuzzle.~SlidingPuzzle();
break;
}
}
} while (!somePuzzle.isBoardSolved() || !exit);
// Exit
_getch();
return 0;
}
code from specification.h:
#ifndef __SlidingPuzzle__
#define __SlidingPuzzle__
#include <iostream>
#include <windows.h> //For color in PrintBoard()
using namespace std;
// CLASS SlidingPuzzle
class SlidingPuzzle {
private:
int height;
int width;
int** theBoard;
int** solvedBoard;
HANDLE currentConsoleHandle;
void cls(HANDLE);
public:
// CONSTRUCTOR
SlidingPuzzle(); //Gives default values to the SlidingPuzzle's attributes
SlidingPuzzle(int, int);
//Deconstructor
~SlidingPuzzle();
//Getter
int getHeight();
int getWidth();
int** getTheBoard();
int** getSolvedBoard();
//Methods
void InitializeBoard();
bool isBoardSolved();
bool SlideTile(int);
void ScrambleBoard();
void PrintBoard();
}; // end - SlidingPuzzle
#endif
code from implementation.cpp:
#include "Specification.h"
// CONSTRUCTOR
SlidingPuzzle::SlidingPuzzle() {
this->height = 0;
this->width = 0;
this->theBoard = NULL;
this->solvedBoard = NULL;
this->currentConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
}
// Overload
SlidingPuzzle::SlidingPuzzle(int newWidth, int newHeight) {
this->currentConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (newHeight > 0) {
this->height = newHeight;
}
else {
this->height = 0;
}
if (newWidth > 0) {
this->width = newWidth;
}
else {
this->width = 0;
}
this->theBoard = new int* [this->height];
for (int i = 0; i < this->height; i++) {
this->theBoard[i] = new int[this->width];
}
this->solvedBoard = new int* [this->height];
for (int i = 0; i < this->height; i++) {
this->solvedBoard[i] = new int [this->width];
}
}
//Getters
int SlidingPuzzle::getHeight() {
return this->height;
}
int SlidingPuzzle::getWidth() {
return this->width;
}
int** SlidingPuzzle::getTheBoard() {
return this->theBoard;
}
int** SlidingPuzzle::getSolvedBoard() {
return this->solvedBoard;
}
//Deconstructor
SlidingPuzzle::~SlidingPuzzle() {
for (int i = 0; i < this->height; ++i)
delete[] this->theBoard[i];
delete[] this->theBoard;
}
//Methods
void SlidingPuzzle::InitializeBoard() {
for (int i = 0; i < this->height; i++) {
for (int j = 0; j < this->width; j++) {
if (i == 0) {
this->theBoard[i][j] = i + j + 1;
}
else if (i == 1) {
this->theBoard[i][j] = i + j + 3;
}
else {
this->theBoard[i][j] = i + j + 5;
if (this->theBoard[i][j] == (this->width * this->height)) {
this->theBoard[i][j] = -1;
}
}
}
}
}
bool SlidingPuzzle::isBoardSolved() {
this->cls(currentConsoleHandle);
this->PrintBoard();
int correct = 0;
//Checks each position to see if the are identical
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (this->theBoard[i][j] != this->solvedBoard[i][j]) {
correct = 1;
}
}
}
if (correct == 0) {
cout << "isBoardSolved(): true" << endl;
return true;
}
else {
cout << "isBoardSolved(): false" << endl;
return false;
}
}
bool SlidingPuzzle::SlideTile(int directionCode) {
int row = 0;
int col = 0;
int rowSpace = 0;
int colSpace = 0;
//Finds the pivot space
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
if (this->theBoard[i][j] == -1) {
row = i;
col = j;
}
}
}
switch (directionCode) {
case 1:
{
rowSpace = row - 1;
colSpace = col;
break;
}
case 2:
{
rowSpace = row + 1;
colSpace = col;
break;
}
case 3:
{
rowSpace = row;
colSpace = col - 1;
break;
}
case 4:
{
rowSpace = row;
colSpace = col + 1;
break;
}
}
//Ensures that the program doesn't break from trying to move off the board
if (rowSpace >= 0 && rowSpace < height && colSpace >= 0 && colSpace < width) {
this->theBoard[row][col] = this->theBoard[rowSpace][colSpace];
this->theBoard[rowSpace][colSpace] = -1;
}
return false;
}
void SlidingPuzzle::ScrambleBoard() {
for (int i = 0; i < 10000; i++) {
int move = (rand() % 4);
move++; //Add 1 so the variable matches the values for the directions
this->SlideTile(move);
}
}
void SlidingPuzzle::PrintBoard() { //Refuses to print, no clue why
HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (this->theBoard[i][j] == -1) {
cout << " *";
}
else {
if (this->theBoard[i][j] == this->solvedBoard[i][j]) {
SetConsoleTextAttribute(hConsole, 2); //changes the color to green for correct postion
cout << " " << this->theBoard[i][j];
SetConsoleTextAttribute(hConsole, 15); //reverts color to normal
}
else {
SetConsoleTextAttribute(hConsole, 4); //changes the color to red for incorrect postion
cout << " " << this->theBoard[i][j];
SetConsoleTextAttribute(hConsole, 15); //reverts color to normal
}
}
}
cout << endl;
}
}
void SlidingPuzzle::cls(HANDLE hConsole)
{
COORD coordScreen = { 0, 0 }; /* here's where we'll home the
cursor */
BOOL bSuccess;
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
DWORD dwConSize; /* number of character cells in
the current buffer */
/* get the number of character cells in the current buffer */
bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
/* fill the entire screen with blanks */
bSuccess = FillConsoleOutputCharacter(hConsole, (TCHAR)' ',
dwConSize, coordScreen, &cCharsWritten);
/* get the current text attribute */
bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
/* now set the buffer's attributes accordingly */
bSuccess = FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
dwConSize, coordScreen, &cCharsWritten);
/* put the cursor at (0, 0) */
bSuccess = SetConsoleCursorPosition(hConsole, coordScreen);
}
I have used the suggestions from the comments and now I am finally getting the array to display. However the values in the array are still displaying as memory addresses. I updated the code here to reflect the changes made so far.
I forgot to add somePuzzle.InitializeBoard(); to the driver.cpp and I feel like a goof now. Thank you all for helping me and sorry about not posting a minimal reproducible example. Thank you Igor Tandetnik and Retired Ninja for pointing out the issues I had and helping me out.
I tried to code a simple version of tic-tac-toe in C++ using the minimax algorithm but ran into a problem while trying to determine the position where the score is the best. The minEval (Returns score for min), maxEval(returns score for max) and playMove (determines which position to play and then plays the move) functions are shown below.
int maxEval(int board[9]) {
if (checkDraw(board)) {
return 0;
}
else if (checkWin(board)) {
return -1000;
}
int finalScore = -1000;
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = 1;
int score = minEval(board);
if (score > finalScore) {
finalScore = score;
}
board[i] = 0;
}
}
return finalScore;
}
int minEval(int board[9]) {
if (checkDraw(board)) {
return 0;
}
else if (checkWin(board)) {
return 1000;
}
int finalScore = 1000;
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = -1;
int score = maxEval(board);
if (score < finalScore) {
finalScore = score;
}
board[i] = 0;
}
}
return finalScore;
}
void playMove(int board[9], int player) {
int finalScore = player * -1000;
int position;
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = player;
int score;
if (player == 1) {
score = maxEval(board);
}
else {
score = minEval(board);
}
if (player == 1 && score >= finalScore) {
finalScore = score;
position = i;
}
else if (player == -1 && score <= finalScore) {
finalScore = score;
position = i;
}
board[i] = 0;
}
}
board[position] = player;
}
When I tested different positions to see whether minEval and maxEval correctly evaluate the position, the functions return the correct score (1000 for max win, -1000 for min win and 0 for a draw). However, when I make the AI play by using the playMove function, it plays very dubious moves and almost always makes "incorrect" moves.
Here is an example of a game I made the program play (with itself):
I suspect that there is something wrong with the way I set position to i, but I tried to make changes to no avail. Any suggestions as to what is wrong with the evaluate function? Thanks.
Here is the link to the entire code: http://ideone.com/6791d4
I would check up on the variations found not just the scores. Are you finding just any winning variation, or the one where the opponent plays best?
e.g. Modify your min/max Eval code to also add the move chosen to an array.
BTW it may be easier to see what is happening if you combine the min/max Eval routines into one.
WARNING UNTESTED CODE
int minmaxEval(int board[9], int player, int moves[9], int move) {
if (checkDraw(board)) {
return 0;
}
int finalScore = player * -1000;
if (checkWin(board)) {
return finalScore;
}
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = player;
int score = minmaxEval(board, -player, moves, move+1);
if ( (player > 0 && score > finalScore) ||
(player < 0 && score < finalScore) ) {
finalScore = score;
moves[move] = i;
}
board[i] = 0;
}
}
return finalScore;
}
If you print out moves[] in your toplevel routine you should see the variation which gave that score. A mismatch there will inform your understanding of the algorithm e.g. is it stopping when it finds a win.
In general it is important to have a way to double check your code is doing what you expect. Look into unit testing and test-driven development.
Thanks for your insights, I solved the problem. There was a bug in the playMove function, where I mismatched maxEval and minEval, this causing the AI to not play for a win or draw. So, the corrected code is:
void playMove(int board[9], int player) {
int finalScore = player * -1000;
int position;
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = player;
int score;
if (player == 1) {
score = minEval(board); //Previously Mismatched
}
else {
score = maxEval(board); //Previously Mismatched
}
if (player == 1 && score >= finalScore) {
finalScore = score;
position = i;
}
else if (player == -1 && score <= finalScore) {
finalScore = score;
position = i;
}
board[i] = 0;
}
}
board[position] = player;
}
I have this code:
void generar() {
while (true) {
if (yPos == topOfTheWorld) {
scene[xPos][yPos] = 2;
} else if (yPos >= topOfTheWorld) {
scene[xPos][yPos] = 1;
} else if(yPos < topOfTheWorld) {
scene[xPos][yPos] = 0;
} else {
scene[xPos][yPos] = 0;
}
yPos++;
if(yPos>worldHeight) {
topOfTheWorld += 0;
yPos = 0;
xPos++;
}
if (xPos>worldWidth) {
break;
}
}
std::ofstream output("mapa.txt");
for(int y=0;y<worldHeight;y++) {
for(int x=0;x<worldWidth;x++) {
output<<scene[x][y];
if(x<(worldWidth-1)){output<<",";}
}
if(y<(worldHeight-1)){output<<std::endl;}
}
MessageBox(0, "World generation has finished!", "Finished!", MB_OK);
}
That generates a world based in an array. But when I add:
slope = random(5)-2;
To:
if(yPos == worldHeight) {
topOfTheWorld += 0; //There would be the slope var...
if(yPos == worldHeight) {
slope = random(5)-2;
topOfTheWorld += slope;
For some reason the while becomes an infinite loop, and I don't know why.
(Random Function)
#include <time.h>
#include <windows.h>
int random(int n = 0) {
srand(time(NULL));
if(n!=0){
return rand() % n;
} else {
return rand();
}
}
(Variables)
const int worldWidth = 50;
const int worldHeight = 26;
int topOfTheWorld = worldHeight/2;
int xPos = 0;
int yPos = 0;
int scene[worldWidth][worldHeight];
int slope;
What can I do?
You show that scene is defined as:
int scene[worldWidth][worldHeight];
However, your code has this:
if (xPos>worldWidth) {
break;
}
Which means you will actually write a value outside the array boundary when xPos == worldWidth, and this causes undefined behavior. Adding the slope variable may cause your variable organization to change in a way that the undefined behavior ends up affecting the values of and or all of your loop control variables.
To fix, you should change the erroneous check with:
if (xPos>=worldWidth) {
break;
}
You have since edited your question with code that makes your yPos check incorrect in a similar way.
There's a repeated calls to srand in your random function
Fixes : -
void generar() {
srand(time(NULL)); //Remove srand() from random(), add it here
bool finished = false;
while (!finished) {
if (yPos == topOfTheWorld) {
scene[xPos][yPos] = 2;
} else if (yPos >= topOfTheWorld) {
scene[xPos][yPos] = 1;
} else if(yPos < topOfTheWorld) {
scene[xPos][yPos] = 0;
} else {
scene[xPos][yPos] = 0;
}
yPos++;
if(yPos == worldHeight) {
// slope = random(5)-2; your random call
topOfTheWorld += 0;
yPos = 0;
xPos++;
}
if (xPos>worldWidth) {
finished = true;
//goto Guardar; not required,
//also use of goto is bad programming practice
}
}
I saw Conway's Game of Life and decided to make my own.
I have a bool array to represent the world, but the edges (Top and bottom) are acting weird, random cells becomes live.
In this code, it does not print the bottom and top of the world, but this is a bad solution.
The world "wraps" at the right and the left, causing even more problems, but that is for another time.
#include <iostream>
const int height = 20;
const int width = 20;
bool now_world[height][width];
bool then_world[height][width];
void clear_world();
void place_random_live_cells();
void then_world_initialization();
void print_world();
void generation_pass();
void update_worlds();
int main(int argc, const char * argv[])
{
using namespace std;
srand((unsigned)time(NULL));
int timer = 0;
int generation = 0;
clear_world();
place_random_live_cells();
then_world_initialization();
bool running = true;
while (running) {
if (timer == 50000000) {
cout << "Generation #" << generation << endl;
print_world();
generation_pass();
update_worlds();
++generation;
timer = 0;
}
++timer;
}//While (running) ends here
return 0;
}
void place_random_live_cells()
{
int percent = 30;
int max_live_cells = ((height * width) / 100) * percent;
int current_live_cells = 0;
while (current_live_cells < max_live_cells) {
int ycoords = 0 + (rand() % (height + 1));
int xcoords = 0 + (rand() % (width + 1));
if (now_world[ycoords][xcoords] == false) {
now_world[ycoords][xcoords] = true;
} else {
current_live_cells--;
}
++current_live_cells;
}
}
//A generation pass and cells die and some cells come to life
void generation_pass()
{
using namespace std;
int neighbours = 0;
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
//Count neighbouring cells that are alive
if (now_world[iii+1][jjj+1] == true) {
++neighbours;
}
if (now_world[iii+1][jjj ] == true) {
++neighbours;
}
if (now_world[iii+1][jjj-1] == true) {
++neighbours;
}
if (now_world[iii ][jjj+1] == true) {
++neighbours;
}
if (now_world[iii ][jjj-1] == true) {
++neighbours;
}
if (now_world[iii-1][jjj+1] == true) {
++neighbours;
}
if (now_world[iii-1][jjj ] == true) {
++neighbours;
}
if (now_world[iii-1][jjj-1] == true) {
++neighbours;
}
//Apply rules to the cells
//Dead cells with three live neighbours becomes alive
if (then_world[iii][jjj] == false && neighbours == 3) {
then_world[iii][jjj] = true;
}
//Alive with fewer than two, they die
if (then_world[iii][jjj] == true && neighbours < 2) {
then_world[iii][jjj] = false;
}
//Alive with 2 or three live neighbours live on unchanged
if (then_world[iii][jjj] == true && neighbours == 2) {
then_world[iii][jjj] = true;
}
if (then_world[iii][jjj] == true && neighbours == 3) {
then_world[iii][jjj] = true;
}
//Alive with more than three, they die
if (then_world[iii][jjj] == true && neighbours > 3) {
then_world[iii][jjj] = false;
}
//Dead cells without exactly three live neighbours remain dead
//Reset neighbour value to zero
neighbours = false;
}
}
}
//Make next generation identical to current
//This is only called once
void then_world_initialization()
{
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
then_world[iii][jjj] = now_world[iii][jjj];
}
}
}
//Make the next generation be today
//This is called every generation
void update_worlds()
{
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
now_world[iii][jjj] = then_world[iii][jjj];
}
}
}
//Set all cells to dead
void clear_world()
{
for (long iii = 0; iii < height; iii++) {
for (long jjj = 0; jjj < width; jjj++) {
now_world[iii][jjj] = false;
then_world[iii][jjj] = false;
}
}
}
//Print world
void print_world()
{
using namespace std;
char live = 'X';
char dead = '.';
for (long iii = height; iii > 0; iii--) {
for (long jjj = width; jjj > 0; jjj--) {
if (iii != 0 && iii != height) {
if (now_world[iii][jjj]) {
cout << live;
} else {
cout << dead;
}
cout << " ";
}
}
cout << endl;
}
cout << endl;
}
Having done this for a course I taught in the past, the most common issue I always see people having is going outside the bounds of the array they're using.
If you look at the if statements in your nested for loop, I think you'll find some issues. For instance, in this case, what happens when iii equals (height-1) or jjj equals (width-1)?
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
//Count neighbouring cells that are alive
if (now_world[iii+1][jjj+1] == true) {
++neighbours;
You're going outside the bounds of your array and so your results will be undefined. You may get segfaults, but you may just also get spurious data. C++ doesn't enforce you staying within the bounds of the array you define.
Make sure you also handle cases like this:
if (now_world[iii-1][jjj+1] == true) {
++neighbours;
}
What if iii equals zero?
Hope that helps.
You're trying to access out-of-boundary indexes in your array.
I'm not sure what behaviour you expect, but an easy way is to not calculate updates for cells on the edges.
So in generation_pass the loops should go from 1 till height-1.
This is a bizarre problem. I've got a void function that performs a for loop and nothing else, but the for loop doesn't ever start, even though the function is being called. Here is the function:
void Cell::Consolidate()
{
cout << "Consolidating (outside)...\n";
for(int i = 0; i < m_Tiles.size(); ++i)
{
cout << "Consolidating (inside)...\n";
int row = m_Tiles[i]->GetRow();
int col = m_Tiles[i]->GetCol();
//Check below.
if((*m_pTileMap)[row + 1][col].pParentCell != this)
{
m_EdgeTiles.push_back(m_Tiles[i]);
m_Tiles[i]->SetColor(sf::Color(100, 100, 100));
bool newNeighbor = true;
for(int j = 0; j < m_Neighbors.size(); ++j)
{
if(m_Neighbors[j] == (*m_pTileMap)[row + 1][col].pParentCell)
{
newNeighbor = false;
break;
}
}
if(newNeighbor)
{
m_Neighbors.push_back((*m_pTileMap)[row + 1][col].pParentCell);
}
}
//Check above.
else if((*m_pTileMap)[row - 1][col].pParentCell != this)
{
m_EdgeTiles.push_back(m_Tiles[i]);
m_Tiles[i]->SetColor(sf::Color(100, 100, 100));
bool newNeighbor = true;
for(int j = 0; j < m_Neighbors.size(); ++j)
{
if(m_Neighbors[j] == (*m_pTileMap)[row - 1][col].pParentCell)
{
newNeighbor = false;
break;
}
}
if(newNeighbor)
{
m_Neighbors.push_back((*m_pTileMap)[row - 1][col].pParentCell);
}
}
//Check the right.
else if((*m_pTileMap)[row][col + 1].pParentCell != this)
{
m_EdgeTiles.push_back(m_Tiles[i]);
m_Tiles[i]->SetColor(sf::Color(100, 100, 100));
bool newNeighbor = true;
for(int j = 0; j < m_Neighbors.size(); ++j)
{
if(m_Neighbors[j] == (*m_pTileMap)[row][col + 1].pParentCell)
{
newNeighbor = false;
break;
}
}
if(newNeighbor)
{
m_Neighbors.push_back((*m_pTileMap)[row][col + 1].pParentCell);
}
}
//Check the left.
else if((*m_pTileMap)[row][col - 1].pParentCell != this)
{
m_EdgeTiles.push_back(m_Tiles[i]);
m_Tiles[i]->SetColor(sf::Color(100, 100, 100));
bool newNeighbor = true;
for(int j = 0; j < m_Neighbors.size(); ++j)
{
if(m_Neighbors[j] == (*m_pTileMap)[row][col - 1].pParentCell)
{
newNeighbor = false;
break;
}
}
if(newNeighbor)
{
m_Neighbors.push_back((*m_pTileMap)[row][col - 1].pParentCell);
}
}
}
}
When I run the program, "Consolidating (outside)...\n" gets send to cout, but "Consolidating (inside)...\n" does not. Nothing that is supposed to happen in the loop actually happens, either (for example the SetColor() calls don't do anything, nor does anything happen if I send things to cout anywhere else in the loop), so I can only assume the loop is not starting at all. Why not? What could cause this?
i < m_Tiles.size()
This loop condition gets checked on entrance to the loop, not only after each iteration. If your m_Tiles vector is empty, well, no loop for you.
Most likely, m_Tiles.size() returns a negative value or zero value.