Scrolling 2D Image problem

Dear JGO Members,

I’m having this weird problem when doing side scrolling at a fast speed, the rectangles drew with g.fillRec() start to have some sort of silhouette and images flashes, I have tried to use variable framerate game loop or increase fps in the fixed framerate loop but neither works. The following is an attempt to demonstrate the problem:

Flashing when moving 1


Flashing when moving 2

Picture to show where the silhouette is when scrolling:

http://img340.imageshack.us/img340/553/text3616.png

Uploaded with ImageShack.us

I’m not exactly sure what the cause of the problem is since it looks fine if I scroll at slower speed, I’m guess the problem has to do with the game loop I’m using, note that I want to have a fixed framerate game loop. Below is the code of the loop, thanks in advance!

The loop is taken from here:
Fixed Framerate loop
http://wiki.games4j.com/wiki/en/Timing_in_main_loops


        private int fps;
	private long timeThen;

	/** Set FPS */
	private void setFPS() {
		fps = 60;
		timeThen = System.nanoTime();
	}

        /** Timer */
	public void sync() {
		long gapTo = 1000000000L / fps + timeThen;
		long timeNow = System.nanoTime();
		
		while (gapTo > timeNow) {
			try { Thread.sleep(1);
			} catch (InterruptedException e) {}
			timeNow = System.nanoTime();
		}
		timeThen = timeNow;
	}


       /** Fixed Framerate Game loop */
	private void gameLoop() {
		long currentUpdateTime = System.nanoTime();
		long lastUpdateTime;	
			
		while(gameRunning) {
			
			lastUpdateTime = currentUpdateTime;
			currentUpdateTime = System.nanoTime();
			long elapsedTime = (currentUpdateTime -    lastUpdateTime)/(1000*1000);
			
			/** Update Game */
			gameUpdate(elapsedTime);
			/** Render */
			gameRender();
			/** Run timer */
			sync();
		}
	}

So what does gameRender() look like? Further, you really want to either paint on the component from the EDT, or paint to an offscreen image, and blit that to the Canvas from the EDT. Either way, do not grab the Graphics object from a component to start drawing from a ‘random’ thread. Having said that, I never saw a silhouette like that before.

Hey Riven,

Thanks for the fast reply, this is what the gameRender() looks like, sorry but what is EDT?


	GameCore() {
		Frame frame = new Frame("Side Scroller");
		frame.setLayout(null);
		setBounds(0,0,WINDOWS_WIDTH,WINDOWS_HEIGHT);
		frame.add(this);
		frame.setSize(WINDOWS_WIDTH,WINDOWS_HEIGHT);
		frame.setResizable(false);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		frame.addKeyListener(this);
		addKeyListener(this);
		//Exit windows
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		

		/** create the strategy used for accelerated rendering. */ 
		createBufferStrategy(2);
		strategy = getBufferStrategy();

                 //Other code here
   		
		setFPS();
		gameLoop();
	}


private void gameRender() {
		Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
		
		// clear the screen
		g.setColor(Color.WHITE);
		g.fillRect(0,0,WINDOWS_WIDTH,WINDOWS_HEIGHT);
		g.translate(0, 10);

		if(player.isAlive() && gameStart) {
			/** Paint map */
			map.paint(g);
			
			/** Paint enemies */
			spawn.paint(g);
			
			/** Pain Power Ups */
			powerUp.paint(g);
			
			/** Paint player */
			player.paint(g);
			
			/** Paint GUI */
			gui.paint(g);
		}

		/** Paint Scene */
		scene.paint(g);
		
		/** flip the buffer so we can see the rendering */
		g.dispose();
		strategy.show();
	}

Edit: I’m trying to keep the game single threaded to keep it as simple as possible. I’m not very good with multi-threading yet.

Edit 2: The silhouette only happens on the g.fillRect() Rectangles, the images don’t have that effect and it only happens when I’m scrolling.

Edit 3: The paint(g) code is something like this:


	/** Draw Player */
	public void paint(Graphics2D g) {
		/** Paint spells */
		for(int i = spellList.size() - 1; i >= 0 ; i--) {
				spellList.get(i).paint(g);
		}
			
		/** Paint explosions */
		for(int i = explosion.size() - 1; i >= 0; i--) {
			if(explosion.get(i).Length() != 0) {
				explosion.get(i).paint(g);
			}
		}

		g.drawImage(anim.getCurrentImage(), xp + offsetX - 10, yp + offsetY, null);
	}

double posted by accident…

Put a panel in your frame (and set layout null) then put a canvas in that panel and setIgnoreRepaint(true) and have the canvas createBufferStrategy(2) and then request focus.
That solved all flickering issues I’ve had.

Thanks for the reply! I’ll try that when I get home. I’m not using any swing components tho will that be fine?

EDIT: I found the problem, it has nothing to do with the game loop at all, there’s something wrong with my scrolling offset, I’ll try and fix it now. Thanks for the help!

I tried the method adon_y_coya suggested but the flickering is still there =/. I’m just curious, what are the possible causes that could cause flickering in java?

Here’s the code for my frame:


Frame frame = new Frame("Stone of Franks");
		Panel panel = new Panel();
		panel.setLayout(null);
		
		Canvas canvas = new Canvas();
		canvas.setBounds(0,0,WINDOWS_WIDTH,WINDOWS_HEIGHT);
		canvas.setIgnoreRepaint(true);
		
		panel.add(canvas);
		frame.add(panel);

		frame.setSize(WINDOWS_WIDTH,WINDOWS_HEIGHT);
		frame.setResizable(false);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		
		/** create the strategy used for accelerated rendering. */ 
		canvas.createBufferStrategy(2);
		strategy = canvas.getBufferStrategy();
		
		canvas.requestFocus();
		
		//Exit windows
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});


	      /** Add Key Listener */
		canvas.addKeyListener(this);
		
		/** Add Mouse Listener */
		canvas.addMouseListener(this);
		canvas.addMouseMotionListener(this);

im trying something similar and I think what we need is a way to do vsync, I asked for that in other post, I hope someone give an answer. 8)

Does vsync get rid of flickering? I’m using double buffering and I still get flickering. It would be really nice if someone can show me how to do scrolling properly, perhaps my way of doing it is just wrong. The way I scroll is to have screen follow this "camera(an invisible rectangle) and when I move mouse to the left/right edges of the screen it increments/decrements the X position of the camera and as an end result the map scrolls.

I noticed in my games when ever I scroll right my character “shifts back” a little bit when he’s near the edge, perhaps this will lead to the root cause of my weird flickering bug.

Edit: I tried it, still doesn’t get rid of flickering and I’m not sure whats wrong with my scrolling code.

Here’s how I do scrolling in case anyone’s interested:
I have 2 variables to tell where the camera is at now, lets forget about Y for now since I’m only doing horizontal scrolling. VisibleX is declared as public static int visibleX = GameCore.WINDOWS_WIDTH / (8 * Map.TILE_SIZE);

Where WINDOWS_WIDTH is 1024(my screen width);
and camera.x is camera’s current position.

Cornershift is just to shift edges according to player’s position so that things outside of the actual map won’t be seen.


mapPosX = Camera.visibleX - Camera.x;
mapPosY = Camera.visibleY - Camera.y;
cornerShift();

Then this is how I calculate the offset to be used for all scrolling


/** Offset X for Camera */
int offsetX = (int)((GameCore.mapPosX + GameCore.fixX)* Map.TILE_SIZE);

/** Offset Y for Camera */
int offsetY = (int)((GameCore.mapPosY + GameCore.fixY) * Map.TILE_SIZE);

// Somewhere in paint method I draw the rectangle with the offset
g.drawRect(xp + offsetX, yp + offsetY, width, height);

I’ve tried all sorts of game loop today, tried running the game in full screen/windowed application as well and different methods posted on forum to get rid of flickering. I can’t really find any bugs/flaws in my scrolling method and none of the methods I tried work so far, any help would be greatly appreciated.

I think I got rid of flickering, can someone please be kind enough to check if you still get flickering when scrolling from my game? For some reason making it full screen seems to do the trick…I have no idea why…

Link to code, the zip file contains 3 jars, just different way of doing things:
http://www.mediafire.com/?mndtjmninzt

Here’s the code highlight for each jar, note that my screen has a resolution of 1024 * 768, scrolling is done by moving mouse to left/right edge of the screen:

  • Sof_FS.jar is the first full screen method I tried

  GraphicsDevice gd;

		  GraphicsEnvironment ge = 
		        GraphicsEnvironment.getLocalGraphicsEnvironment();
		    gd = ge.getDefaultScreenDevice();
		    GraphicsConfiguration gc = gd.getDefaultConfiguration();

			final int currentRefreshrate = gd.getDisplayMode().getRefreshRate();
			
			System.out.println("Reported Refreshrate=" + currentRefreshrate);
			targetFps = (currentRefreshrate==DisplayMode.REFRESH_RATE_UNKNOWN?60:currentRefreshrate);
				
		Frame frame = new Frame(gc);
		frame.setIgnoreRepaint(true);
		frame.setUndecorated( true );
		frame.setLayout(null);
		setIgnoreRepaint(true);
		setBounds(0,0,WINDOWS_WIDTH,WINDOWS_HEIGHT);
		frame.add(this);
		frame.setSize(WINDOWS_WIDTH,WINDOWS_HEIGHT);
		frame.setFocusTraversalKeysEnabled(false);
		frame.setResizable(false);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		
	    // Change to full screen
	    gd.setFullScreenWindow(frame);
	    if( gd.isDisplayChangeSupported() ) {
	      gd.setDisplayMode( 
	        new DisplayMode( WINDOWS_WIDTH, WINDOWS_HEIGHT, 32, DisplayMode.REFRESH_RATE_UNKNOWN )
	      );
	    }


  • Sof_FS2.jar is the second full screen method I tried:

                Frame frame = new Frame("Test Scroller");
		frame.setLayout(null);
		setBounds(0,0,WINDOWS_WIDTH,WINDOWS_HEIGHT);
		frame.add(this);
		frame.setSize(WINDOWS_WIDTH,WINDOWS_HEIGHT);
		frame.setResizable(false);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		
//		Exit windows
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		
		/** create the strategy used for accelerated rendering. */ 
		createBufferStrategy(2);
		strategy = getBufferStrategy();

            //I simply added these 2 lines to the original code
	    GraphicsEnvironment.getLocalGraphicsEnvironment().
            getDefaultScreenDevice().setFullScreenWindow(frame);

  • SoF.jar, the non-full screen mode:

Frame frame = new Frame("Side Scroller");
		frame.setLayout(null);
		setBounds(0,0,WINDOWS_WIDTH,WINDOWS_HEIGHT);
		frame.add(this);
		frame.setSize(WINDOWS_WIDTH,WINDOWS_HEIGHT);
		frame.setResizable(false);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		
//		Exit windows
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		
		/** create the strategy used for accelerated rendering. */ 
		createBufferStrategy(2);
		strategy = getBufferStrategy();