Device: Macbook, OS X, multitouch, SDL2.
float posX = event.tfinger.x;
float posY = event.tfinger.y;
if ( event.type == SDL_FINGERDOWN ) std::cout << "posX = " << posX << ", posY = " << posY << "\n";
It returns me coordinates of my multitouch device. If I tap my multitouch at the left-top corner it returns me coordinates something like 0.1x0.1. Ok, right. But how to get coordinates of the cursor position in OS X?
I can get only coordinates of multitouch device but it doesn't mean that it's the coordinates of the cursor on the screen. I mean... I can tap my multitouch at the left-top corner but my cursor at this time will be at the right-bottom corner of the screen.
If I understand you correctly, you want to get both the point where you touch the device, and where the cursor on the screen is?
I'd recommend using the SDL_MOUSEMOTION event:
while (SDL_PollEvent(&e))
{
switch(e->type) {
case SDL_MOUSEMOTION:
mouseX = e.button.x;
mouseY = e.button.y;
break;
}
}
where the "mouseX" and "mouseY" variables will be the coordinates of the cursor on the screen within the SDL_Window.
If you want the global mouse coordinates, you can use SDL_GetGlobalMouseState:
int mouseX;
int mouseY;
SDL_GetGlobalMouseState(&mouseX, &mouseY);
which will get you the global (relative to the desktop) coordinates.
Currently there is a bug with SDL_GetMouseState where if you use SDL_SetWindowFullscreen and set it to borderless fullscreen (SDL_WINDOW_FULLSCREEN_DESKTOP) it gets the wrong coordinates, which is why I recommed use of the SDL_MOUSEMOTION event instead.
It's fine to use in any other instance (as far as I can tell).
I'm attempting to make a console side scrolling shooter, I know this isn't the ideal medium for it but I set myself a bit of a challenge.
The problem is that whenever it updates the frame, the entire console is flickering. Is there any way to get around this?
I have used an array to hold all of the necessary characters to be output, here is my updateFrame function. Yes, I know system("cls") is lazy, but unless that's the cause of problem I'm not fussed for this purpose.
void updateFrame()
{
system("cls");
updateBattleField();
std::this_thread::sleep_for(std::chrono::milliseconds(33));
for (int y = 0; y < MAX_Y; y++)
{
for (int x = 0; x < MAX_X; x++)
{
std::cout << battleField[x][y];
}
std::cout << std::endl;
}
}
Ah, this brings back the good old days. I did similar things in high school :-)
You're going to run into performance problems. Console I/O, especially on Windows, is slow. Very, very slow (sometimes slower than writing to disk, even). In fact, you'll quickly become amazed how much other work you can do without it affecting the latency of your game loop, since the I/O will tend to dominate everything else. So the golden rule is simply to minimize the amount of I/O you do, above all else.
First, I suggest getting rid of the system("cls") and replace it with calls to the actual Win32 console subsystem functions that cls wraps (docs):
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
void cls()
{
// Get the Win32 handle representing standard output.
// This generally only has to be done once, so we make it static.
static const HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
COORD topLeft = { 0, 0 };
// std::cout uses a buffer to batch writes to the underlying console.
// We need to flush that to the console because we're circumventing
// std::cout entirely; after we clear the console, we don't want
// stale buffered text to randomly be written out.
std::cout.flush();
// Figure out the current width and height of the console window
if (!GetConsoleScreenBufferInfo(hOut, &csbi)) {
// TODO: Handle failure!
abort();
}
DWORD length = csbi.dwSize.X * csbi.dwSize.Y;
DWORD written;
// Flood-fill the console with spaces to clear it
FillConsoleOutputCharacter(hOut, TEXT(' '), length, topLeft, &written);
// Reset the attributes of every character to the default.
// This clears all background colour formatting, if any.
FillConsoleOutputAttribute(hOut, csbi.wAttributes, length, topLeft, &written);
// Move the cursor back to the top left for the next sequence of writes
SetConsoleCursorPosition(hOut, topLeft);
}
Indeed, instead of redrawing the entire "frame" every time, you're much better off drawing (or erasing, by overwriting them with a space) individual characters at a time:
// x is the column, y is the row. The origin (0,0) is top-left.
void setCursorPosition(int x, int y)
{
static const HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
std::cout.flush();
COORD coord = { (SHORT)x, (SHORT)y };
SetConsoleCursorPosition(hOut, coord);
}
// Step through with a debugger, or insert sleeps, to see the effect.
setCursorPosition(10, 5);
std::cout << "CHEESE";
setCursorPosition(10, 5);
std::cout 'W';
setCursorPosition(10, 9);
std::cout << 'Z';
setCursorPosition(10, 5);
std::cout << " "; // Overwrite characters with spaces to "erase" them
std::cout.flush();
// VoilĂ , 'CHEESE' converted to 'WHEEZE', then all but the last 'E' erased
Note that this eliminates the flicker, too, since there's no longer any need to clear the screen completely before redrawing -- you can simply change what needs changing without doing an intermediate clear, so the previous frame is incrementally updated, persisting until it's completely up to date.
I suggest using a double-buffering technique: Have one buffer in memory that represents the "current" state of the console screen, initially populated with spaces. Then have another buffer that represents the "next" state of the screen. Your game update logic will modify the "next" state (exactly like it does with your battleField array right now). When it comes time to draw the frame, don't erase everything first. Instead, go through both buffers in parallel, and write out only the changes from the previous state (the "current" buffer at that point contains the previous state). Then, copy the "next" buffer into the "current" buffer to set up for your next frame.
char prevBattleField[MAX_X][MAX_Y];
std::memset((char*)prevBattleField, 0, MAX_X * MAX_Y);
// ...
for (int y = 0; y != MAX_Y; ++y)
{
for (int x = 0; x != MAX_X; ++x)
{
if (battleField[x][y] == prevBattleField[x][y]) {
continue;
}
setCursorPosition(x, y);
std::cout << battleField[x][y];
}
}
std::cout.flush();
std::memcpy((char*)prevBattleField, (char const*)battleField, MAX_X * MAX_Y);
You can even go one step further and batch runs of changes together into a single I/O call (which is significantly cheaper than many calls for individual character writes, but still proportionally more expensive the more characters are written).
// Note: This requires you to invert the dimensions of `battleField` (and
// `prevBattleField`) in order for rows of characters to be contiguous in memory.
for (int y = 0; y != MAX_Y; ++y)
{
int runStart = -1;
for (int x = 0; x != MAX_X; ++x)
{
if (battleField[y][x] == prevBattleField[y][x]) {
if (runStart != -1) {
setCursorPosition(runStart, y);
std::cout.write(&battleField[y][runStart], x - runStart);
runStart = -1;
}
}
else if (runStart == -1) {
runStart = x;
}
}
if (runStart != -1) {
setCursorPosition(runStart, y);
std::cout.write(&battleField[y][runStart], MAX_X - runStart);
}
}
std::cout.flush();
std::memcpy((char*)prevBattleField, (char const*)battleField, MAX_X * MAX_Y);
In theory, that will run a lot faster than the first loop; however in practice it probably won't make a difference since std::cout is already buffering writes anyway. But it's a good example (and a common pattern that shows up a lot when there is no buffer in the underlying system), so I included it anyway.
Finally, note that you can reduce your sleep to 1 millisecond. Windows will actually often sleep longer, typically up 15ms, but it will prevent your CPU core from reaching 100% usage with a minimum of additional latency.
Note that this not at all the way "real" games do things; they almost always clear the buffer and redraw everything every frame. They don't get flickering because they use the equivalent of a double-buffer on the GPU, where the previous frame stays visible until the new frame is completely finished being drawn.
Bonus: You can change the colour to any of 8 different system colours, and the background too:
void setConsoleColour(unsigned short colour)
{
static const HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
std::cout.flush();
SetConsoleTextAttribute(hOut, colour);
}
// Example:
const unsigned short DARK_BLUE = FOREGROUND_BLUE;
const unsigned short BRIGHT_BLUE = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
std::cout << "Hello ";
setConsoleColour(BRIGHT_BLUE);
std::cout << "world";
setConsoleColour(DARK_BLUE);
std::cout << "!" << std::endl;
system("cls") is the cause of your problem. For updating frame your program has to spawn another process and then load and execute another program. This is quite expensive.
cls clears your screen, which means for a small amount of the time (until control returns to your main process) it displays completely nothing. That's where flickering comes from.
You should use some library like ncurses which allows you to display the "scene", then move your cursor position to <0,0> without modifying anything on the screen and redisplay your scene "over" the old one. This way you'll avoid flickering, because your scene will always display something, without 'completely blank screen' step.
One method is to write the formatted data to a string (or buffer) then block write the buffer to the console.
Every call to a function has an overhead. Try go get more done in a function. In your Output, this could mean a lot of text per output request.
For example:
static char buffer[2048];
char * p_next_write = &buffer[0];
for (int y = 0; y < MAX_Y; y++)
{
for (int x = 0; x < MAX_X; x++)
{
*p_next_write++ = battleField[x][y];
}
*p_next_write++ = '\n';
}
*p_next_write = '\0'; // "Insurance" for C-Style strings.
cout.write(&buffer[0], std::distance(p_buffer - &buffer[0]));
I/O operations are expensive (execution-wise), so the best use is to maximize the data per output request.
With the accepted answer the rendering would still be flickering if your updated area is big enough. Even if you animate a single horizontal line to move from top to bottom you'll most of the time see it like this:
###########################
#####################
This happens because you see the previous frame in the process of being overwritten by a newer one. For complex scenes like video or 3D rendering, this is barely acceptable. The proper way to do it is by using the double buffering technique. The idea is to draw all the "pixels" into an off-screen buffer and when done display it all at once. Gladly Windows console supports this approach pretty well. Please see the full example on how to do the double buffering below:
#include <chrono>
#include <thread>
#include <Windows.h>
#include <vector>
const unsigned FPS = 25;
std::vector<char> frameData;
short cursor = 0;
// Get the intial console buffer.
auto firstBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
// Create an additional buffer for switching.
auto secondBuffer = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
nullptr,
CONSOLE_TEXTMODE_BUFFER,
nullptr);
// Assign switchable back buffer.
HANDLE backBuffer = secondBuffer;
bool bufferSwitch = true;
// Returns current window size in rows and columns.
COORD getScreenSize()
{
CONSOLE_SCREEN_BUFFER_INFO bufferInfo;
GetConsoleScreenBufferInfo(firstBuffer, &bufferInfo);
const auto newScreenWidth = bufferInfo.srWindow.Right - bufferInfo.srWindow.Left + 1;
const auto newscreenHeight = bufferInfo.srWindow.Bottom - bufferInfo.srWindow.Top + 1;
return COORD{ static_cast<short>(newScreenWidth), static_cast<short>(newscreenHeight) };
}
// Switches back buffer as active.
void swapBuffers()
{
WriteConsole(backBuffer, &frameData.front(), static_cast<short>(frameData.size()), nullptr, nullptr);
SetConsoleActiveScreenBuffer(backBuffer);
backBuffer = bufferSwitch ? firstBuffer : secondBuffer;
bufferSwitch = !bufferSwitch;
std::this_thread::sleep_for(std::chrono::milliseconds(1000 / FPS));
}
// Draw horizontal line moving from top to bottom.
void drawFrame(COORD screenSize)
{
for (auto i = 0; i < screenSize.Y; i++)
{
for (auto j = 0; j < screenSize.X; j++)
if (cursor == i)
frameData[i * screenSize.X + j] = '#';
else
frameData[i * screenSize.X + j] = ' ';
}
cursor++;
if (cursor >= screenSize.Y)
cursor = 0;
}
int main()
{
const auto screenSize = getScreenSize();
SetConsoleScreenBufferSize(firstBuffer, screenSize);
SetConsoleScreenBufferSize(secondBuffer, screenSize);
frameData.resize(screenSize.X * screenSize.Y);
// Main rendering loop:
// 1. Draw frame to the back buffer.
// 2. Set back buffer as active.
while (true)
{
drawFrame(screenSize);
swapBuffers();
}
}
In this example, I went with a static FPS value for the sake of simplicity. You may also want to introduce some functionality to stabilize frame frequency output by counting the actual FPS. That would make your animation run smoothly independent of the console throughput.
Hi so I'm trying to make it so a little UFO bitmap (drawing/painting already taken care of) can be dragged around the screen. I can't seem to make the UFO position update and then redraw repeatedly from the MouseButtonDown() function (simplified code for mouse event handler). Any suggestions on detecting the dragging and redrawing accordingly? Code is below for relevant functions:
void MouseButtonDown(int x, int y, BOOL bLeft)
{
if (bLeft)
{
while(_bMouseMoving == true && _bMouseDragRelease == false) {
_iSaucerX = x - (_pSaucer->GetWidth() / 2);
_iSaucerY = y - (_pSaucer->GetHeight() / 2);
InvalidateRect(_pGame->GetWindow(), NULL, FALSE);
}
// Set the saucer position to the mouse position
_iSaucerX = x - (_pSaucer->GetWidth() / 2);
_iSaucerY = y - (_pSaucer->GetHeight() / 2);
}
else
{
// Stop the saucer
_iSpeedX = 0;
_iSpeedY = 0;
}
}
void MouseButtonUp(int x, int y, BOOL bLeft)
{
_bMouseDragRelease = true;
}
void MouseMove(int x, int y)
{
_bMouseMoving = true;
}
To clarify what chris said, you're only going to get the WM_xBUTTONDOWN message once, and you'll need to use that to toggle a dragging state that you can query when you recieve a WM_MOUSEMOVE message.
When you get the mouse move message during a dragging state, you'll want to invalidate the rectangle surrounding where the ufo was, and the rectangle surrounding where it is.
Invalidating a rectangle causes WM_PAINT messages, where you redraw whatever was behind the ufo, and the ufo in it's new place.
Or you could cheat and make the UFO a cursor when you're dragging :)
I have a QMainWindow with:
Two widgets in a horizontal splitter. "m_liner" is on the right side
Both widgets have a minimum size of say, 300 pixels.
A checkbox to hide/show the right-side widget m_liner.
I want the overall QMainWindow to expand when showing the widget, and shrink when hiding. The code below does this except:
If both widgets are shown, the minimum window size is 600 pixels.
Shrink the window to this smallest size.
Uncheck the box to hide the right-side widget.
Program hides the right-side widget.
Program calls this->resize(300, height);
The window ends up being 600 pixels wide (the minimum size with both widgets visible), instead of around 300 (the minimum size with only the left widget).
Later, I can resize the window down to 300 pixels with the mouse or another button. But it won't resize to 300 in the checkbox event, even if I call resize several times.
Does anyone have an idea how to solve this?
Critical bit of code follows, I have a full project available if you need it:
void MainWindow::on_checkBox_stateChanged(int val)
{
std::cout << "-------------------- Checkbox clicked " << val << std::endl;
bool visible = val;
QWidget * m_liner = ui->textEdit_2;
QSplitter * m_splitter = ui->splitter;
int linerWidth = m_liner->width();
if (linerWidth <= 0) linerWidth = m_lastLinerWidth;
if (linerWidth <= 0) linerWidth = m_liner->sizeHint().width();
// Account for the splitter handle
linerWidth += m_splitter->handleWidth() - 4;
std::cout << "Frame width starts at " << this->width() << std::endl;
std::cout << "Right Panel width is " << m_liner->width() << std::endl;
// this->setUpdatesEnabled(false);
if (visible && !m_liner->isVisible())
{
// Expand the window to include the Right Panel
int w = this->width() + linerWidth;
m_liner->setVisible(true);
QList<int> sizes = m_splitter->sizes();
if (sizes[1] == 0)
{
sizes[1] = linerWidth;
m_splitter->setSizes(sizes);
}
this->resize(w, this->height());
}
else if (!visible && m_liner->isVisible())
{
// Shrink the window to exclude the Right Panel
int w = this->width() - linerWidth;
std::cout << "Shrinking to " << w << std::endl;
m_lastLinerWidth = m_liner->width();
m_liner->setVisible(false);
m_splitter->setStretchFactor(1, 0);
this->resize(w, this->height());
m_splitter->resize(w, this->height());
this->update();
this->resize(w, this->height());
}
else
{
// Toggle the visibility of the liner
m_liner->setVisible(visible);
}
this->setUpdatesEnabled(true);
std::cout << "Frame width of " << this->width() << std::endl;
}
Sounds to me like there are some internal Qt events that need to get propagated before it recognizes that you can resize the main window. If this is the case then I can think of two potential solutions:
Use a queued single shot timer to call the code that resizes your window down to 300px:
m_liner->hide();
QTimer::singleShot( 0, this, SLOT(resizeTo300px()) );
or, after you hide your widget you can try a call to processEvents() (this function has potentially dangerous side effects, so use with caution):
m_liner->hide();
QApplication::processEvents();
resize( w, height() );
Another potential solution would be to set the horizontal size policy of your widget to ignored when hiding it:
m_liner->hide();
m_liner->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
resize( w, height() );
When showing your widget again, you'd need to adjust the size policy again.
So I'm simply trying to make a red 10 x 10 box move vertically back and forth. I compile and run my program and the red box appears starts moving down, then just disappears after it hits the edge of the screen. I used some cout << statements that tell me when the functions are being called and they are all being called when they are supposed to. Even when the box can't be seen the functions are properly being called.
My main loop
while(running)
{
myScreen->Clear();
boxes.Move();
boxes.Draw();
myScreen->Flip();
........
My draw() function
SDL_Color red;
red.r = 255;
red.g = 0;
red.b = 0;
if( SDL_FillRect( my_screen->Get_screen(), &start_dest, SDL_MapRGB(
my_screen->Get_pixel_format(), red.r, red.g, red.b ) ) == -1 )`
cout << "Fill rect in Draw(); failed\n";
My Move() function
start_dest.y += y_step;
if ( start_dest.y >= my_screen->Get_height() )
{
cout << "start_dest.y >= screen height\n";
start_dest.y = my_screen->Get_height();
y_step = -y_step;
}
if ( start_dest.y <= 0 )
{
cout << "start_dest.y <= 0\n";
start_dest.y = 0;
y_step = -y_step;
}
I have been trying to find this bug forever. just leave a comment if anyone wants to see more code. Thanks
There isn't enough information to give conclusive answer, but here's a hint.
From my experience with SDL, SDL functions can modify your Rect structure when called, especially when rect is partly off-screen. Make sure you set all its properties (x,y,width,height) before each SDL function that uses the rectangle.
(I'm assuming here that start_dest has a 'height' member, and that the screen coordinates have (0,0) in the top left corner)
I think perhaps the first 'if' statement in Move() should be
if(start_dest.y >= my_screen.Get_height - start_dest.height)
so that the rectangle will bounce when its bottom hits the bottom of the screen rather than waiting until the top of the rectangle gets there. Something to that effect, anyways.