Strange behaviour using j2d

I was making a 4k game when i noticed some strange stuff happening when i played it. It is very strange on j2sdk1.4.2_06 but works fine in jre1.5.0_04.

Here is the code:



import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;

public class AstroPilot extends Canvas {
		
	private final boolean[] k = new boolean[600];
	
	public AstroPilot(){
		
		setSize(500, 350);    	
   		JFrame f = new JFrame();
		f.getContentPane().add(this);
		f.setResizable(false);
		f.pack();
		f.setLocationRelativeTo(null);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.show();
		
  		enableEvents(AWTEvent.KEY_EVENT_MASK);
    	requestFocusInWindow();
        	
       	Image buffer = createImage(500, 350);
       	Graphics2D g = (Graphics2D) buffer.getGraphics();
       	g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		final float halfPI = (float) Math.PI/2;
		  	
		final int resolution = 128;
		final float averageHeight = 80;
		final double range = 5;
		final float falloff = 3;
		//gen map
		float[] heights = new float[resolution];
		//init all to average height + rnd
		for(int i=0; i<resolution; i++){
			heights[i] = averageHeight + (float)(Math.random()*range);
		}
		
		//planet stuff
		final int planetX = 200, planetY = 150;
		final float planetGravity = 0.01f;
		
		Polygon planet = new Polygon();
		//smooth heights
		for(int i=0; i<heights.length; i++){
			int prev = (i-1) % resolution;
			if(prev < 0) prev = resolution-1;
			int next = (i+1) % resolution;
			//
			heights[i] = (heights[i] + heights[prev] + heights[next])/3;
			planet.addPoint(planetX + (int)(heights[i] * Math.cos(((halfPI*4)/resolution) * i)),
						planetY + (int)(heights[i] * Math.sin(((halfPI*4)/resolution) * i)));
		}
		
		//ship stuff
		float shipX=350, shipY=150, shipVelX = 0, shipVelY = 0, shipRot = 0, shipRotVel=0;
		final float shipThrustAccel = 0.08f;
		final float shipRotAccel = 0.004f;
		final float shipCollisionSquare = 10;
		boolean shipAlive = true;
		
		//particle stuff
		final int numParticles = 128;
		final float maxParticleLife = 120;
		final float minParticleLife = 20;		
		//dim 1 = each particle
		//dim 2: x, y, velx, vely, life(if 0 then not alive)
		float[][] particles = new float[numParticles][5];		
		int particleCounter = 0;
		
			
    	//create the bg
    	Image backGround = createImage(500, 350);
	 	Graphics2D bgGFX = (Graphics2D) backGround.getGraphics();
	   	bgGFX.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		bgGFX.setPaint(new GradientPaint(0, 0, Color.black, 0, 350, Color.blue.darker()));		g.fillRect(0, 0, getSize().width, getSize().height);
		bgGFX.fillRect(0, 0, 550, 350);
		bgGFX.setColor(Color.green);
		bgGFX.fill(planet);
			
		//loop
		do{
			
			/**
			 *gamelogic
			 */
			
			if(k[KeyEvent.VK_LEFT]){
				shipRotVel -= shipRotAccel;				
				particleCounter = ++particleCounter % numParticles;
				particles[particleCounter][0] = shipX;
				particles[particleCounter][1] = shipY;
				particles[particleCounter][2] = shipVelX + (float) (Math.cos(shipRot) + (Math.random()*0.2));
				particles[particleCounter][3] = shipVelY + (float) (Math.sin(shipRot) + (Math.random()*0.2));
				particles[particleCounter][4] = minParticleLife + (float) Math.random()*(maxParticleLife-minParticleLife);		
			}
			if(k[KeyEvent.VK_RIGHT]){
				shipRotVel += shipRotAccel;
				particleCounter = ++particleCounter % numParticles;
				particles[particleCounter][0] = shipX;
				particles[particleCounter][1] = shipY;
				particles[particleCounter][2] = shipVelX + (float) (Math.cos(shipRot-2*halfPI) + (Math.random()*0.2));
				particles[particleCounter][3] = shipVelY + (float) (Math.sin(shipRot-2*halfPI) + (Math.random()*0.2));
				particles[particleCounter][4] = minParticleLife + (float) Math.random()*(maxParticleLife-minParticleLife);	
			}			
			if(k[KeyEvent.VK_UP]){
				shipVelX += (float) (shipThrustAccel*Math.cos(shipRot-halfPI));
				shipVelY += (float) (shipThrustAccel*Math.sin(shipRot-halfPI));
				
				particleCounter = ++particleCounter % numParticles;
				particles[particleCounter][0] = shipX;
				particles[particleCounter][1] = shipY;
				particles[particleCounter][2] = shipVelX + (float) (Math.cos(shipRot+halfPI) + (Math.random()*0.2));
				particles[particleCounter][3] = shipVelY + (float) (Math.sin(shipRot+halfPI) + (Math.random()*0.2));
				particles[particleCounter][4] = minParticleLife + (float) Math.random()*(maxParticleLife-minParticleLife);
			}
			
			//gravity
			float distsq = (shipX-planetX)*(shipX-planetX) + (shipY-planetY)*(shipY-planetY);
			float dx = shipX-planetX;
			float dy = shipY-planetY;
			dx = dx / (float)Math.sqrt(distsq);
			dy = dy / (float)Math.sqrt(distsq);
			shipVelX -= planetGravity * dx;
			shipVelY -= planetGravity * dy;
			
			//update ship
			if(shipAlive && !planet.intersects(shipX+shipVelX, shipY+shipVelY, shipCollisionSquare, shipCollisionSquare)){
				shipRot += shipRotVel;
				shipX += shipVelX;
				shipY += shipVelY;
			}
			//die!
			else if(shipAlive){
				shipAlive = false;
				for(int i=0; i<128; i++){
					particleCounter = ++particleCounter % numParticles;
					particles[particleCounter][0] = shipX;
					particles[particleCounter][1] = shipY;
					particles[particleCounter][2] = 1-(float)(Math.random()*2);
					particles[particleCounter][3] = 1-(float)(Math.random()*2);
					particles[particleCounter][4] = minParticleLife + (float) Math.random()*(maxParticleLife-minParticleLife);
				}
			}
			
			//update particles
			for(int i=0; i<numParticles; i++){
				particles[i][0] += particles[i][2];
				particles[i][1] += particles[i][3];				
				particles[i][4]--; 
			}
			
			/**
			 *painting
			 */
		
			//uncomment this to get a different strange effect	
		//	g.clearRect(0, 0, 999, 999);
			
			g.drawImage(backGround, 0, 0, null);
			
			g.setColor(Color.white);
			
			//draw the ship
			if(shipAlive){
			
				g.translate(shipX, shipY);
				g.rotate(shipRot);
				
				g.drawOval(-5, -10, 10, 10);
				g.drawRect(-2, -1, 4, 4);
				g.drawLine(-7, 6, -5, -5);
				g.drawLine(7, 6, 5, -5);
				g.drawLine(-7, 6, -2, 2);
				g.drawLine(7, 6, 2, 2);
				
				g.rotate(-shipRot);
				g.translate(-shipX, -shipY);
				
			}
				
			//draw particles
			for(int i=0; i<numParticles; i++){
				if(particles[i][4] > 0){	//if particle is alive
					g.drawLine(
						(int)particles[i][0], (int)particles[i][1],
						(int)particles[i][0], (int)particles[i][1]);
				}
			}
			
			
			getGraphics().drawImage(buffer, 0, 0, null);
			
			try{ Thread.sleep(1000/28); }catch(Exception e){}
			
		}while(true);
	}
	
	
	public void processKeyEvent(KeyEvent e){
     	if(e.getID() == KeyEvent.KEY_PRESSED)
    		k[e.getKeyCode()] = true;
    	if(e.getID() == KeyEvent.KEY_RELEASED)
    		k[e.getKeyCode()] = false;
    	if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
    		System.exit(0);
	}
	
	
	public static void main(String[] args){
		new AstroPilot();
	}
}

and the two pictures are attchted(top one with the strange behaviour)

One thing I notice:


public class X extends Canvas
{
   public X()
   {
       ...
       getGraphics().drawImage(buffer, 0, 0, null);
       ...
   }
}

This is not the way it’s meant to be. It might work, yes, but you’re supposed to override paint(g) and draw from there.

Just give it a try, maybe this will solve your rendering errors. Who knows. :slight_smile:

i’d use bufferstrategy to get the drawgraphics if you are using canvas, i have not compared, but you are trading the overhead of creating a new method for a call (or two) to createbufferstrategy() + getbufferstrategy().getdrawgraphics(), so you can use that graphics and then call getbufferstrategy().show() from wherever you want :slight_smile: