"Screen Saver" help

Started by
7 comments, last by BugTilaheH 22 years, 4 months ago
Hey, Bug here again with another problem (I''m still not done with the other program, the one with the random maze, but I will post the source to that someday..). 8) OK, this time I have a program that I''ve already made myself which draws unfilled circles on the screen. They increment in a random direction from the middle to the "edge". As soon as they hit the "edge" (within 10 pixels from the screen''s edge), they bounce off it and go for another edge. The program does this infinitely until a key is pressed, hence the "screen saver" effect to it. The only problem with this is that the circles are kept being drawn to the screen, and they fill it up over time. Now, how would I enqueue the coordinates and say, dequeue them after 10 circles are drawn to the screen so that the previous 10 are erased from the screen without using a clear screen function? So that it gives the appearance of a circle bouncing off the edge with a small trail? I know how to use a queue, but I don''t know how it''s possible to enqueue circles and then erase them after so many are on the screen. *scratches head* The queue implementations are done with a templated class, so any data type can be used, I suppose. My circles program is done the OOP way with classes and such (in C++, NO Windows programming), btw. If you need my code to better understand what I''m trying to do, just ask and I''ll post it here. Also, if this topic has been answered before in another post, please direct me to it ''cos I couldn''t find any posts with any help to this problem. I''ve been searching the internet and gametutorials.com for answers as well, and nothing has helped yet. :-/ -Bug /********************************* * Website: The Page of Stuff.COM * * Message board: POS.COM Forum   * *********************************/
-Bug/********************************** Website: The Page of Stuff.COM ** Message board: POS.COM Forum   **********************************/
Advertisement
Two ways to do that:

For either way, I would use a linked list to store the 10 elements you want to see.


Method 1)Clear the screen between every frame and draw all of the circles in the list. Pop the back circle (oldest) off the list and push the new circle onto the front of the list.

Method 2)Pop the back circle off the list and redraw it, this time using the color of the background. Then push the new circle onto the front of the list and draw it in the circle color.
Hold on a minute..
OK, I think I got it. I used a count iterator so that whenever it hits an edge, it increments, and if the counter is 1 or above it dequeues the previous circle and draws it in black. I had thought of this before, but I didn''t quite finish the count for all cases for some reason last night (I was getting tired..).. so now it works! Sorta.. It looks like a bug flying around the screen, LOL! Anyway, I think I got it now.. Now, just to fix this little bug.. ^_^;



-Bug
/*********************************
* Website: The Page of Stuff.COM *
* Message board: POS.COM Forum   *
*********************************/
-Bug/********************************** Website: The Page of Stuff.COM ** Message board: POS.COM Forum   **********************************/
Arg! I can't get it to stop from "shaking violently" (the bug thing). o.O;;;; See, it's drawing the circles twice and it flickers from one to the other at a delay time of 100.

Instead of trying to explain this, check these pics out and the following code that makes it do this:
bounce.gif
bounce1.gif

Code:

          void Circles::DrawCircles(){	Count = 0;	GFX320 C; //class with graphics functions like circle, etc.	apqueue < int > Q; // initialize Q as a queue as type int	Q.makeEmpty();	do	{		delay(100);		C.SetColor(Color); //the color changes when an edge is hit		Q.enqueue(CenterX);		Q.enqueue(CenterY);		C.Circle(CenterX,CenterY,Radius);	if (Count>=1 && !Q.isEmpty())	{		C.SetColor(0); //color==black		Q.dequeue(CenterX);		Q.dequeue(CenterY);		C.Circle(CenterX,CenterY,Radius);	}        else           ...        }        while (!kbhit());}          


Have any ideas of how I could fix this, or do you need more code?

I've tried replacing the if statement with while and added Count=0; into it and it did the same IIRC,.. so..





-Bug
/*********************************
* Website: The Page of Stuff.COM *
* Message board: POS.COM Forum   *
*********************************/


Edited by - BugTilaheH on December 9, 2001 11:57:19 PM

Edited by - BugTilaheH on December 9, 2001 12:06:49 AM

Edited by - BugTilaheH on December 9, 2001 12:07:56 AM
-Bug/********************************** Website: The Page of Stuff.COM ** Message board: POS.COM Forum   **********************************/
Here is an entirely different method:

Try using a structure of 10 elements(forgive me, my C/C++ lingo may be off as I haven''t used it in awhile.) 2 elements to hold the center coords(X, Y), one for the radius of the circle, one for color of the circle(if needed) and one as a Time-to-live(TTL) marker.

Now each time you make a new circle you put it into an empty slot(those less than 1 in their TTL element) filling all the members with the desired values, setting the TTL element to 9.

Each time you draw the screen you decrement each of the TTL elements. now when it''s time for a new circle, the oldest circle''s TTL will be 0 and it will be replaced! This is a rather easy and simple solution.

If you need more info email me at:

nyninteractive.mike@angelfire.com

throw table_exception("(? ???)? ? ???");

Ok, going for the screen clear option... And I''m going to drastically oversimplify the things like the movement vector, just dividing the screen into a 160 x 120 area, figuring each circle should fit in one of those squares. The ''vector'' is a x step and a y step. I didn''t double check this, so it may have some errors:

  typedef list<Circle> CircleList;DWORD gXStep;DWORD gYStep;DWORD gXPosition;DWORD gYPosition;CircleList gChain;void MoveChain(){    //BOUNCE X    if(gXPosition + gXStep > 160 || gXPosition + gXStep < 0)        gXStep = -(gXStep);    //BOUNCE Y    if(gYPosition + gYStep > 120 || gYPosition + gYStep < 0)        gYStep = -(gYStep);    //CREATE CIRCLE        Circle c(gXPosition + gXStep, gYPosition + gYStep);    //ADD NEW HEAD    gChain.push_front(c);    //DELETE OLD TAIL    gChain.pop_back();}void DrawChain(){    CircleList::iterator it;    it = gChain.begin();    while(it != gChain.end()){        Circle c = (*it);        c.Draw();        it++;    }}  


if you wanted to do it without clearing the screen every time, than you could do the ''method 2'' jonStelley posted; however; one thing you would want to do that isn''t mentioned is redraw all of the circles every frame. If you take the oldest circle and redraw it using the background color, then it will overwrite any intersections with other circles.

So you would want to redraw the oldest circle in the background color, pop it off the front of the queue, re-draw the remaining 9 circles, draw the new circle, and push it onto the back of the queue.

Another option (if you only use one color (or always erase the oldest (or farthest back) thing to be drawn)) would be to store an array the size of the screen that stored how many times you had written to a given pixel using the color you are drawing with. When you erase a circle, you erase it from the logical array of counts; by decrementing each count. if the count hits 0, then you draw black to the screen, but if it isn''t 0, then you leave it alone. When you draw the circles in the first place, you have to make sure to draw to the screen, and increment the count of each pixel in the logical array. This works as long as you don''t overflow any of the counters, of course. (ie: there needs to be an upper limit on the total number of interesecting objects).

however, if you only have a small number of trailing circles, re-drawing the entire chain is probably preferable. (the second approach is better if you had a large number of trailing circles (ie: the second approach, as the number of circles grows, doesn''t really end up doing more work -- the total work done each frame is fairly constant, however, that work is probably greater than the work required to simply draw n circles to the screen, if n is small))

OK, I fixed it to where it''ll draw a circle on the screen.. but it doesn''t leave a trail .. What it does is enqueue the circle and then turn around and dequeue it (or draw it in black) as soon as the next circle is drawn.. so how would I get a trail of say, 10 circles (using my code below)?

  void Circles::DrawCircles(){	GFX320 C;	apqueue < int > Q;	Q.makeEmpty();	do	{		delay(100);		C.SetColor(Color);		for (int X=0; X<=100; X++)		{			Q.enqueue(CenterX);			Q.enqueue(CenterY);			C.Circle(CenterX,CenterY,Radius);		}		while (!Q.isEmpty()) //should something be added here?		{			C.SetColor(0); //black like the background			Q.dequeue(CenterX);			Q.dequeue(CenterY);			C.Circle(CenterX,CenterY,Radius);		}         }   ...         while (!kbhit());}  


Oh, and I cannot use stack functions.. just queue. I don''t have access to any queue functions except isEmpty (EmptyQueue), makeEmpty (ClearQueue), enqueue, and dequeue. I don''t think I can use front, back or length.. maybe a counter iterator would work but I don''t know how I can do that.


-Bug
/*********************************
* Website: The Page of Stuff.COM *
* Message board: POS.COM Forum   *
*********************************/
-Bug/********************************** Website: The Page of Stuff.COM ** Message board: POS.COM Forum   **********************************/
OK, I figured it out in class today! I kinda cheated though.. I got help by the guy next to me, but he owed me anyway 'cos I let him cheat on a previous lab.. so we're even. I don't see anything wrong with helping each other out.

    #include < iostream.h >#include < iomanip.h >#include "APQUEUE.H"#include "GFX320.H"class Circles{   private:      int Count;      //rest of data here...   public:      Circles();      ~Circles();      void EnterData();      bool HitEdge();      void NewData();      void DrawCircles();};void main(){   clrscr();   Circles C;   C.EnterData();   C.DrawCircles();}Circles::Circles(){}Circles::~Circles(){}void Circles::EnterData(){   ...}bool Circles::HitEdge(){   ...   return 0;}void Circles::NewData(){   ...}void Circles::DrawCircles(){   Count=0;   GFX320 C;   apqueue <int> Q;   apqueue <int> Q1; // two queues needed, duh...   do   {      delay(100);      Count++;      C.SetColor(Color);      Q.enqueue(CenterX);      Q1.enqueue(CenterY);      C.Circle(CenterX,CenterY,Radius);         if (Count > 10) //the trail is n circles long            {               int A,B;	       C.SetColor(0); //black	       Q.dequeue(A);	       Q1.dequeue(B);	       C.Circle(A,B,Radius);	       C.SetColor(Color);            }   }   while (!kbhit());}    


OK.. so maybe it works without using Count as a parameter (I didn't check) but it works this way anyway.. the point is, it works and that's all that matters! ^_^

EDIT- Durr.. no need to pass a parameter if Count is in the private segment..

-Bug
/*********************************
* Website: The Page of Stuff.COM *
* Message board: POS.COM Forum   *
*********************************/


Edited by - BugTilaheH on December 11, 2001 5:08:06 PM
-Bug/********************************** Website: The Page of Stuff.COM ** Message board: POS.COM Forum   **********************************/

This topic is closed to new replies.

Advertisement