Starfield, stars are *sometimes* not erased..

Started by
5 comments, last by soundsystem 19 years, 11 months ago
I am doing a simple star field.. problem is that the stars are drawn "twice".. so if the star is at 0, 0, it is drawn, then what is supposed to happen is that the 0,0 star gets erased and it''s supposed to be drawn at a new location.. let''s say the velocity is 5.. It should start at 0,0 then 5,0 then 10,0.. etc. but I see 2 dots, one at 0,0 and one at 5,0, then one at 5,0 and one at 10,0.. etc. So there is 2 dots following each other. I am using FillRect() to draw the black BG.. here is that part of the code:

		// Black out the screen for redrawing. 

		SDL_FillRect(screen,  0, SDL_MapRGB(screen->format, 0, 0, 0)); 
		// Redraw screen. 

		draw_scene(screen); 
		SDL_Flip(screen); 
The whole code is below (don''t comment on code design/style please, this is very early, I like to get things working before optimizing/cleaning, I just threw variables all over the place):

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <SDL/SDL.h>
using namespace std; 

void DrawPixel(SDL_Surface *screen, Uint8 R, Uint8 G, Uint8 B, int x, int y)
{
    Uint32 color = SDL_MapRGB(screen->format, R, G, B);

    if ( SDL_MUSTLOCK(screen) ) {
        if ( SDL_LockSurface(screen) < 0 ) {
            return;
        }
    }
    switch (screen->format->BytesPerPixel) {
        case 1: { /* Assuming 8-bpp */
            Uint8 *bufp;

            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
            *bufp = color;
        }
        break;

        case 2: { /* Probably 15-bpp or 16-bpp */
            Uint16 *bufp;

            bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
            *bufp = color;
        }
        break;

        case 3: { /* Slow 24-bpp mode, usually not used */
            Uint8 *bufp;

            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
            *(bufp+screen->format->Rshift/8) = R;
            *(bufp+screen->format->Gshift/8) = G;
            *(bufp+screen->format->Bshift/8) = B;
        }
        break;

        case 4: { /* Probably 32-bpp */
            Uint32 *bufp;

            bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
            *bufp = color;
        }
        break;
    }
    if ( SDL_MUSTLOCK(screen) ) {
        SDL_UnlockSurface(screen);
    }
    SDL_UpdateRect(screen, x, y, 1, 1);
}

inline int err() {
	cerr << SDL_GetError() << ''\n''; 
	exit(1);
}

class star {
private:
	int vx, vy; 
	int colour; 
	int dir;
	bool moving; 
	int x, y; 
public:
	star(int velx, int vely, int color, int direction,
			int xi, int yi) 
			: vx(velx), vy(vely), colour(color), dir(direction), 
			moving(false), x(xi), y(yi) {}
	
	void setv(int velx, int vely) { vx=velx; vy=vely; }
	void setd(int direction) { dir=direction; }
	void setx(int xx) { x=xx; }
	void sety(int yy) { y=yy; }
	void start() { moving=true; }
	void stop() { moving=false; }
	int getx() { return x; }
	int gety() { return y; }
	int getvx() { return vx; }
	int getvy() { return vy; }
}; 

vector<star*> stars; 
#define MAXSTARS 1

void draw_scene(SDL_Surface* screen) {
	if (stars.size()<MAXSTARS) {
		// Get random values for velocity and initial location. 

		int rvx=(rand()%5)+1; 
		int rvy=(rand()%5)+1; 
		int ry=(rand()%480)+1; 
		int rx=(rand()%640)+1; 
		cout << rvx << '' '' << rvy << '' '' << ry << '' '' << rx << endl; 
		stars.push_back(new star(rvx, rvy, 123, 0, rx, ry)); 
		stars[stars.size()-1]->start(); 
	}

	// Move the stars & check if any star is off-screen. 

	for (unsigned int i=0; i<stars.size(); ++i) {
		stars[i]->setx(stars[i]->getx()+stars[i]->getvx()); 
		if (stars[i]->getx() > 640) 
			stars[i]->setx(0); 
		
		// The actual drawing.

		SDL_LockSurface(screen); 
		DrawPixel(screen, 255, 255, 255, stars[i]->getx(), stars[i]->gety()); 
		SDL_UnlockSurface(screen); 
	//	cout << "Drew star(" << i << ") point at (" << stars-&gt;getx() &lt;&lt; ", " &lt;&lt; stars-&gt;gety() &lt;&lt; '')'' &lt;&lt; endl;
</font>
	}
}

<font color=blue>int</font> main(<font color=gray>/*if DEVC++, uncomment*/</font> <font color=gray>/*int argc, char** argv*/</font>) {
	srand(time(0)); 
	<font color=blue>if</font> (SDL_Init(SDL_INIT_VIDEO)&lt;0)
		<font color=blue>return</font> err(); 
	atexit(SDL_Quit); 
	SDL_WM_SetCaption(<font color=darkred>"S.T.A.R.S"</font>, 0); 

	const <font color=blue>int</font> SW=640; 
	const <font color=blue>int</font> SH=480; 
	const <font color=blue>int</font> SD=16; 
	SDL_Surface* screen=SDL_SetVideoMode(SW,SH,SD,SDL_HWSURFACE|SDL_DOUBLEBUF); 
	<font color=blue>if</font> (!screen) <font color=blue>return</font> err(); 

	<font color=blue>bool</font> gogogo=<font color=blue>true</font>; 
	SDL_Event event; 
	<font color=blue>while</font> (gogogo) {
		<font color=blue>while</font> (SDL_PollEvent(&event)) {
			<font color=blue>if</font> (SDL_QUIT==event.type) 
				gogogo=<font color=blue>false</font>; 		
			<font color=blue>else</font> <font color=blue>if</font> (SDL_KEYDOWN==event.type)
				<font color=blue>if</font> (SDLK_ESCAPE==event.key.keysym.sym)
					gogogo=<font color=blue>false</font>; 
		}
		
		<font color=gray>// Black out the screen for redrawing. 
</font>
		SDL_FillRect(screen,  0, SDL_MapRGB(screen-&gt;format, 0, 0, 0)); 
		<font color=gray>// Redraw screen. 
</font>
		draw_scene(screen); 
		SDL_Flip(screen); 
	}

	SDL_FreeSurface(screen); 
	<font color=blue>return</font> 0;
}
</pre><!–ENDSCRIPT–>
   
Advertisement
Do note that your eyes may register multiple stars if they move too fast. Take a screenshot and check if you see multiple stars. If you don''t, it''s an eye thing most likely. Try throwing in a Sleep(500) in your main loop to REALLY slow stuff down, and see if you still have duplicates.
hehe, yeah that was the first thing I thought. yes, I tried SDL_Delay(500), and it shows two stars.

Did you compile my code? if so, did it do the same thing?


hmm.. I took a screenshow and it's only one star. - but if I delay it to even 1000ms, it shows two stars. Also if I "freeze" the window it shows two stars, like if I hold left mouse on the title bar it freezes the main display and I see two stars.

When I lower the delay, I can like.. "see" it lag.. it looks like it chops, it would draw one star and draw the other but the first one gets overwritten very late.. that's what it looks like, like the star is dragging behind.


I wrote a smaller piece of code to try this out on.. and I took a screenshot of the desktop instead of using SDL_SaveBMP().. here:
http://wordbirdturd.tripod.com/glasses.jpg
#include <iostream>#include <fstream>#include <string>#include <vector>#include <cstdlib>#include <ctime>#include <SDL/SDL.h>using namespace std; #ifdef WIN32#pragma comment(lib, "SDL.lib")#pragma comment(lib, "SDLmain.lib")#endifvoid DrawPixel(SDL_Surface *screen, Uint8 R, Uint8 G, Uint8 B, int x, int y){    Uint32 color = SDL_MapRGB(screen->format, R, G, B);    if ( SDL_MUSTLOCK(screen) ) {        if ( SDL_LockSurface(screen) < 0 ) {            return;        }    }    switch (screen->format->BytesPerPixel) {        case 1: { /* Assuming 8-bpp */            Uint8 *bufp;            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;            *bufp = color;        }        break;        case 2: { /* Probably 15-bpp or 16-bpp */            Uint16 *bufp;            bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;            *bufp = color;        }        break;        case 3: { /* Slow 24-bpp mode, usually not used */            Uint8 *bufp;            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;            *(bufp+screen->format->Rshift/8) = R;            *(bufp+screen->format->Gshift/8) = G;            *(bufp+screen->format->Bshift/8) = B;        }        break;        case 4: { /* Probably 32-bpp */            Uint32 *bufp;            bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;            *bufp = color;        }        break;    }    if ( SDL_MUSTLOCK(screen) ) {        SDL_UnlockSurface(screen);    }    SDL_UpdateRect(screen, x, y, 1, 1);}inline int err() {	cerr << SDL_GetError() << '\n'; 	exit(1);}void draw_scene(SDL_Surface* screen) {	static int x; 	if (x>640) x=0; 	x+=5; 	SDL_LockSurface(screen); 	DrawPixel(screen, 255, 255, 255, x, 240); 	SDL_UnlockSurface(screen); }int main(/*if DEVC++, uncomment*/ /*int argc, char** argv*/) {	if (SDL_Init(SDL_INIT_VIDEO)<0) return err(); 	atexit(SDL_Quit); 	const int SW=640; 	const int SH=480; 	const int SD=16; 	SDL_Surface* screen=SDL_SetVideoMode(SW,SH,SD,SDL_HWSURFACE|SDL_DOUBLEBUF); 	if (!screen) return err(); 	bool gogogo=true; 	SDL_Event event; 	while (gogogo) {		while (SDL_PollEvent(&event)) {			if (SDL_QUIT==event.type) 				gogogo=false; 			else if (SDL_KEYDOWN==event.type)				if (SDLK_ESCAPE==event.key.keysym.sym)					gogogo=false; 				if (SDLK_F5==event.key.keysym.sym)					SDL_SaveBMP(screen, "doubletrouble.bmp"); 		}				SDL_FillRect(screen,  0, SDL_MapRGB(screen->format, 0, 0, 0)); 		draw_scene(screen); 		SDL_Flip(screen); 	}	SDL_FreeSurface(screen); 	return 0;}


[edited by - soundsystem on May 21, 2004 9:41:05 PM]
First of all, looking at your code, you''re locking the screen every pixel. BAD idea. This is VERY slow. Instead, you should lock before your loop and unlock afterwards. This isn''t just an optimization issue, it''s pretty much essential.

Second, it''s impossible to compile your code: you left out some vital stuff. Such as your star class.

Third, actually, you''re locking twice : in your loop and in your pixel plotting function. Why? >"<
I did not leave out the star class. It is in the first post, the last source I pasted is just a pixel moving right, it doesn't use the star class.

Ooops! - I just copied the function from somewhere, planned on studying it after I got this working. Updated it so now it only locks/unlocks outside the loop.

Unfortunately, no real difference.


I am starting to think it's my setup or something else external of the code.. I made this box that bounces from left to right, I can literally see it redrawing on each iteration.. here is the code:
#include <iostream>#include <string>#include <cstdlib>#include <ctime>#include <SDL/SDL.h>using namespace std; #ifdef WIN32#pragma comment(lib, "SDL.lib")#pragma comment(lib, "SDLmain.lib")#endifvoid DrawPixel(SDL_Surface *screen, Uint8 R, Uint8 G, Uint8 B, int x, int y){    Uint32 color = SDL_MapRGB(screen->format, R, G, B);    switch (screen->format->BytesPerPixel) {        case 1: { /* Assuming 8-bpp */            Uint8 *bufp;            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;            *bufp = color;        }        break;        case 2: { /* Probably 15-bpp or 16-bpp */            Uint16 *bufp;            bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;            *bufp = color;        }        break;        case 3: { /* Slow 24-bpp mode, usually not used */            Uint8 *bufp;            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;            *(bufp+screen->format->Rshift/8) = R;            *(bufp+screen->format->Gshift/8) = G;            *(bufp+screen->format->Bshift/8) = B;        }        break;        case 4: { /* Probably 32-bpp */            Uint32 *bufp;            bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;            *bufp = color;        }        break;    }    SDL_UpdateRect(screen, x, y, 1, 1);}inline int err() {	cerr << SDL_GetError() << '\n'; 	exit(1);}void DrawBox(SDL_Surface* screen, int side, Uint8 R, Uint8 G, Uint8 B, int x, int y) {	for (int row=0; row<side; ++row)		for (int k=0; k<side; ++k)			DrawPixel(screen, R, G, B, x+k, y+row);}void draw_scene(SDL_Surface* screen) {	static x,y=100; 	static bool MovingRight=true; 	if (MovingRight && (x+50)>=640) 		MovingRight=false; 	else if (!MovingRight && x<=0)		MovingRight=true; 	if (MovingRight) 		x+=10; 	else 		x-=10; 	SDL_LockSurface(screen); 	DrawBox(screen, 50, 255, 0, 0, x, y); 	SDL_UnlockSurface(screen); }int main(/*if DEVC++, uncomment*/ /*int argc, char** argv*/) {	srand(time(0)); 	if (SDL_Init(SDL_INIT_VIDEO)<0)		return err(); 	atexit(SDL_Quit); 	const int SW=640; 	const int SH=480; 	const int SD=16; 	SDL_Surface* screen=SDL_SetVideoMode(SW,SH,SD,SDL_HWSURFACE|SDL_DOUBLEBUF); 	if (!screen) return err(); 	bool gogogo=true; 	SDL_Event event; 	while (gogogo) {		while (SDL_PollEvent(&event)) {			if (SDL_QUIT==event.type) 				gogogo=false; 			else if (SDL_KEYDOWN==event.type)				if (SDLK_ESCAPE==event.key.keysym.sym)					gogogo=false; 				if (SDLK_F5==event.key.keysym.sym)					SDL_SaveBMP(screen, "doubletrouble.bmp"); 		}				// Black out the screen for redrawing. 		SDL_FillRect(screen,  0, SDL_MapRGB(screen->format, 0, 0, 0)); 		// Redraw screen. 		draw_scene(screen); 		SDL_Flip(screen); 		SDL_Delay(10); 	}	SDL_FreeSurface(screen); 	return 0;}



[edited by - soundsystem on May 21, 2004 12:04:13 AM]
Agh, I can''t believe I missed this! You tipped me off with "I can see it being redrawn."

SDL_UpdateRect updates the rectangle specified. Obviously, if called after every pixel, you''ll see them being updated one by one. Remove it. You don''t want it. You''re already flipping your surfaces, so why update the screen after every pixel is drawn too?
It worked, thanks.

This topic is closed to new replies.

Advertisement