I've been trying to create my roguelike type of game for C++ using the ncurses library. After following many different tutorials, I am able to create the Player character, the map, the code to prevent the Player from going through walls and the random movements for the Monster character.
The next problem I'm encountering is implementing a boolean so whenever the Player character interacts with the Monster character, the game will quit (much like the roguelike games). However, I can't seem to get it to function the way I wanted. I think it has to do with the coordinates that I have set for the Player and the Monster but I'm still not sure. Can anyone help me out please?
Here is the code:
#include <iostream>
#include <ncurses.h>
#define MAP_WIDTH 22
#define MAP_HEIGHT 15
#define TILE_FLOOR 0
#define TILE_WALL 1
int PlayerX, PlayerY;
void erase (int y, int x) {
mvaddch(y, x, '.');
}
int nMapArray[MAP_HEIGHT][MAP_WIDTH] = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
{ 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1 },
{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
};
bool IsPassable (int nMapX, int nMapY) { //prevents from walking into walls
if (nMapX < 0 || nMapX >= MAP_WIDTH || nMapY < 0 || nMapY >= MAP_HEIGHT)
return false;
int nTileValue = nMapArray[nMapY][nMapX];
if( nTileValue == TILE_FLOOR) {
return true;
}
return false;
}
class Monster {
public:
void Appearance(char monster) {
this->Monster = monster;
}
void SetPos(int x, int y) {
this->PosX = x;
this->PosY = y;
}
void Movement(int &MonsX, int &MonsY) {
int x = (rand() % 3 - 1);
int y = (rand() % 3 - 1);
if (IsPassable(this->PosX+x, this->PosY+y)) {
erase(PosY, PosX);
MonsX = this->PosX += x;
mvaddch(this->PosY, MonsX, this->Monster);
refresh();
erase(PosY, PosX);
MonsY = this->PosY += y;
mvaddch(MonsY, this->PosX, this->Monster);
refresh();
}
}
protected:
int PosX;
int PosY;
char Monster;
};
bool MonsterContact (int nMapY, int nMapX, int x, int y) {
if (nMapArray[nMapY][nMapX] == nMapArray[y][x]) {
return true;
}
return false;
}
void map() {
for (int y = 0; y < MAP_HEIGHT; y++) { //loops to print the map
move(y,0);
for (int x = 0; x < MAP_WIDTH; x++) {
switch (nMapArray[y][x]) {
case TILE_FLOOR:
printw(".");
break;
case TILE_WALL:
printw("#");
break;
}
}
}
};
void init() { //starts the ncurses screen.
initscr();
clear();
noecho();
raw();
keypad(stdscr, TRUE);
curs_set(0);
}
void game_loop (char Player, int row, int col, int ch) {
Monster npc;
npc.SetPos(7, 8);
npc.Appearance('g');
int MonsX,MonsY;
mvaddch(row,col, Player); //player movement
refresh();
while(true) {
npc.Movement(MonsX, MonsY);
ch = getch();
switch (ch) {
case 'w':
if (IsPassable(col, row-1)) {
erase(row,col);
row = row - 1;
mvaddch(row, col, Player);
refresh();
}
if (MonsterContact(col, row, MonsX, MonsY)) {
return();
}
break;
case 's':
if (IsPassable(col, row+1)) {
erase(row, col);
row = row + 1;
mvaddch(row, col, Player);
refresh();
}
if (MonsterContact(col, row, MonsX, MonsY)) {
return();
}
break;
case 'a':
if (IsPassable(col-1, row)) {
erase(row,col);
col = col - 1;
mvaddch(row, col, Player);
refresh();
}
if (MonsterContact(col, row, MonsX, MonsY)) {
return();
}
break;
case 'd':
if (IsPassable(col+1, row)) {
erase(row,col);
col = col + 1;
mvaddch(row,col, Player);
refresh();
}
if (MonsterContact(col, row, MonsX, MonsY)) {
return();
}
break;
case 'q':
return;
default:
break;
}
}
}
int main(int argc, const char * argv[]) {
PlayerX = 2, PlayerY = 1; //Player initial position.
char Player = '#';
init(); //starts the ncurses screen.
printw("Press any key to start the game");
int ch = getch();
clear();
map();
game_loop(Player, PlayerY, PlayerX, ch);
endwin();
return 0;
}
I'll sum up what jonhopkins commented on.
This is essentially a result of inconsistency. Your code passes arguments in different orders in different functions (first x, then y in isPassable, but vice versa in MonsterContact), and uses different names for the same things (row and x are the same.)
Your problem is caused by the fact that you passed col, row into MonsterContact, when you should have passed row, col. Perhaps you subconsciously copied the order of arguments from when you wrote isPassable a little earlier, forgetting that the order of arguments is reversed. Or you momentarily mistakenly thought that col meant y and row meant x.
Always remember to keep your code as consistent as possible, and you can avoid these sorts of mistakes in the future.
Related
I'm looking to iteratively create a set of rectangle shapes of different colours and display them on the screen in different positions. This should produce a maze made up of rectangles.
The positions of the shapes should reflect the array that stores a 9x9 maze.
I'm able to successfully create a single shape, change it's colour and position. However, when I try to do the same to a shape inside an array it does not work. Only a single blue rectangle is generated in the top right corner of the screen.
int main() {
sf::RenderWindow window(sf::VideoMode(1920, 1080), "Baphomet");
sf::RectangleShape tiles[81] = {sf::RectangleShape(sf::Vector2f(20, 20))};
char maze[81] = {0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 1, 0, 1, 1, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 1, 1, 0, 1, 0, 1, 0,
0, 0, 0, 1, 0, 1, 0, 1, 0,
0, 1, 1, 1, 0, 1, 1, 1, 0,
0, 0, 1, 0, 0, 0, 1, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0};
int x;
int y;
for (int i = 0; i < 81; i++) {
if (maze[i] == 0) {
tiles[i].setFillColor(sf::Color::Blue);
} else if (maze[i] == 1) {
tiles[i].setFillColor(sf::Color::Red);
}
x = (i % 9) * 20;
y = (i / 9) * 20;
std::cout << x << " " << y << std::endl;
tiles[i].setPosition((float)x, (float)y);
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
for (int i = 0; i < 81; i++) {
window.draw(tiles[i]);
}
window.display();
}
return 0;
}
How can I make the shapes change their positions to the x and y variables successfully?
I think the main problem is the definition
sf::RectangleShape tiles[81] = {sf::RectangleShape(sf::Vector2f(20, 20))};
Here you explicitly initialize only the first element (tiles[0]). All the rest of the elements will only have default-constructed shape objects.
To properly initialize all elements to the same values, either use a loop
for (auto& shape : tiles)
shape = sf::RectangleShape(sf::Vector2f(20, 20));
Or use a vector
std::vector<sf::RectangleShape> tiles(81, sf::RectangleShape(sf::Vector2f(20, 20)));
im currently trying to code Pacman in C++. Im doing it in RAD Studio 10.2 (Embarcadero IDE) because we have to use it. I implemented a C++-Source-Code for the Ghost-Pathfinding from the Internet. But it never finds a path.
First things first - this is my the source code (that matters for the problem):
static int map[ROWS][COLUMNS] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{ 1, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 2, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 7, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 7, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 3, 1, 1, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 3, 3, 3, 3, 3, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 3, 12, 3, 13, 3, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 3, 3, 14, 3, 3, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 3, 1, 0, 1, 3, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1 },
{ 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1 },
{ 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1 },
{ 1, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 2, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
};
const int n = 60; // horizontal size of the map
const int m = 60; // vertical size size of the map
static int closed_nodes_map[n][m]; // map of closed (tried-out) nodes
static int open_nodes_map[n][m]; // map of open (not-yet-tried) nodes
static int dir_map[n][m]; // map of directions
const int dir = 4; // number of possible directions to go at any position
static int dx[dir] = { 1, 0, -1, 0 };
static int dy[dir] = { 0, 1, 0, -1 };
int Gx, Gy, Px, Py;
using namespace std;
void TForm1::GhostMove(Ghost *ghost) {
Gx = ((ghost->X)-((ghost->X)%32))/32;
Gy = ((ghost->Y)-((ghost->Y)%32))/32;
Px = ((player->X)-((player->X)%32))/32;
Py = ((player->Y)-((player->Y)%32))/32;
Label1->Caption = Py;
string st = pathFind(Gx, Gy, Px, Py);
UnicodeString str = st.c_str();
}
string pathFind(const int &xStart, const int &yStart,
const int &xFinish, const int &yFinish) {
static priority_queue<node> pq[2]; // list of open (not-yet-tried) nodes
static int pqi; // pq index
static node* n0;
static node* m0;
static int i, j, x, y, xdx, ydy;
static char c;
pqi = 0;
// reset the node maps
for (y = 0; y<m; y++)
{
for (x = 0; x<n; x++)
{
closed_nodes_map[x][y] = 0;
open_nodes_map[x][y] = 0;
}
}
// create the start node and push into list of open nodes
n0 = new node(xStart, yStart, 0, 0);
n0->updatePriority(xFinish, yFinish);
pq[pqi].push(*n0);
open_nodes_map[x][y] = n0->getPriority(); // mark it on the open nodes map
// A* search
while (!pq[pqi].empty())
{
// get the current node w/ the highest priority
// from the list of open nodes
n0 = new node(pq[pqi].top().getxPos(), pq[pqi].top().getyPos(),
pq[pqi].top().getLevel(), pq[pqi].top().getPriority());
x = n0->getxPos(); y = n0->getyPos();
pq[pqi].pop(); // remove the node from the open list
open_nodes_map[x][y] = 0;
// mark it on the closed nodes map
closed_nodes_map[x][y] = 1;
// quit searching when the goal state is reached
//if((*n0).estimate(xFinish, yFinish) == 0)
if (x == xFinish && y == yFinish)
{
// generate the path from finish to start
// by following the directions
string path = "";
while (!(x == xStart && y == yStart))
{
j = dir_map[x][y];
c = '0' + (j + dir / 2) % dir;
path = c + path;
x += dx[j];
y += dy[j];
}
// garbage collection
delete n0;
// empty the leftover nodes
while (!pq[pqi].empty()) pq[pqi].pop();
return path;
}
// generate moves (child nodes) in all possible directions
for (i = 0; i<dir; i++)
{
xdx = x + dx[i]; ydy = y + dy[i];
if (!(xdx<0 || xdx>n - 1 || ydy<0 || ydy>m - 1 || map[xdx][ydy] == 1
|| closed_nodes_map[xdx][ydy] == 1))
{
// generate a child node
m0 = new node(xdx, ydy, n0->getLevel(),
n0->getPriority());
m0->nextLevel(i);
m0->updatePriority(xFinish, yFinish);
// if it is not in the open list then add into that
if (open_nodes_map[xdx][ydy] == 0)
{
open_nodes_map[xdx][ydy] = m0->getPriority();
pq[pqi].push(*m0);
// mark its parent node direction
dir_map[xdx][ydy] = (i + dir / 2) % dir;
}
else if (open_nodes_map[xdx][ydy]>m0->getPriority())
{
// update the priority info
open_nodes_map[xdx][ydy] = m0->getPriority();
// update the parent direction info
dir_map[xdx][ydy] = (i + dir / 2) % dir;
// replace the node
// by emptying one pq to the other one
// except the node to be replaced will be ignored
// and the new node will be pushed in instead
while (!(pq[pqi].top().getxPos() == xdx &&
pq[pqi].top().getyPos() == ydy))
{
pq[1 - pqi].push(pq[pqi].top());
pq[pqi].pop();
}
pq[pqi].pop(); // remove the wanted node
// empty the larger size pq to the smaller one
if (pq[pqi].size()>pq[1 - pqi].size()) pqi = 1 - pqi;
while (!pq[pqi].empty())
{
pq[1 - pqi].push(pq[pqi].top());
pq[pqi].pop();
}
pqi = 1 - pqi;
pq[pqi].push(*m0); // add the better node instead
}
else delete m0; // garbage collection
}
}
delete n0; // garbage collection
}
return ""; // no route found
}
So as you can see it first creates a map - this looks like this:
(Each Tile is 32*32)
Then for the GhostMoving it tries to find the shortest path to the Player.
But if click the Button for Testing the result/my teststring/testlabel is "" which means no path got found.
I dont really unterstand this because like in the extern algorithm code from the internet my Obstacles(Walls) are 1 in the map array.
So I dont really see through all this - is it maybe because of the Tilesize?
Thanks for your help
I'd like to know if I translated a piece of code correctly from C++ to Delphi.
It looks like it is working, but I have a feeling that I'm reading and writing into memory that I'm not supposed to using Delphi.
Given C++ code:
struct tile_map
{
int32 CountX;
int32 CountY;
uint32 *Tiles;
};
inline uint32
GetTileValueUnchecked(tile_map *TileMap, int32 TileX, int32 TileY)
{
uint32 TileMapValue = TileMap->Tiles[TileY*TileMap->CountX + TileX];
return(TileMapValue);
}
uint32 Tiles00[9][17] =
{
{1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};
// More tile map declarations ...
// uint32 Tiles01[9][17] = ...
// uint32 Tiles10[9][17] = ...
// uint32 Tiles11[9][17] = ...
tile_map TileMaps[2][2];
TileMaps[0][0].CountX = 17;
TileMaps[0][0].CountY = 9;
TileMaps[0][0].Tiles = (uint32 *)Tiles00;
TileMaps[0][1] = TileMaps[0][0];
TileMaps[0][1].Tiles = (uint32 *)Tiles01;
TileMaps[1][0] = TileMaps[0][0];
TileMaps[1][0].Tiles = (uint32 *)Tiles10;
TileMaps[1][1] = TileMaps[0][0];
TileMaps[1][1].Tiles = (uint32 *)Tiles11;
// Usage
int32 PlayerTileX = 2;
int32 PlayerTileY = 2;
uint32 TileMapValue = GetTileValueUnchecked(&TileMap[1][1], PlayerTileX, PlayerTileY);
Delphi translation:
program Project1;
{$APPTYPE CONSOLE}
type
Puint32 = ^uint32;
tile_map = record
CountX : int32;
CountY : int32;
Tiles : Puint32;
end;
Ptile_map = ^tile_map;
{$POINTERMATH ON}
function GetTileValueUnchecked(TileMap : Ptile_map; TileX, TileY : int32) : uint32; inline;
begin
result := TileMap^.Tiles[TileY * TileMap^.CountX + TileX];
end;
const //in the future these will be read from file, so const for now
Tiles00: array [0..8, 0..16] of uint32 =
(
(1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
);
// More tile map declarations ...
//Tiles01: array [0..8, 0..16] of uint32 = ...
//Tiles10: array [0..8, 0..16] of uint32 = ...
//Tiles11: array [0..8, 0..16] of uint32 = ...
var
TileMaps : array [0..1, 0..1] of tile_map;
PlayerTileX, PlayerTileY : int32;
TileMapValue : uint32;
begin
TileMaps[0][0].CountX := 17;
TileMaps[0][0].CountY := 9;
TileMaps[0][0].Tiles := Addr(Tiles00);
TileMaps[0][1] := TileMaps[0][0];
TileMaps[0][1].Tiles := Addr(Tiles01);
TileMaps[1][0] := TileMaps[0][0];
TileMaps[1][0].Tiles := Addr(Tiles10);
TileMaps[1][1] := TileMaps[0][0];
TileMaps[1][1].Tiles := Addr(Tiles11);
// Usage
PlayerTileX := 2;
PlayerTileY := 2;
TileMapValue = GetTileValueUnchecked(#TileMaps[1][1], PlayerTileX, PlayerTileY);
end.
David Heffernan's comments has been helpful and others seem to agree that the code is correct, so I will mark this as answered.
I have a .cpp file that must include Console.h. In the file I'm trying to create a map (used later on for a game).
Error C2086: 'int nMapArray[15][20]: redefinition
#include "Console.h"
#include <Windows.h>
#include <stdint.h>
// Map dimensions
#define MAP_WIDTH 20
#define MAP_HEIGHT 15
// Tile Types
#define TILE_FLOOR 0
#define TILE_WALL 1
// Map declaration
int nMapArray[ MAP_HEIGHT ][ MAP_WIDTH ];
// Map Layout
int nMapArray[ MAP_HEIGHT ][ MAP_WIDTH ]=
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
I know that I'm only supposed to declare nMapArray once but I'm not sure which one to discard. If I discard int nMapArray[ MAP_HEIGHT ][ MAP_WIDTH ]; then it will generate two errors:
LNK2019: unresolved external symbol
and
LNK1120: unresolved externals
Did a bit of googling but I still can't find the fix so help would be appreciated.
EDIT:
Ok so following the advice of many to get rid of the first inisialisation. From here I get two errors:
error LNK2019: unresolved external symbol "public: virtual class IConsole & __thiscall Win32Console::Color(unsigned short)" (?Color#Win32Console##UAEAAVIConsole##G#Z) referenced in function "void __cdecl DrawTile(int,int)" (?DrawTile##YAXHH#Z)
and
error LNK1120: 1 unresolved externals
Full code:
#include "Console.h"
#include <Windows.h>
#include <stdint.h>
// Map dimensions
#define MAP_WIDTH 20
#define MAP_HEIGHT 15
// Tile Types
#define TILE_FLOOR 0
#define TILE_WALL 1
// Map Layout
int nMapArray[ MAP_HEIGHT ][ MAP_WIDTH ]=
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
void DrawMap( void );
bool IsPassable( int x, int y );
void DrawTile( int x, int y );
int main( void )
{
console.SetTitle( "Article Two Demo" );
// Declare the player's position
int nPlayerX = 4;
int nPlayerY = 4;
// Main game loop
while( true )
{
// Draw the map
DrawMap();
// Draw the player to the screen
console.Color( RED );
console.Position( nPlayerX, nPlayerY );
console << '#';
// Input phase - Wait for the player to do something
KEYPRESS sKeyPress = console.WaitForKeypress();
// Process the input
switch( sKeyPress.eCode )
{
// Move up
case CONSOLE_KEY_UP:
// Can we move to the tile above?
if( IsPassable(nPlayerX, nPlayerY-1) )
{
// Move up
nPlayerY--;
}
break;
// Move left
case CONSOLE_KEY_LEFT:
// Can we move to the tile to the left of the player?
if( IsPassable(nPlayerX-1, nPlayerY) )
{
// Move left
nPlayerX--;
}
break;
// Move right
case CONSOLE_KEY_RIGHT:
// Can we move to the tile to the right of the player
if( IsPassable(nPlayerX+1, nPlayerY ) )
{
// Move right
nPlayerX++;
}
break;
// Move down
case CONSOLE_KEY_DOWN:
// Can we move to the tile below the player?
if( IsPassable(nPlayerX, nPlayerY+1) )
{
// Move down
nPlayerY++;
}
break;
// Escape key
case CONSOLE_KEY_ESCAPE:
// Quit the program
return 0;
// Ignore any other keys
default:
break;
}
}
// If execution gets here, the program is done
return 0;
}
// IsPassable Function ///////////////////////////////////////////////////////////////////
//
// This function analyzes the coordinates of the map array specified and returns
// true if the coordinate is passable (able for the player to occupy), false if not.
//
bool IsPassable( int x, int y )
{
// Before we do anything, make darn sure that the coordinates are valid
if( x < 0 || x >= MAP_WIDTH || y < 0 || y >= MAP_HEIGHT )
return false;
// Store the value of the tile specified
int nTileValue = nMapArray[y][x];
// Return true if it's passable
if( nTileValue == TILE_FLOOR)
return true;
return false;
}
// DrawMap Function //////////////////////////////////////////////////////////////////////
//
// This function draws the entire map to the screen.
//
void DrawMap( void )
{
for( int y = 0; y < MAP_HEIGHT; y++ )
{
for( int x = 0; x < MAP_WIDTH; x++ )
{
DrawTile(x, y);
}
}
}
// DrawTile Function /////////////////////////////////////////////////////////////////////
//
// Draws a map tile for the map coordinates specified.
//
void DrawTile( int x, int y )
{
console.Position( x, y );
switch( nMapArray[y][x] )
{
case TILE_FLOOR:
console.Color( GREY );
console << '.';
break;
case TILE_WALL:
console.Color( GREY );
console << '#';
break;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
In Console.h I haven't put the layout in (because I'm not entirely sure how to do that).
Get rid of the first one, the one without the initialisation.
That solves the compiler issue, the linker errors are another matter. The reason they appear is simply because the compilation phase is working once the double declaration is fixed.
Then I suggest you post another question with more details on the linker problems.
I use the following function to return a weight matrix of values between 0 and 1 depending on how close to the center a particular matrix position is. Also after a threshold the values are all 1 (it is like plateau with the points closer to center having value 1 and points away from center after a threshold of distance linearly fall from 1 to 0 at the edges)?
cv::Mat2f getWeightsMatrix(int N, int M, float r){
cv::Mat2f weights = cv::Mat2f(N,M);
int i,j;
for(i=0;i<N;i++){
for(j=0;j<M;j++){
if(i<=floor(N*(1-r)/2)){
if(j<=floor(M*(1-r)/2)){
weights[i][j]=((float)(i/N-j/M)/(1-r));
}
else{
weights[i][j]=(2*(float)(i/N)/(1-r));
}
}
else if (i>=floor(N*(1+r)/2)){
if(j>=floor(M*(1+r)/2)){
weights[i][j]=(((float)((N-i)/N))-((float)((M-j)/M)))/(1-r);
}
else{
weights[i][j]=(2*(float)((N-i)/N)/(1-r));
}
}
else{
if(j<=floor(M*(1-r)/2)){
weights[i][j]=(2*(float)(j/M)/(1-r));
}
else if(j>=floor(M*(1+r)/2)){
weights[i][j]=(2*(float)((M-j)/M)/(1-r));
}
else{
weights[i][j]=1;
}
}
}
}
cout << weights << endl;
return weights;
}
Now my problem is that I am having some casting issues and only values 0 and 1 are being returned (no floats). Also my matrix size displayed by the cout is 20x10 when I call the function with N=10, M=10 and r=0.5.
Please helP!
EDIT: This is the output
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Your matrix consists only if integers because when you do basic operations on integers, the results gets rounded automatically.
For example: when you write
weights[i][j]=((float)(i/N-j/M)/(1-r));
The result of i/N is rounded to a integer, j/M is also rounded to an integer, and finally, the division by (1-r) is also rounded. Your (float) cast is a good idea but it's applied too late.
You can do several things:
Cast inside elementary operations, for instance, float(i)/N instead of i/N
Use float numbers instead of integers: write 1.0 instead of 1
Use floats inside your loops and statements
For example:
for(float i = 0; i < N-0.5; i++) {
for(float j = 0; j < M-0.5; j++) {
if(i <= floor(N*(1.0-r)/2.0)) {
// ...
It's important you understand that because of floating point precision, a test such as i < N might or might not pass when float i = N. This is why I did a little trick by substracting 0.5 from your loop bounds N and M.