Superclass method with subclass data - c++

Good morning.
Im learning some concepts about inheritance and consoles manipulation.
Im pretty beginner as you could see.
So Im trying to have a single character drawn on a console and I want its position to be updated.
Now please note that I know my code is probably very bad in multiple ways and that there are probably hundreds better completely alternative ways to do this, but I want to understand some inheritance concepts first and why it doesn't work the way it is.
So, I draw my player character "X" on the console, then I update its position calling a specific member method to move it.
Now, because I made it that Player class expand DrawConsole class, I would like to call drawConsole on the Player instance.
When I do this, I have that playerA instance have its position coordinates actually updated, but the reference to the player instance have now two member called 'position', as you can see on the image.
How can I say to choice the playerA one without completely remake the code or use a completely different approach?
Or maybe simply I cant and I have actually complete change the approach?
Hope I was able to comunicate what my doubt actually is.
Here is the code
#include <ctime>
#include <cstdlib>
#include "windows.h"
#define width 100
#define height 15
class StaticBuffer
{
public:
StaticBuffer() { srand(time(0)); }
void loadBackGround(CHAR_INFO *backGround, int swidth, int sheight)
{
for (int y = 0; y < sheight; y++)
{
int rnd = rand() % 100 + 1;
for (int x = 0; x < swidth; x++)
if (y == 0 || y == sheight - 1)
{
backGround[y * swidth + x].Char.AsciiChar = (unsigned char)127;
backGround[y * swidth + x].Attributes = (unsigned char)23;
}
else if (x > 4 * rnd && x < (4 * rnd) + 5 || x > 4 * rnd / 2 && x < (4 * rnd / 2) + 5)
{
backGround[y * swidth + x].Char.AsciiChar = (unsigned char)178;
backGround[y * swidth + x].Attributes = (unsigned char)12;
}
else
{
backGround[y * swidth + x].Char.AsciiChar = 32;
backGround[y * swidth + x].Attributes = (unsigned char)3;
}
}
}
private:
};
class DrawConsole
{
public:
DrawConsole()
{
wConsole = GetStdHandle(STD_OUTPUT_HANDLE);
rConsole = GetStdHandle(STD_INPUT_HANDLE);
windowSizeInit = {0, 0, 30, 10};
windowSize = {0, 0, bufferSize.X - 1, bufferSize.Y - 1};
backGround = new CHAR_INFO[bufferSize.X * bufferSize.Y];
obstacle = new CHAR_INFO[bufferSize.X * bufferSize.Y];
inputBuffer = new INPUT_RECORD[4];
drawBackGround.loadBackGround(backGround, bufferSize.X, bufferSize.Y);
nInputWritten = 0;
nOutputWritten = 0;
playerString[0] = L'X';
charLenght = 1;
position = {10,13};
}
void drawConsole()
{
wConsole = GetStdHandle(STD_OUTPUT_HANDLE);
rConsole = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleWindowInfo(wConsole, TRUE, &windowSizeInit);
wConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleScreenBufferSize(wConsole, bufferSize);
SetConsoleWindowInfo(wConsole, TRUE, &windowSize);
WriteConsoleOutputA(wConsole, backGround, bufferSize, {0,0}, &windowSize);
WriteConsoleOutputCharacterW(wConsole, playerString, charLenght, position, &nOutputWritten);
}
void drawChar()
{
WriteConsoleOutputA(wConsole, backGround, bufferSize, {0,0}, &windowSize);
WriteConsoleOutputCharacterW(wConsole, playerString, charLenght, position, &nOutputWritten);
}
protected:
HANDLE wConsole;
HANDLE rConsole;
COORD bufferSize{width, height};
SMALL_RECT windowSizeInit;
SMALL_RECT windowSize;
CHAR_INFO *backGround;
CHAR_INFO *obstacle;
INPUT_RECORD *inputBuffer;
DWORD nInputWritten;
DWORD nOutputWritten;
DWORD charLenght;
StaticBuffer drawBackGround;
wchar_t playerString[2];
COORD position;
};
class Player :public DrawConsole
{
public:
Player()
{
position.X = 20;
position.Y = height - 2;
}
void movePlayerRight()
{
for (int i = 0; i < 3; i++)
position.X += 1;
}
COORD getPositionC() { return position; }
private:
COORD position;
};
Player *playerA = new Player;
DrawConsole *myConsole = new DrawConsole;
int main()
{
myConsole->drawConsole();
while (true)
{
//Sleep(5000);
playerA->movePlayerRight();
playerA->drawChar();
}
}

It depends on what you really want. If the idea is that both variables represent the same concept, you shouldn't have to re-define it in the derived class, because it is "protected" in the base class so the derived class is able to access it.
If the variables represent different things, but they happen to have the same name (which, by the way, would be a bad idea), you can qualify it with the class the variable has been defined in. So, for instance, you could do:
DrawConsole::position.X += 1;
To modify the position variable declared in DrawConsole and:
Player::position.X += 1;
To modify the position variable declared in Player
But, as I said before, I would try to avoid having two variables with the same name because it can easily result in errors.
UPDATE:
If you want to maintain the inheritance as is, just remove the attribute position from Player. The reason is as follows:
Currently, when you call drawChar, you are executing code that is in the DrawConsole class (Player itself does not define a drawChar method). This code cannot access Player::position because a method in a parent class cannot access an attribute in a child class (even if you are calling the method from an instance of the child class), so it only sees DrawConsole::position and that is the variable that it is using.
But when you call movePlayerRigth in an instance of Player, the code that is being executed is a method in the Player class. This method tries to access a position attribute and it finds out that there are two possibilities: DrawConsole::position and Player::position. In this case, it chooses Player::position because it is defined in the same class.
So, you have a method that draws the console based on DrawConsole::position and another method that modifies Player::position. This can't work and in fact if you run it, you will see that the X is not moving.
If you remove the position variable from Player, in movePlayerRight when you try to access the variable position, the code will see that Player does not define a position attribute, but it realizes that its parent class (DrawConsole) does indeed define a position attribute, and with protected access. Being protected means that code in child classes can access it directly, and so movePlayerRight will modify DrawConsole::position. In this case, both drawChar and movePlayerRight will access the same variable and it will work as expected.
So, if you want it this way, remove from the Player class the line:
COORD position;
And you will see that the code compiles and works as expected (the X moves right) because now the code in Player and the code in DrawConsole are accessing both the same variable (DrawConsole::position).

Related

C++ code for Microsoft Kinect - trying to dynamically allocate array of target positions

So I'm trying to modify the Kinect BodyBasicsD2D code so that a fixed number of "target positions" appear on the screen (as ellipses) for the user to move his hand toward. I'm having trouble creating the initial target positions.
This is my code in the header file for the allocation of the array of target positions (these are a public field of the CBodyBasics class, already built into the original BodyToBasics program):
D2D1_POINT_2F* targetPositions = NULL;
int numTargets = 3;
Then I have a function "GenerateTargetPositions" which is supposed to generate 3, in this case, target positions to be passed into the "DrawTargetPositions" function.
void CBodyBasics::GenerateTargetPositions(D2D1_POINT_2F * targetPositions, int numTargets)
{
targetPositions = new D2D1_POINT_2F[numTargets];
RECT rct;
GetClientRect(GetDlgItem(m_hWnd, IDC_VIDEOVIEW), &rct);
int width = rct.right;
int height = rct.bottom;
FLOAT x;
FLOAT y;
D2D1_POINT_2F tempPoint;
for (int i = 0; i < numTargets; i++) {
x = 1.0f*i*width / numTargets;
y = 1.0f*i*height / numTargets;
tempPoint = D2D1::Point2F(x, y);
targetPositions[i] = tempPoint;
}
}
My DrawTargetPositions function is:
void CBodyBasics::DrawTargetPositions(D2D1_POINT_2F * targetPositions, int numTargets)
{
D2D1_ELLIPSE ellipse;
for (int i = 0; i < numTargets; i++)
{
ellipse = D2D1::Ellipse(targetPositions[i], 50.f, 50.f);
m_pRenderTarget->FillEllipse(ellipse, m_pSilverBrush);
}
}
When I try to run my code, I get the error that both "targetPositions" and "targetPositions[i]" is NULL (and thus my GenerateTargetPositions function must not be working properly). I believe that targetPositions[i] is a struct (a point with x and y values) so I am wondering if this may be the reason for my errors.
I call GenerateTargetPositions and DrawTargetPositions before the main "while" loop in my code so that each function is not being called on each iteration (there are many iterations of through the while loop because this is an interactive Microsoft Kinect, recording one's movements).
Any suggestions and advice would be greatly appreciated. Thanks so much!

Is it possible to declare a 2d array class member inside the constructor with a for loop?

Currently I have this
//gameboard.h
class GameBoard
{
public:
GameBoard(bool showShips);
~GameBoard();
void draw();
void placeShipStart(int x, int y);
void placeShipEnd(int ship, int x, int y);
private:
bool defaultShowShips;
Field playerBoard[10][10];
vector<Ship*> ships[5];
};
//gameboard.cpp
GameBoard::GameBoard(bool showShips)
{
defaultShowShips = showShips;
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
{
xyzCoord ul, lr;
ul.x = j * 5.0f;
ul.y = i * 5.0f;
ul.z = 2.0f;
lr.x = j * 5.0f + 5.0f;
lr.y = i * 5.0f + 5.0f;
lr.z = 0.0f;
playerBoard[i][j] = Field(ul, lr);
}
};
The way it is right now it's telling me that I need to have a default constructor for field. I'm trying to accomplish initializing each position in a different position. Am I doing this completely wrong? I've seen the vector of vectors approach. If possible I would like to avoid that because it wasn't working for me earlier.
I am guessing here to a certain degree, but try this:
Field::Field()
{
// Provided default values to your two member variables
}
Field::Field(xyzCoord ul, xyzCoord lr)
{
// Populate your two member variables with the passed in values
}
The first constructor will be your default as it has no parameters.
I hope this helps. Apologies if I miss-understood your question.
Update
The alternative is:
This in the header:
Field::Field(xyzCoord ul = xyzCoord(), xyzCoord lr = xyzCoord())
This in the source:
Field::Field(xyzCoord ul /*xyzCoord()*/, xyzCoord lr /*xyzCoord()*/)
{
// Populate your two member variables with the passed in values
}
I am conveying the principles. Without seeing the Field and xyzCoord class I can't see what the suitable declarations would be. With this last approach the constructor how provides default values for each parameter.
See this default constructor topic for more information. In part it mentions:

passing values to a boolean array

I'm working on a simple 2d game engine, and am trying to set up a system where the player model can move behind certain objects. Every time an non-player object is blitted to the screen, its X and Y are recorded in an array so they can be used later. As such, I have set up a system where if the player X and player Y are relative to an environmental object's X and Y in a certain way, the environmental object is not immediately blitted (Normally, it would be immediately blitted before the player character so that the player character is above the object). Instead of being blitted, I have a true value be handed to a boolean array. I have an int variable that gets 1 larger every time an object is blitted so that the different X, Y and boolean values are associated with a certain position in the array. Essentially, the system looks like this:
HDcounter += 1;
forbiddenX[HDcounter] = modelX[modelNumber] + modelXChange;
forbiddenY[HDcounter] = modelY[modelNumber] + modelYChange;
forbiddenSpriteWidth[HDcounter] = 100;
forbiddenSpriteHeight[HDcounter] = 200;
forbiddenSpriteDepth[HDcounter] = 25;
if((forbiddenX[HDcounter] <= playerXE + forbiddenSpriteWidth[HDcounter]) && (forbiddenX[HDcounter] + forbiddenSpriteWidth[HDcounter] >= playerXE) && (forbiddenY[HDcounter] <= playerYE + forbiddenSpriteWidth[HDcounter]) && (forbiddenY[HDcounter] + forbiddenSpriteHeight[HDcounter] >= playerYE + 77))
{
pineTreeBlitAP = true;
blitModelAP[HDcounter] = true;
}
else
{
modelIMAGE = IBFobjectENVIRO.loadIMG("pineTree.png");
IBFobjectENVIRO.blitIMG(modelX[modelNumber] + modelXChange, modelY[modelNumber] + modelYChange, windowMODELS, modelIMAGE, 0, 0, 200, 200);
}
The problem is that when I try to use the boolean array to blit the model after the player, it does not seem to work. I can get something to happen when the player X and Y hits the threshold, but I cannot seem to get the true value recorded inside the boolean array and then used by my function.
This is the function where it is used:
void enviroment::blitEnviroModelsAP(SDL_Surface* BAPwindow, int modelAmount)
{
SDL_Surface* modelAPimage;
for(int model = 0; model < modelAmount; model++)
{
if((pineTreeBlitAP == true) && (blitModelAP[model] == true))
{
modelAPimage = IBFobjectENVIRO.loadIMG("pineTree.png");
IBFobjectENVIRO.blitIMG(forbiddenX[model], forbiddenY[model], BAPwindow, modelAPimage, 0, 0, 200, 200);
}
}
}
I get that this is probably a totally noob question, I just want some kind of help with this as I have been stuck for nearly a week.
Edit: Here are how my arrays are declared.
int forbiddenX[2000] = {0};
int forbiddenY[2000] = {0};
int forbiddenSpriteHeight[2000] = {0};
int forbiddenSpriteWidth[2000] = {0};
int forbiddenSpriteDepth[2000] = {0};
int blitModelAP[2000] = {false};

Giant Char or multiple Chars for console game map?

I'm a pretty novice c++ coder and I am starting to make a console adventure game.
My adventure game currently consists of a player character that walks around inside a console application window with an 80 character width x 40 lines.
I am not sure how to approach storing the maps for my game. Each map will consist of 80 x 40 ASCII characters with colour attributes.
Should I store each 80 x 40 map in its own char? so a single map would look something like...
int cHeight = 5; // Reduced size for this example
int cHeight = 10; // Reduced size for this example
// Set up the characters:
char map[cHeight][cWidth+1] = {
"1234567890",
"1234567890",
"1234567890",
"1234567890",
"1234567890",
};
CHAR_INFO mapA[cWidth * cHeight];
for (int y = 0; y < cHeight; ++y) {
for (int x = 0; x < cWidth; ++x) {
mapA[x + cWidth * y].Char.AsciiChar = map[y][x];
mapA[x + cWidth * y].Attributes = FOREGROUND_BLUE | Black; //I have an enum setup with background colours.
}
}
// Set up the positions:
COORD charBufSize = {cWidth,cHeight};
COORD characterPos = {0,0};
SMALL_RECT writeArea = {0,0,cWidth-1,cHeight-1};
// Write the characters:
WriteConsoleOutputA(wHnd, mapA, charBufSize, characterPos, &writeArea);
Im not sure if this is entirely the correct way to display the characters but I didn't think it was a good idea to just cout every character in the for loop.
So.. lets say my console window (in the above code) is 10 characters wide and 5 lines high.
In the above code I have a single map in the Char, so when loading each map I would put each one in their own array.
I was thinking of putting the entire map into a single Char, but then only displaying what I needed by offsetting the x and y in the for loop.
mapA[x + cWidth * y].Char.AsciiChar = map[y+offset][x+offset];
So the map would look more like this;
char map[cHeight][cWidth+1] = {
"1234567890ABCDEFGHIJ",
"1234567890ABCDEFGHIJ",
"1234567890ABCDEFGHIJ",
"1234567890ABCDEFGHIJ",
"1234567890ABCDEFGHIJ",
};
with the offset I could display '1234567890' on 5 rows separately from 'ABCDEFGHIJ' on 5 rows.
So in short I would like to know the most effective way to do this, should I have multiple Chars? Should I create a class? then I could store the characters an colours? (class' are still new to me in c++).
Should I draw the terrain only in the map and then add objects (houses, trees)?
Or just draw it all in the map manually?
I think I've just thought about this too long and need a bit of direction
Thanks!
The way I would do it would be to create a map of
Node* map[height][width]
This means you would create the map which are pointers to Node* elements and you could define the Node* element to be...
class Node{
char displayCharacter;
int posx,poxy
unsigned int r; //red
unsigned int g; //green
unsigned int b; //blue
unsigned int a; //alpha
display(); // This function will know how to display a node using the colour etc
};
Then you could for example if you wanted to create a house you would give it the center point of the model etc... to draw to a function
void createHouse(Node* center)
{
if((center->posh > 0)&&(center->posh< maxheight))
{
if(map[center->posy-1][center->posx]!=NULL)
{
map[center->posy-1][center->posx]->displayCharacter = '_';
map[center->posy-1][center->posx]->r = 255;
}
}
}
Then in main you would have something like...
while(true)
{
for(int i=0; i<maxheight; i++)
{
for(int j=0; j< maxwidth; j++)
{
map[i][j]->Display();
}
}
}
I hope all this sample code is of help to you and answered your question. I have not debugged or looked for any syntax errors. If there any errors in the code, you will have to fix them!
Good luck to you!

Crash, on Console Application, trying to draw enemies, out of bounds (following vid tutorial)

{Hopefully improved my post, please still suggest any other code you need, and once again im sorry for being so clueless, im determined to get past this problem though so i truly appreciate your time!!!}
**EDIT: thanks to Frank with his reply below, the program now starts and draws the three enemies, but just a few second later crashes, the program code below therefore is still applicable as its basically the move loop and somewhere in there something is still going wrong.
I realise this is extremely obscure and i have tried my best to explain it, but if noone can advise then the few second its up should be enough to complete the tutorial anyway and ill dissect the whole project after its finished and really try and break it down and learn as much as possible.**
Okay, so I run this loop designed to create new enemies, and then draw them onto the screen, it now works, but after a few second crashes. below is the steps the debugging goes through and the call stack at the end if what it displayed after the crash. hope you can help!
this is a video tutorial im following and im stuck, cant find the answer. checked the code over and over again. (the full code is at the bottom of the post (codeblocks,) but i have tried to include as much info as possible in this post)
the function is:
level->addEnemies(3);
which looks like in the main game.cpp:
bool Game::run(void)
{
level = new Level(&drawArea, 30, 20);
drawArea.createBackgroundTile(TILE_EMPTY, ' ');
drawArea.createBackgroundTile(TILE_WALL, 219);
drawArea.createSprite(SPRITE_PLAYER, 1);
drawArea.createSprite(SPRITE_ENEMY, '$');
player = new Character(level, &drawArea, 0);
level->draw();
level->addPlayer(player);
level->addEnemies(3); <-------- SKIPS TO THIS FUNC
char key = ' ';
startTime = timeGetTime();
frameCount = 0;
lastTime = 0;
posx = 0;
player->move(0,0);
while (key != 'q')
{
while (!getInput(&key))
{
timerUpdate();
}
level->keyPress(key);
}
delete player;
return true;
}
the function in full is below, note that when i remove this addEnemies function from the main game loop everything runs perfectly fine with no crash, so it has something to do with the upcoming functions.
void Level::addEnemies(int num)
{
int i = num;
while (i > 0)
{
int xpos = int(float(rand() % 100) / 100) * (width - 2) + 1;
int ypos = int(float(rand() % 100) / 100) * (height - 2) + 1;
if (level[xpos][ypos] != TILE_WALL)
{
Enemy *temp = new Enemy(this, drawArea, SPRITE_ENEMY,
(float)xpos, float(ypos));
temp->addGoal(player);
addNPC((Sprite *)temp);
i--;
}
}
}
It gets through this function without any problems it seems.
After this function is goes back to the game loops and executes through fine, goes into timer update without any problems. Here is the timerUpdate function:
void Game::timerUpdate(void)
{
double currentTime = timeGetTime() - lastTime;
if (currentTime < GAME_SPEED)
return;
level->update(); <--------SKIPS TO THIS FUNC
frameCount++;
lastTime = timeGetTime();
}
This is the Level->Update() Func:
void Level::update(void)
{
for (Iter = npc.begin(); Iter != npc.end(); Iter++)
{
(*Iter)->idleUpdate(); <-------------SKIPS TO THIS FUNC
if ((*Iter)->isAlive() == false)
{
Sprite *temp = *Iter;
//kill the enemy
Iter--;
delete temp;
npc.remove(temp);
}
}
}
idleUpdate():
void Enemy::idleUpdate(void)
{
if (goal)
simulateAI(); <------ Goes to this func
}
simulateAI():
void Enemy::simulateAI(void)
{
vector goal_pos = goal->getPosition();
vector direction;
direction.x = goal_pos.x - pos.x;
direction.y = goal_pos.y - pos.y;
float mag = sqrt(direction.x * direction.x + direction.y * direction.y);
direction.x = direction.x / (mag);
direction.y = direction.y / (mag);
if (!move(direction.x, direction.y)) <------ SKIPS TO THIS FUNC
{
while (!move(rand() % 3 - 1, rand() % 3 - 1))
{
}
}
move function:
bool Sprite::move(float x, float y)
{
int xpos = (int)(pos.x +x);
int ypos = (int)(pos.y +y);
if (isValidLevelMove(xpos,ypos)) SKIPS TO THIS FUNC
{
//.....rest not needed
isValidMove func:
bool Sprite::isValidLevelMove(int xpos, int ypos)
{
if (level->level[xpos][ypos] != TILE_WALL) <-------------THIS LINE CRASHES!!
return true;
return false;
}
I really cant figure out where this goes wrong, and why at the end the call stakc shows such high out of bounds numbers for xpos adn ypos.
Here is the full call stack:
#0 00402920 Sprite::isValidLevelMove (this=0x791498, xpos=-2147483648, ypos=-2147483648) (sprite.cpp:95)
#1 00000000 0x00401750 in Enemy::move (this=0x791498, x=-nan(0x400000) (enemy.cpp:21)
#2 00401892 Enemy::simulateAI (this=0x791498) (enemy.cpp:67)
#3 004017E5 Enemy::idleUpdate (this=0x791498) (enemy.cpp:46)
#4 0040226E Level::update (this=0x792e90) (level.cpp:86)
#5 00401CB8 Game::timerUpdate (this=0x28fec0) (game.cpp:93)
#6 00401BB5 Game::run (this=0x28fec0) (game.cpp:54)
#7 0040258D main() (main.cpp:11)
which basically tells me xpos and ypos have been mutilated from somehere in thsi proccess and thats causeing the crash im sure because its way out of bounds from the [30][20] int array of the width and height of the drawengine.
ANOTHER EDIT:
Here is the Sprite class, if it helps, will edit in more if needed.
enum
{
SPRITE_CLASSID,
CHARACTER_CLASSID,
ENEMY_CLASSID
};
struct vector
{
float x;
float y;
};
class Sprite
{
public:
Sprite(Level *l, DrawEngine *de, int s_index, float x = 1, float y = 1, int i_lives = 1);
~Sprite();
vector getPosition(void);
float getX(void);
float getY(void);
virtual void addLives(int num = 1);
int getLives(void);
bool isAlive(void);
virtual void idleUpdate(void);
virtual bool move(float x, float y);
protected:
Level *level;
DrawEngine *drawArea;
vector pos;
int spriteIndex;
int numLives;
int classID;
vector facingDirection;
void draw(float x, float y);
void erase(float x, float y);
bool isValidLevelMove(int xpos, int ypos);
};
anyway any help and i would be sooooo grateful, i know i must seem totally useless, but i rteally am determined to learn, and any help you guys can provide would be priceless!!!!
full code file (codeblocks) : http://www.mediafire.com/?5xz2seadmagbetb
This might not be the actual problem, but could be related. Your code to create a random position within your Level::addEnemies(int num) function will always return 1 for xpos and ypos.
This is because of the way you apply the casts. You seem to miss parenthesis for your final cast to int. I think you want something like this:
int xpos = int((float(rand() % 100) / 100) * (width - 2)) + 1;
Update:
The code causing the crash is located in your simulateAI() function. With:
float mag = sqrt(direction.x * direction.x + direction.y * direction.y);
You calculate the distance between two points, but if the points have the same coordinates, the distance is 0.
Later with: direction.x = direction.x / (mag); you devide by this potential 0 and as a result your coordinates will contain NaN. Within your bool Sprite::move(float x, float y) function you cast these NaNs into an int which will give you some undefined number. With this number you are trying to access your array which will lead to the access violation that crashes your program.
So first thing to do is to check for a zero distance and handle that differently.