Drawing Dice in a Windows C++ program? - c++

We just started learning windows programming in C++. We have to make a program that has 4 die on the screen, and when the user presses 'SpaceBar', the die roll, or the number of dots on the die change randomly. Our professor hasent given us a lot of information, so I am kind of just looking for some direction.
Right now, I have 4 squares drawn on the screen, made with the Rectangle() function.
Rectangle(hDC,30,100,130,200);
Rectangle(hDC,180,100,280,200);
Rectangle(hDC,330,100,430,200);
Rectangle(hDC,480,100,580,200);
My question is 1) how would I go about drawing dots on these 'squares' and not on the 'screen'. So if I move the die upwards, the dots move with the square and dont just stay stationed painted on the screen. And 2.) How would I go about making those dots randomly change when spacebar is pressed (simulating that they have been rolled)?
Just looking for some direction, thanks.

1)
You will still have to draw them on the screen, but you can structure your program to realize the dots as part of the square.
void moveSquare()
{
//change square position
//change dots positions the same as you changed the square
}
2)
You can capture keypresses in your window with the WM_KEYDOWN and WM_KEYUP messages, or the WM_CHAR message. Just start a chain of changing how many dots are supposed to appear on the die when space is pressed (SetTimer could be handy), and let WM_PAINT do the work of painting the dots (or call something to calculate the positions of the dots, and let WM_PAINT loop through each dot it needs to draw.
void OnSpacePressed()
{
//start changing dots every so often, handled elsewhere
//maybe check if finished rolling before doing so
}
void calculateDotPositions()
{
switch (numberOfDots) {...} //hint: use the square as a reference point
}
void OnPaint()
{
//paint each sqaure
//paint each dot in the correct position, which should be updated with square
}
void OnChangeDots()
{
//change number of dots
//also start a new change to happen later if not done rolling
}
For drawing dots, use Warren P's reference link.

Another method is to create a bitmap or picture in memory. One for each of the 6 faces of the die. The objective here is to copy the bitmaps to the screen, rather than having to redraw them each time. Research "bitmap", and "bitblt".

You should make a routine that draws a die at the origin, offset by given coordinates. I'm not familiar with the particular library you are using, so I don't know what hDC is, but it should look something like the following.
void drawDie(HDC hDC, int xCoord, int yCoord, int dieValue)
{
Rectangle(hDC, -50 + xCoord, -50 + yCoord, 50 + xCoord, 50 + yCoord);
// draw some number of circles specified by dieValue at appropriate coordinates
// translated by xCoord and yCoord arguments
}
Then you can just redraw dice over your previous ones if you want them to change.

Related

Change Cursor Image While Hovering Over An Object Drawn At OpenGL And Displaying Object's Variables

I am currently working on a project that I use C++, OpenGL, Qt 5.9.2 and Microsoft Visual Studio Professional 2015 on a 64 bit Operating System, Windows 10 Pro.
I have a user interface that I have created and in that user interface, there is a QGLWidget, that I am using for draw processes, with other widgets like push buttons and a dockWidget. I have a class Ball and it has variables(distance(double) and angle(int)) that determines where an instance of that Ball is going to be drawn inside the QGLWidget. Ball class has got 2 more variables that is, id(int), model(String) and year(int) Every other draw process draws lines except Ball drawings.
Drawings are 2 dimensional.
Every Ball has the same color(rgb)!
First problem: I want to left click to one of the Ball instances and I want to display it's id, model and year at The dockWidget.
Second Problem: While doing the stuff that I have mentioned at the First Problem section. I want the cursor image to change while hovering above any of the Ball instances, and change back to default Windows mouse cursor while not.
I have created a function that checks if the MouseEvent is LeftClick:
void DisplayManager::mousePressEvent(QMouseEvent* ev) {
if (ev->buttons() & Qt::LeftButton) { // Balls Are Green
if(// CHECK IF THERE IS A BALL AT THE CLICKED COORDINATES) {
// DISPLAY THE X and Y OF THE BALL AT THE DOCK WIDGET
}
}
}
This is my initializeGL function: (DisplayManager is the name of my QGLWidget)
void DisplayManager::initializeGL() {
glEnable(GL_COLOR_MATERIAL); // Enables the changing of the draw color with glColor() functions
glColor3f(0.0, 1.0, 0.0);
glEnable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 1); //sets a black background 1 0 0 1
}
On the basis this is a Picking problem and there are several information about it at the internet but I am not using GLUT and I am not using any shader. So in the light of all these I was unable to find any effective solution or clue about how can I accomplish all that I want.
I would be really glad if someone could help me with at least one of these problems.
I have currently finished working with the project. I thought that I should provide an answer to my question in case someone with a similar problem comes across with my question in the future.
void DisplayManager::mousePressEvent(QMouseEvent* ev) {
// The processes that are being executed after a left mouse button click on the DisplayManager.
if (ev->buttons() & Qt::LeftButton) {
double aspectRatio = openGLWidgetWidth / openGLWidgetHeight;
int xOfClicked = ev->x() - (openGLWidgetWidth / 2);
int yOfClicked = - (ev->y() - (openGLWidgetHeight / 2));
// The variable to be used for calculating fault tolerance of the click event.
int distanceBetweenPressAndDraw = 0;
// Executes the processes inside for every ball in vector.
for (int i = 0; i < ballVector.length(); i++) {
// Calculates the screen coordinates of the i'th ball.
int rangeOfBallInScreenDistance = rangeToScreenDistance(ballVector.at(i).range);
double screenXOfBall = rangeOfBallInScreenDistance * sin(ballVector.at(i).degree * DEGTORAD);
double screenYOfBall = rangeOfBallInScreenDistance * cos(ballVector.at(i).degree * DEGTORAD);
// Calculates the distance between pressed position and the i'th ball according to the screen coordinates.
distanceBetweenPressAndDraw = sqrt(pow((screenXOfBall - xOfClicked), 2) + pow((screenYOfBall - yOfClicked), 2));
// Decides if the clicked position is a ball (considering the fault tolerance).
if (distanceBetweenPressAndDraw < 10) {
emit printXY(QPointF(xOfClicked, yOfClicked)); // Prints the screen coordinates of the clicked positions (At the Dock Widget inside Main Window).
}
}
}
}
This was the solution for my First Problem. I would be glad though if someone could answer my Second problem in a comment or answer somehow.

c++ How to wait for multiple mouse clicks

I want to draw a Triangle in CImg library. However, I do not know how to write the code that will allow me to draw the triangle using three mouse clicks.
The code in the documentation is this:
while (!main_disp.is_closed() && !draw_disp.is_closed())
{
main_disp.wait();
if (main_disp.button() && main_disp.mouse_y()>=0)
http://cimg.sourceforge.net/reference/group__cimg__tutorial.html
But it is for one mouse click, which I implemented successfully to draw a circle on the mouse click. But to do for three mouse clicks or two has proven to be difficult for me.
I also have the problem of inputting the color I want. I wrote red for example as:
const unsigned char red[] = {250, 0, 0};
Then I want the user to choose which color, enter his choice(assume it's red) and then pass this definition of red into the image.
Anyone can help with this ?!
If you know how to detect when the mouse button is clicked, you can store information about that click for later. For example, you can store previous mouse clicks in a deque.
struct point
{
int x,y;
};
...
std::deque<point> clicks;
while (!main_disp.is_closed() && !draw_disp.is_closed())
{
main_disp.wait();
if (main_disp.button())
{
clicks.push_front({mouse_disp.mouse_x(), mouse_disp.mouse_y()});
if (clicks.size() >= 3)
{
// draw a triangle using clicks[0], clicks[1] and clicks[2]
}
}
}

How to clear a part of screen in SDL 2.0

So, currently i'm writing a game and i have a small texture(20x20) that fills screen (1680x1050). My player moves on this backgroud, all in game loop. I need my backgound to be static and drawn just once, but SDL_RenderClear redraws all the area and this causes to lag. How can i draw it once, and then update it with my player figure?
There is really no way to "Draw it once and leave it like that"
But there is a way you can make just a part of to draw in order to have the same result, just draw the part of the background that the character is, before drawing the new character.
In more details, draw all the "blocks" that are touched by the hero even by a little bit, then draw your hero over them.
Here is an example:
//LocationX is the location of hero on the X axis
//LocationX /20 is the number of the first texture that is drawn on X axis
//LocationX +Width (width of hero) +20 (width of texture) this is the number of the last texture on X axis
//Now draw everything from first to last texture that is touched the hero (just calculate the Y axis the same way as X axis!)
for (int xxx = LocationX /20; xxx < LocationX +Width + 20; xxx++)
{
for (/*Do the same for Y axis*/)
{
draw(texture, xxx *20, yyy *20);
}
}
//Draw Hero here, the background is clear!
Literally answering, you should use SDL_RenderDrawRect to 'clear a part of screen'.
However, you've mentioned that you have texture at background - RenderClear wouldn't draw a texture, so something in this description appears to be wrong.

Relative mouse position of SDL_Surface

In my application I need to return the relative mouse position from an SDL_Surface, the problem is the mouse position that gets returned is relative to the SDL window and not the SDL_Surface. I guess my question is what is the easiest / most effective way of doing this. Any questions just ask. Thanks.
EDIT: Sorry I should have explained better, I have SDL_Surface* Surf_Display; on Surf_display there is an Image say its 1000 x 1000, So in order to see the image on a 600 x 600 window I have a camera that I can move around ( really its the surface that moves not the camera ) for instance to look right of the image I move the surface -1 left if that makes sense. So my problem is when I click my mouse on a part of the surface(image) my mouse returns the position that the mouse compared to where the cursor is in the window, what i'm wanting is so that it returns the position of the cursor compared to where it is on the surface(image)
I hope that better explains the situation. Thanks again
Just add(or subtract, depending on how you look at it) the offset to the mouse coordinates. So you're drawing the surface something like this:
SDL_Rect dest_rect = { -camera.x, -camera.y };
SDL_BlitSurface(image_surface, NULL, screen_surface, &dest_rect);
I don't know if you're using event based mouse handling, or if you're using SDL_GetMouseState, but either way, you would simply add camera.x and camera.y to the mouse position, for example:
int x, y;
SDL_GetMouseState(&x, &y);
x += camera.x;
y += camera.y;

Need help in optimizing a drawing code ...

I needed some help in trying to optimize this code portion ... Basically here's the thing .. I'm making this 'calligraphy pen' which gives the calligraphy effect by simply drawing a lot of adjacent slanted lines ... The problem is this: When I update the draw region using update() after every single draw of a slanted line, the output is correct, in the sense that updates are done in a timely manner, so that everything 'drawn' using the pen is immediately 'seen' the drawing.. however, because a lot (100s of them) of updates are done, the program slows down a little when run on the N900 ...
When I try to do a little optimization by running update after drawing all the slanted lines (so that all lines are updated onto the drawing board through a single update() ), the output is ... odd .... That is, immediately after drawing the lines, they lines seem broken (they have vacant patches where the drawing should have happened as well) ... however, if I trigger a redrawing of the form window (say, by changing the size of the form), the broken patches are immediately fixed !! When I run this program on my N900, it gets the initial broken output and stays like that, since I don't know how to enforce a redraw in this case ...
Here is the first 'optimized' code and output (partially correct/incorrect)
void Canvas::drawLineTo(const QPoint &endPoint)
{
QPainter painter(&image);
painter.setPen(QPen(Qt::black,1,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
int fx=0,fy=0,k=0;
qPoints.clear();
connectingPointsCalculator2(qPoints,lastPoint.x(),lastPoint.y(),endPoint.x(),endPoint.y());
int i=0;
int x,y;
for(i=0;i<qPoints.size();i++)
{
x=qPoints.at(i).x();
y=qPoints.at(i).y();
painter.setPen(Qt::black);
painter.drawLine(x-5,y-5,x+5,y+5); **// Drawing slanted lines**
}
**//Updating only once after many draws:**
update (QRect(QPoint(lastPoint.x()-5,lastPoint.y()-5), QPoint(endPoint.x()+5,endPoint.y()+5)).normalized());
modified = true;
lastPoint = endPoint;
}
Image right after scribbling on screen:
http://img823.imageshack.us/img823/8755/59943912.png
After re-adjusting the window size, all the broken links above are fixed like they should be ..
Here is the second un-optimized code (its output is correct right after drawing, just like in the second picture above):
void Canvas::drawLineTo(const QPoint &endPoint)
{
QPainter painter(&image);
painter.setPen(QPen(Qt::black,1,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
int fx=0,fy=0,k=0;
qPoints.clear();
connectingPointsCalculator2(qPoints,lastPoint.x(),lastPoint.y(),endPoint.x(),endPoint.y());
int i=0;
int x,y;
for(i=0;i<qPoints.size();i++)
{
x=qPoints.at(i).x();
y=qPoints.at(i).y();
painter.setPen(Qt::black);
painter.drawLine(x-5,y-5,x+5,y+5); **// Drawing slanted lines**
**//Updating repeatedly during the for loop:**
update(QRect(QPoint(x-5,y-5), QPoint(x+5,y+5)).normalized());//.adjusted(-rad,-rad,rad,rad));
}
modified = true;
int rad = (myPenWidth / 2) + 2;
lastPoint = endPoint;
}
Can anyone see what the issue might be ?
Sorry if I misunderstood, but have you tried to use the "double buffer" approach? Instead of drawing directly on the screen, you "draw" your points and lines to a memory buffer. After that, you just copy the buffer to the screen. This is faster and avoids flickering.
As I understand you should find min and max of x and y processed in your for-loop and use them in update(QRect(QPoint(minX-5, minY-5), QPoint(maxX+5, maxY+5)).normalized());
I'm not sure exactly what your issue is with the broken lines, but I can offer you this advice: keep your pen around. Instead of this:
for(i=0;i<qPoints.size();i++)
{
// ...
painter.setPen(Qt::black);
painter.drawLine(x-5,y-5,x+5,y+5); **// Drawing slanted lines**
// ...
}
do this:
QPen black_pen(Qt::black);
for(i=0;i<qPoints.size();i++)
{
// ...
painter.setPen(black_pen);
painter.drawLine(x-5,y-5,x+5,y+5); **// Drawing slanted lines**
// ...
}
Even more, if you are repeatedly calling your drawLineTo function with the same pen every time, store the pen in your class and keep it around. At my company, we've found that to vastly reduce drawing times where we can take advantage of it. (One instance on a large image cut drawing times in half.)
One other note: I'm not sure what type the image you are painting is, but I'm assuming it is a QImage. When you are done drawing, if you will be using the unmodified image repeatedly, you might convert it once to a QPixmap. The QPixmap class is stored in a way that is supposed to be ready for blitting directly to the screen (but it a lot slower to modify in many cases, because of that).