I'm writing a console game in C++ and I'd like to be able to do menus easily. The screen state is stored in a wchar_t* screen[screenWidth*screenHeight]. I wrote a class Menu that should write to my screenbuffer to display a scoreboard. The class has a draw function that takes a pointer to the screenbuffer and some coordinate parameters. The draw function uses swprintf_s to change the state of the screenbuffer, however when I run the code it doesn't output anything. I tried changing the swprintf_s call by passing in a literal but it still doesn't work. However when I just use raw swprintf_s from main() it works.
void Menu::draw(wchar_t* screen, int xScreen, int yScreen, int xField, int yField,
int xMenu, int yMenu) {
for (int i = 0; i < buttons.size(); ++i) {
int currentY = yMenu / (buttons.size() + 1) * (i + 1);
swprintf_s(&screen[xScreen * currentY + xField + xMenu / 2 - 7], 16, buttons[i].str);
}
}
buttons is a vector of menus, str is a wchar_t* to the menu's text.
When I just use the function in main:swprintf_s(&screen[15 * nScreenWidth + nFieldWidth + 6], 16, L"SCORE: %8d", nScore);
outputs as it should. Any suggestions?
Related
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).
I'm working on a console game. It uses a screen buffer to refresh the console window after updating the map.
Here's the main while loop.
while (true) {
//player.doStuff(_kbhit());
//map.update();
WriteConsoleOutputCharacter(
console.getScreenBuffer(),
(LPWSTR)map.getScreen(),
map.getWidth() * map.getHeight(),
{ 0, 0 }, console.getBytesWritten()
);
Sleep(1000 / 30);
}
Before this loop, I'm getting the layout of the map from a .txt file:
class Map {
int width, height;
wchar_t* screen;
public:
wchar_t* getScreen() {
return screen;
}
void setScreen(std::string layoutFile, std::string levelDataFile) {
std::ifstream levelData(levelDataFile);
levelData >> width >> height;
screen = new wchar_t[(width + 1) * height];
levelData.close();
std::wifstream layout(layoutFile);
std::wstring line;
for (int j = 0; j < height; j++) {
std::getline<wchar_t>(layout, line);
for(int i = 0; i < width; i++) {
screen[j * width + i] = line.at(i);
}
screen[width * (j + 1)] = L'\n';
}
layout.close();
}
};
map.setScreen("demo.txt", "demo_data.txt");
The problem is that the printed map displays as one string without any line breaks, like this:
00000__00000
When I expected it to look like this instead:
0000
0__0
0000
I tried adding L'\n', L'\r\n' after every line written, but it doesn't work.
In short
There are two independent problems here:
The first one is that your newline characters get overwritten.
The second, once you've corrected the first, is that the windows console API does not handle newlines
More details
The problem with the overwriting
I assume that the width does not include the trailing newline at the end of each line, since your allocation for the screen is:
new wchar_t[(width + 1) * height]; // real width is width + 1 for '\n'
Now looking at your logic, the last '\n' that you add to the line, is set at:
screen[ width * (j + 1) ] // same as screen[ j * width + width ]
This seems fine according to your indexing scheme, since you copy the layout characters to:
screen[ j * width + i ]` // where `i` is between `0` and `width-1`
so the newline would be at screen[ j * width + width ].
Unfortunately, with your indexing formula, the first character of the next line overwrites the same place: replacing j with j+1 and i with 0 gives:
screen[ (j + 1) * width + 0 ]
which is
screen[ (j + 1) * width ] // same location as screen [ width * (j+1)]
The solution for having trailing newlines on very line
Correct your indexing scheme, taking into account that the real width of the line is width+1.
So the indexing formula becomes:
for(int i = 0; i < width; i++) {
screen[j * (width+1) + i] = line.at(i);
}
and of course the trailing newline:
screen[j * (width+1) + width] = L'\n'; // self-explaining
screen[(j+1) * (width+1) -1] = L'\n'; // or alternative
The problem with the console API
The WriteConsoleOutputCharacter() provides no real support for newlines and control characters. These are diplayed as a question mark.
The documentation refers to a possibility to get those control characters handled depending on the console mode, but I've tried with Windows 10, and even with the variant WriteConsoleOutputCharacterA() (to be sure to exclude issues with wide characters), it simply does not work.
You have two solutions to make this work, but the two require some rework:
display the output line by line and control the cursor position accordingly
use the WriteConsoleOutput() which allows you to specify the target rectangle (heigth and width) and write the characters in a rectangle without need for a newline. Unfortunately, the array shall then be of CHAR_INFO instead of simple characters.
Example for the second way:
std::string w = "SATORAREPOTENETOPERAROTAS";
SMALL_RECT sr{ 2, 2, 6, 6 };
CHAR_INFO t[25];
for (int i = 0; i < 25; i++) { t[i].Char.AsciiChar = w[i]; t[i].Attributes = BACKGROUND_GREEN; }
WriteConsoleOutputA(
hOut,
t,
{ 5,5 },
{ 0,0 },
&sr
);
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!
I am working on a MFC project and for 3d graphic I am using opengl;
in OnDraw() function I write this code :
int idx1 = MarkerCoordinates[SourceMarkerIndex];
int idx2 = MarkerCoordinates[SourceMarkerIndex + 1];
int idx3 = MarkerCoordinates[SourceMarkerIndex + 2];
int idx4 = MarkerCoordinates[DestMarkerIndex];
int idx5 = MarkerCoordinates[DestMarkerIndex+1];
int idx6 = MarkerCoordinates[DestMarkerIndex+2];
glBegin(GL_LINES);
glVertex3f(idx1,idx2,idx3);
glVertex3f(idx4,idx5,idx6);
glEnd();
because the user at runtime detemine the parameters to define a bone I must pass the parameters to the glVertex3f()(idxi , i = 1,2,...);however in this way, there is no line in output; if I explicitly pass integers to the glVertex3f it draw lines;
can you tell me where is my wrong?
Call Invalidate() function to trigger WM_PAINT message, which in turn call OnDraw()
I'm working my way through some tutorials I found on creating an ASCII game engine in C and writing my program in C++ to practice. I'm currently working on some stuff with allocating image data on the heap in the form of an Image struct (containing an int width, int height, and two char pointers to locations on the heap holding arrays of chars [width * height] in size)... however, I'm having some problems calling the new operator. The function where I'm allocating the memory for the struct itself, as well as its character and colour data, looks like this:
Image *allocateImage(int width, int height) {
Image *image;
image = new Image;
if (image == NULL)
return NULL;
image->width = width;
image->height = height;
image->chars = new CHAR[width * height];
image->colours = new COL[width * height];
//image->colours = (CHAR*) PtrAdd(image->chars, sizeof(CHAR) + width * height);
for (int i = 0; i < width * height; ++i) { //initializes transparent image
*(&image->chars + i) = 0;
*(&image->colours + i) = 0;
}
return image;
}
The main function itself (where this function is called twice) looks like this:
int main() {
int x, y, offsetx, offsety;
DWORD i;
srand(time(0));
bool write = FALSE;
INPUT_RECORD *eventBuffer;
COLORREF palette[16] =
{
0x00000000, 0x00800000, 0x00008000, 0x00808000,
0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
};
COORD bufferSize = {WIDTH, HEIGHT};
DWORD num_events_read = 0;
SMALL_RECT windowSize = {0, 0, WIDTH - 1, HEIGHT - 1};
COORD characterBufferSize = {WIDTH, HEIGHT};
COORD characterPosition = {0, 0};
SMALL_RECT consoleWriteArea = {0, 0, WIDTH - 1, HEIGHT - 1};
wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
rHnd = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleTitle("Title!");
SetConsolePalette(palette, 8, 8, L"Sunkure Font");
SetConsoleScreenBufferSize(wHnd, bufferSize);
SetConsoleWindowInfo(wHnd, TRUE, &windowSize);
for (y = 0; y < HEIGHT; ++y) {
for (x = 0; x < WIDTH; ++x) {
consoleBuffer[x + WIDTH * y].Char.AsciiChar = (unsigned char)219;
consoleBuffer[x + WIDTH * y].Attributes = FOREGROUND_BLUE;
}
}
write = TRUE;
Image *sun_image = allocateImage(SUNW, SUNH);
Image *cloud_image = allocateImage(CLOUDW, CLOUDH);
setImage(sun_image, SUN.chars, SUN.colors);
setImage(cloud_image, Cloud.chars, Cloud.colours);
I can post more code if anyone feels it's necessary, but the program only reaches this point - in fact, a little before, as it crashes on the second call to allocateImage, at the point in the function where the new operator is called. The program has been working just fine until this point - the only recent additions have been the functions for allocation of image data on the heap (for creation of images with variable sizes) as well as deallocation (which isn't reached by this program). Since the program I'm learning from is written in C this is one place where looking at the source code won't help me, and Google's been not much help either. Can anyone point me to what's going wrong?
These lines
*(&image->chars + i) = 0;
*(&image->colours + i) = 0;
are dubious because image is already a pointer. A pointer to a pointer doesn't make sense here. Simply remove the &.
Since your actual code writes to Joe Random Address anything can happen. So it is not unusual that you thwart the memory subsystem and hence the next new call.