I am trying to do a little game, and in my game I have some squares and when the user click on these squares, they got highlighted. To achieve this effect I am using glutMouseFunc with glutTimerFunc.
When the user clicks on the screen I pick the pixel and identify the square I need to highlight. Once the square is identified I call glutTimerFunc. The function registred with glutTimerFunc increase the value of each component of color by 0.01 until they reach one max value defined by me, then this value goes back to a minimum value.
glutTimerFunc execute in 60 milliseconds and I get a almost smooth shine effect.
My problem is, if I click on two squares very fast, the effect starts on the first square, but don't finish, so the square remains highlighted and the second squares do the entire effect. If I click like a crazy man on every square, all of them got highlighted.
How can I make this effect of shining terminate even if I click on other square?
Here is a snippet of code
void Memoria::shineEffect(GLint value) {
if(value == 1) {
for(GLint i = 0; i < 3; i++) {
if(colors[selectedSquare][i] > 0) {
colors[selectedSquare][i] += COLOR_INCREASE;
if(colors[selectedSquare][i] >= MAX) {
colors[selectedSquare][i] = MAX;
value = -1;
}
}
}
glutTimerFunc(FPS, timeWrapper, value);
}
else {
if(value == -1) {
for(GLint i = 0; i < 3; i++) {
if(colors[selectedSquare][i] > 0) {
colors[selectedSquare][i] -= COLOR_INCREASE;
if(colors[selectedSquare][i] <= MIN) {
value = 0;
colors[selectedSquare][i] = MIN;
}
}
}
glutTimerFunc(FPS, timeWrapper, value);
}
}
}
timeWrapper calls shineEffect if the value passed in the parameter is 1 or -1.
You want the shineEffect function to go through one highlight loop at least, and then stop if the highlighted item has changed. It's more a UI code design issue rather than an OpenGL or GLUT one.
The mechanic you need to implement is pretty straightforward:
install once for all an updateHighlights function with glutTimerFunc: this function will be responsible of updating the highlights of all the clicked elements,
create a queue of elements: each time an element has been clicked, add it to the queue,
The task performed by the updateHighLights function should be as follow:
if the queue contains one element, keep cycling its highlight as you already do in your program
if the queue contain more than one element, for each element in the queue,
step the highlight cycle
if the cycle is over, and the element is not the last one, remove the element from the queue
Here's another perhaps more flexible take on your problem.
The Glut event loop machinery is very simple design: there's only one hook to put your "idle work" code, so it's probably more flexible to install a function there which calls a list of others functions. That list could be then modified with a set primitive, to install or remove specific tasks to perform during idle time. This could be much more flexible than the "one function" approach of GLUT.
For instance, you could isolate your current highlight code in one function with a struct containing the element to highlight, and have the function remove itself from the list when its element is done through a highlight cycle and isn't active anymore.
Since you are using C++, it should be easy to bundle all these functionalities in classes:
one class for the list of idle tasks
one base class for idle tasks
one derived idle task class for the purpose of highlighting a square (with fields for the square and for the active status)
one class to keep track of the active square, so that it may be easily deactivated and replaced by the new active one. This one would be accessed by the glutMouseFunc function.
Related
I have a Worker Thread that copes with heavy and long computations (up to tenth of seconds). These computations produce several thousands of QLines, representing the edges of a dynamically-growing tree.
These edges can be modified anytime, since they connect the nodes of the trees by checking the cost, represented by the distance.
I would like a smooth update of the QGraphicsScene containing the edges.
I tried with signal and slots:
Worker thread emits a signal, so when the buffer is full this signal gets caught by the main thread, that will cope with the update/drawing of the line
This signal gets still caught by the main thread, but it seems it gets emitted very often, so QGraphicsView gets choked with QLine to be added
Changing the size of the buffer doesn't matter
Is there an alternative approach to this?
The main slot is:
void MainWindow::update_scene(bufferType buffer)
{
for (int i = 0; i < buffer.size(); ++i)
{
if (buffer[i].first < (g_edges.size() - 1))
{
delete g_edges[buffer[i].first];
g_edges[buffer[i].first] = scene->addLine(buffer[i].second);
}
else
g_edges.push_back(scene->addLine(buffer[i].second));
}
}
Note that bufferType is of type QList<std::pair<int,QLine>>.
Here is the heavy computing part
while (T.size() < max_nodes_number && !_stop)
{
const cnode random_node = rand_conf ();
const cnode nearest_node = T.nearest_node (random_node);
cnode new_node = new_conf (nearest_node, random_node);
if (obstacle_free(nearest_node, new_node))
{
QList<cnode*> X_near = T.neighbours (new_node, max_neighbour_radius);
cnode lowest_cost_node = nearest_node;
qreal c_min = nearest_node.cost() + T.distance (nearest_node, new_node);
for (int j = 0; j < X_near.size(); ++j)
{
if (obstacle_free(*X_near[j], new_node) && ((X_near[j]->cost() + T.distance (*X_near[j], new_node)) < c_min))
{
c_min = X_near[j]->cost() + T.distance (*X_near[j], new_node);
lowest_cost_node = *X_near[j];
}
}
T.add_node (new_node, lowest_cost_node.id());
queue (new_node.id(), QLine (new_node.x(), new_node.y(), lowest_cost_node.x(), lowest_cost_node.y()));
for (int j = 0; j < X_near.size(); ++j)
{
if (obstacle_free(*X_near[j], new_node) && (new_node.cost() + T.distance (new_node, *X_near[j])) < X_near[j]->cost())
{
queue (X_near[j]->id(), QLine (new_node.x(), new_node.y(), X_near[j]->x(), X_near[j]->y()));
T.update_parent (*X_near[j], new_node.id());
T.rewire_tree (X_near[j]->id());
}
}
}
}
emit finished();
Please note that T is a class representing a Tree. It is constituted by some methods allowing to add a node, searching for the nearest one, etc. It has a QList<cnode> as private member, storing the tree's nodes. cnode is a structure constituted of two coordinates, an id, a parent, a cost, a list of its children.
The solution is as usual - avoid frequent queued connections, as those are quite slow. Queued connections are a coarse grain construct and such be used as such.
Batch the work. In your scenario, you could aggregate the computed lines in a container, and only when it reaches a certain threshold, pass that container to the main thread to draw/update the lines. The threshold can be count, time or a combination of both, you don't want not updating if there are only a few results to update. You will need to expand on your design to split the while loop to run in the thread event loop instead of blocking so you can aggregate and pass updates periodically - something similar to this. This is always a good idea for workers that take time - you can monitor progress, cancel, pause and all sorts of handy stuff.
Those 2 lines look fishy:
edges.removeAt(i);
edges.insert (i, scene->addLine (l));
Then you remove and then insert - that's an invitation for potential costly reallocation, even without reallocation there is unnecessary copying involved. Instead of removing and inserting you can simply replace the element at that index.
In your case you might omit splitting the actual while loop. Just don't emit in the loop, instead do something like this (pseudocode):
while(...) {
...
queue(new line)
...
queue(update line)
...
queue(final flush)
}
void queue(stuff) {
stuffBuffer.append(stuff)
if (stuffBuffer.size() > 50 || final_flush) {
emit do_stuff(stuffBuffer) // pass by copy
stuffBuffer.clear() // COW will only clear stuffBuffer but not the copy passed above
}
}
Or if it will make you feel better:
copy = stuffBuffer
stuffBuffer.clear()
emit do_stuff(copy)
This way the two containers are detached from the shared data before the copy is emitted.
EDIT: After a long discussion I ended up proposing a number of changes to the design to improve performance (the queued connections were only one aspect of the performance problem):
alleviate the graphics scene - find a compromise between "one item per line" and "one item for all lines" solution, where each item handles the drawing of the lines of its direct children, balancing between the CPU time for adding items to the scene and redrawing items on data changes.
disable automatic scene updates, and instead control the scene update explicitly, this way the scene is not updated for each and every tiny change.
aggregate view commands in batches and submit the work buffer at a fixed interval to avoid queued signals overhead.
The explanation might be confusing or long (or both), so please let me know if there needs to be any clarification.
I am currently designing a backtracking algorithm to find a solution for something similar to what a game of "snake" looks like.
The program will start with a 2D grid, where some of the cells are inaccessible (like an obstacle). The program then proceeds with a backtracking algorithm to connect int x sequence of cells into a string-like group, then repeats this process until all int y accessible cells in the grid are connected into y / x groups. There are no cases where y is indivisible by x.
To determine the cost of the group, there are certain priority on the direction of the connection. For simplification, I will only use 3 connection types, double horizontal, double vertical, and double diagonal, where horizontal has the lowest cost and diagonal has the highest.
I've spent numerous days on trying to come up with different backtracking algorithms, but none of them had worked so far.
Here's a rough sketch of what I have(actual code has lots of custom class involved, so it may cause a lot of confusions):
String_c Grid::backtracking(int x, int y, int tot_pnl_needed, String_c &str_orig){
bool branch_found = false;
String_c str_cur = str_orig;
// set cell (x,y) as occupied. OCCUPIED is an enum value
set_avail(x,y,OCCUPIED);
str_cur.push_cell(x,y);
if (str_cur.is_complete()) {
return str_cur;
}
String_c str_tmp;
std::priority_queue<String_c, std::vector<String_c>, compareString> queue;
// if the neighboring cell is available, create a branch
if (is_available(x+1, y)){ // right side
tmp_str = backtracking(x+1, y, tot_pnl_needed-1, str_cur);
if (tmp_str == failed){ // assume that "failed" is a special String_c object. == operator is overloaded.
set_avail(x+1,y,AVAILABLE); // AVAIL is an enum value
tmp_str.pop_cell();
}
else{
branch_found = true;
queue.push(&tmp_str);
}
}
// copy this selection code above for each different direction
if (branch_found) {
while (!queue.empty()) {
// push all branches into the stack, which is a parameter of Grid class
stack.push(queue.pop());
}
else return failed;
return stack.top();
This is a pseudo code for the minimum backtracking algorithm required. In actual program, if the algorithm hits branch_found == false at the end, it needs to flip the sequence of the String_c, then continue the backtracking until it finds no branch again. Again, after one backtracking algorithm is finished, it will be called again until all cells are occupied.
One thing to be noted is that even if a String_c is completed and is pushed to the stack, it may be reverted later if none of its branch had found a solution.
This is the first time attempting to program a backtracking algorithm, so it was really stressful even to come up with this (which still fails...)
If you are the expert at this matter, I would greatly appreciate your help.
I have a vector holding 10 items (all of the same class for simplicity call it 'a'). What I want to do is to check that 'A' isn't either a) hiding the walls or b) hiding another 'A'. I have a collisions function that does this.
The idea is simply to have this looping class go though and move 'A' to the next position, if that potion is causing a collision then it needs to give itself a new random position on the screen. Because the screen is small, there is a good chance that the element will be put onto of another one (or on top of the wall etc). The logic of the code works well in my head - but debugging the code the object just gets stuck in the loop, and stay in the same position. 'A' is supposed to move about the screen, but it stays still!
When I comment out the Do while loop, and move the 'MoveObject()' Function up the code works perfectly the 'A's are moving about the screen. It is just when I try and add the extra functionality to it is when it doesn't work.
void Board::Loop(void){
//Display the postion of that Element.
for (unsigned int i = 0; i <= 10; ++i){
do {
if (checkCollisions(i)==true){
moveObject(i);
}
else{
objects[i]->ResetPostion();
}
}
while (checkCollisions(i) == false);
objects[i]->SetPosition(objects[i]->getXDir(),objects[i]->getYDir());
}
}
The class below is the collision detection. This I will expand later.
bool Board::checkCollisions(int index){
char boundry = map[objects[index]->getXDir()][objects[index]->getYDir()];
//There has been no collisions - therefore don't change anything
if(boundry == SYMBOL_EMPTY){
return false;
}
else{
return true;
}
}
Any help would be much appreciated. I will buy you a virtual beer :-)
Thanks
Edit:
ResetPostion -> this will give the element A a random position on the screen
moveObject -> this will look at the direction of the object and adjust the x and Y cord's appropriately.
I guess you need: do { ...
... } while (checkCollisions(i));
Also, if you have 10 elements, then i = 0; i < 10; i++
And btw. don't write if (something == true), simply if (something) or if (!something)
for (unsigned int i = 0; i <= 10; ++i){
is wrong because that's a loop for eleven items, use
for (unsigned int i = 0; i < 10; ++i){
instead.
You don't define what 'doesn't work' means, so that's all the help I can give for now.
There seems to be a lot of confusion here over basic language structure and logic flow. Writing a few very simple test apps that exercise different language features will probably help you a lot. (So will a step-thru debugger, if you have one)
do/while() is a fairly advanced feature that some people spend whole careers never using, see: do...while vs while
I recommend getting a solid foundation with while and if/else before even using for. Your first look at do should be when you've just finished a while or for loop and realize you could save a mountain of duplicate initialization code if you just changed the order of execution a bit. (Personally I don't even use do for that any more, I just use an iterator with while(true)/break since it lets me pre and post code all within a single loop)
I think this simplifies what you're trying to accomplish:
void Board::Loop(void) {
//Display the postion of that Element.
for (unsigned int i = 0; i < 10; ++i) {
while(IsGoingToCollide(i)) //check is first, do while doesn't make sense
objects[i]->ResetPosition();
moveObject(i); //same as ->SetPosition(XDir, YDir)?
//either explain difference or remove one or the other
}
}
This function name seems ambiguous to me:
bool Board::checkCollisions(int index) {
I'd recommend changing it to:
// returns true if moving to next position (based on inertia) will
// cause overlap with any other object's or structure's current location
bool Board::IsGoingToCollide(int index) {
In contrast checkCollisions() could also mean:
// returns true if there is no overlap between this object's
// current location and any other object's or structure's current location
bool Board::DidntCollide(int index) {
Final note: Double check that ->ResetPosition() puts things inside the boundaries.
I know that in order to kill invaders in C++, I need to make a collider.
However, nothing will ever kill the invaders in that game.
Here's the code in the header:
bool DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight);
This is the function I'm initializing:
bool Game::DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight) {
if (Xbpos+BulWidth < Xipos || Xbpos > Xipos+InvWidth) return false;
if (Ybpos+BulHeight < Yipos || Ybpos > Yipos+InvHeight) return false;
return true;
}
And this is what happens if somebody presses the space key:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
}
Does anybody know what's going wrong?
The problem isn't C++. The problem is how you are using it. The only way you'll get a kill with your code as written is if the invader is right on top of you. But that's too late. The alien invader has already killed you.
What you need to do is make those bullets into objects that you propagate over time, just like your invaders are objects that you propagate over time. The response to the user pressing a space key should be to add a new instance of a bullet to the set of active bullets. Each of those active bullets has a position that changes with time. On each time step, you should advance the states of the active invaders per the rules that dictate how invaders move and advance the states of the active bullets per the rules that dictate how bullets move. Remove bullets when they reach the top of the screen, and if an alien invader reaches the bottom of the screen, game over.
After propagating, removing off-screen bullets, and checking for game over, you want to check for collisions between each of the N bullets with each of the M invaders. When a collision is detected, remove the bullet from the set of active bullets and delete the alien invader from the set of active invaders. And of course you'll want some nifty graphics to show the user that another alien bit the dust.
Aside: Being an NxM problem, this check might be the biggest drain on CPU usage. You can speed this up with some simple heuristics.
You could manage the collections of alien invaders and bullets yourself, carefully using new and delete so as to prevent your invaders and bullets from killing your program with a memory leak. You don't have to do this. C++ gives you some nifty tools to manage these collections. Use one of the C++ standard library collections instead of rolling your own collection. For example, std::vector<AlienInvader> invaders; or std::list<AlienInvader> invaders, and the same for bullets. You'll be deleting from the middle a lot, which suggests that std::list or std::deque might be more appropriate than std::vector here.
You test the collision for the fired item just when they are created
Shouldn't be the test collision done in the main loop for each existing item at each frame ?
Don't worry, C++ has got all you need to kill invaders :)))
It's not easy to give advice based on so little code, but here the only logical error seems to be you test for collision only when space is pressed; you should test for it in an outside loop probably:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
}
From a logical point of view, pressing Space should fire a bullet: the starting position for the bullet is set, and so is its speed on the Y axis (so that it goes up).
The code that check for collision should go outside of this if block. In fact, this block of code is executed only if you're still pressing space -that is: still firing-. Should collision be checked only if you're "still firing"? Do the fact that you fired a bullet and started waiting for it to destroy the invader interfere in some way with the fact that this bullet can reach the invader and, indeed, destroy it? Of course not!
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
You want collision to be checked in an outside loop, the same that probably also contains the checks for key presses. In this way, even if you're just looking at the screen and waiting, the program keeps testing the condition and, when it's fulfilled, code associated with the event of collision is executed (that is: an invader is "inactivated").
You say //Space , is that what it is or should it be 32 (if ASCII) instead of 57? Does the program flow into the if==57 block?
Your code looks fine, but you need two loops around the collision checker: one for checking all invaders (not just one of them) and another one to check at every bullet position along its trajectory, not just the moment when it leaves the gun.
I will assume we have an auxiliary function that moves the bullet and returns whether it is still inside the screen:
bool BulletIsInScreen();
Then we can write the loops:
if (code == 57) { // Space
while (BulletIsInScreen()) {
for (size_t i = 0; i < counter; ++i) { // counter is the number of invaders,
// according to your comment to your own answer
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[i].MyBullet.Xbpos, Invaders[i].MyBullet.Ybpos,
Invaders[i].MyBullet.BulWidth, Invaders[i].MyBullet.BulHeight,
Invaders[i].Xipos, Invaders[i].Yipos,
Invaders[i].InvWidth, Invaders[i].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[i].Active = false;
printf("Collide!\n");
}
}
}
}
Now this should work as expected.
Hello I am trying to get enemies to move left and right as if they are sliding backwards and forwards I know this can be done with the following code:
slide += slide_incr;
if(abs(slide)>30) slide_incr = -slide_incr;
However this is of no use to me as I need to set a boolean so I can cycle through the frames for when the enemy is going right or going left.
Ive tried the follow code with no luck:
if(abs(eSlide)<=0)
{
eSlide += eSlide_incr;
}
if(abs(eSlide)>30)
{
eSlide_incr = -eSlide_incr;
}
Any ideas on how I can implement it?
Thanks
You want to hold a hysteresis state for if you're sliding forward or backward. You are also mixing up how to use the abs() function when bounds checking. Try something along the lines of:
eSlide += eSlide_incr;
if (abs(eSlide) >= 30) {
eSlide_incr = -eSlide_incr;
}
the first thing that stands out for me is that the contents of the block:
if (abs(eSlid) <= 0) {
eSlide += eSlide_incr;
}
will never ever run (the absolute value will always be greater than or equal to 0)
as for your boolean facing, that can be achieved with:
bool isSlidingRight = eSlide_incr > 0;
(note: this would still use the left animation set for values of 0)