Canvas setting background Image for games/Other Canvas<Solved>

Good point.

Well, to be honest, i’ve never used levels and level switching like that, however i know it works well for game states. But for an average turn-based, 2D rpg i suspect that it will be more than adequate, and also from what i saw in your video. The trick i think is to do what you think best and what you want to do, then if you do run into probems, learn from them and properly fix things up (eg. redesign).

@Above thanks, gotcha =). Also another question for you you guys, I got my canvas working and everything seems fine tri buffering and my delta time is great but it seems when I go from 60fps to 100 fps animations go a bit too fast, why is this? Why are they moving too fast and not synchronized well, what is the best way to combat this I thought delta time was supposed to do so?

Do you multiply everything by delta time each time through the update process?

 long desiredFPS =100;
   long desiredDeltaLoop = (1000*1000*1000)/desiredFPS;
    
   boolean running = true;
   
   public void run(){
      
      long beginLoopTime;
      long endLoopTime;
      long currentUpdateTime = System.nanoTime();
      long lastUpdateTime;
      long deltaLoop;
      
      while(running){
         beginLoopTime = System.nanoTime();
         
         render();
         
         lastUpdateTime = currentUpdateTime;
         currentUpdateTime = System.nanoTime();
         update((int) ((currentUpdateTime - lastUpdateTime)/(1000*1000)));
         
         endLoopTime = System.nanoTime();
         deltaLoop = endLoopTime - beginLoopTime;
           
           if(deltaLoop > desiredDeltaLoop){
               //Do nothing. We are already late.
           }else{
               try{
                   Thread.sleep((desiredDeltaLoop - deltaLoop)/(1000*1000));
               }catch(InterruptedException e){
                   //Do nothing
               }
           }
      }
   }
protected void update(int deltaTime){
      //b3.setDelta(deltaTime);
	   b3.update(deltaTime);
   System.out.println(deltaTime);
   }

Then I take delta pass it through update which is then passed through set delta method to my board class b3.update(delta time) that is then passed through for other methods dealing with time such as animations and movement. Or is that incorrect? The other methods in the board class such as playerSprite.setTime(takes in delta from the board class) and then looks over that time and checks if seconds go by or minutes to do game updates based on the overall delta time of the main games time.

Example of MonsterSprites methods dealing with delta time.

public void setTick(int delta) {//Time is money..
		tick += delta;
		mainTime += delta;
		aniTime += delta;
		aniTime2+=delta;
		// System.out.println(tick);
		
		if (tick >= 500) {
			mainSpriteTick++;
       	//  fx1tick++;
			//counterTick2++;
			// System.out.println(mainSpriteTick);
			tick = 0;

		}
}

When I set it to 100fps as opposed to60fps at 100 fps things seem to move slightly faster than they should like 3 frames tick for monster movement looks like 5-6 at 100fps+.

Isn’t this correct? What am I doing wrong??? It appears that my game Logic is faster than it should or should I not even worry about 100fps as long as 60fps stays the same? I was before just using timer every 14ms to update an action preformed method to do update logic and repaint(), found this loop on the forums and it seems much better although, can someone please explain how to sync game logic properly?
Thanks

I would say that 60fps is an ample frame rate for any game. Most monitors have a refresh rate of 60Hz anyway and using more can just be overkill i think.

Is my logic correct? Such as accumulating delta time and updating stuff w.e time I want like 500ms? And where should I be multiplying delta?
For example In my setTick Method in my monster Sprite class for my main sprite movement it updates every 500ms.

public void setTick(int delta) {//
      tick += delta;
      mainTime += delta;
      aniTime += delta;
      aniTime2+=delta;
      // System.out.println(tick);
      
      if (tick >= 500) {
         mainSpriteTick++;
          //  fx1tick++;
         //counterTick2++;
         // System.out.println(mainSpriteTick);
         tick = 0;

      }

The way i’ve done it is multiplying movement by delta.
eg.


xPos += (xVel * delta);

So for xVelocity I want my sprite to move 3pixels but with a delta time of 14ms I’d be moving at 42pixels per second?

How can I make sure I just move x pixles perSecond? This is in regards of a simple RPG. Btw I should be using delta time for keeping track of ALL time right? Or am I confused with the purpose of delta time?

xVel would be how many pixels per second you want.
delta would be the number of milliseconds or nanoseconds passed divided by 1000 (for milliseconds) or 1e9 (for nanoseconds).

Ok so…

if
xVel= 3;
delta = 14/1000 = .014
xPos += (xVel * delta);

?

And you’re saying this should sync things further?..

Also am I understanding Delta? such as in a board class passing through delta to other classes where I can control time such as adding counters to delta and then testing time such as delta being passed into my sprite class’s setTick method? This is really the only thing I don’t seem to understand in game design…other wise I feel that i’m ready to move on with my game, but as of now this is the only problem i’m having with graphics and time updating.



//MOnster sprite set tick method keeps control time to add to loops which add or subtract movement and update logic
public void setTick(int delta) {
      tick += delta; Main sprite tick for movement
      mainTime += delta;//Control of time for seconds and minutes
      aniTime += delta;//Animation time 1 
      aniTime2+=delta;//Animation time 2
      // System.out.println(tick);
      
      if (tick >= 500) {
         mainSpriteTick++;
          //  fx1tick++;
         //counterTick2++;
         // System.out.println(mainSpriteTick);
         tick = 0;

      }
}

Yeah, you basically just keep time for each animation frame. However, it’s best to organize this into a more OO way. Check out my Animation class.

So yes we do keep track of time by adding deltas MS/ns to a counter right?
Also ,from what i’ve said before about upping fps for delta and objects moving too fast, is it because logic is going too fast? I thought delta time was supposed to take care of this fully?

Increasing the FPS should decrease the deltaTime value, which should keep the movement speed the same.

Doesn’t seem to do so though the higher Increase the FPS the faster objects are moving XD.

Also from switching from my JPanel setup/non delta gameloop to this and canvas I’ve noticed some choppiness not sure why…performance hasn’t gone up, I must’ve fked something up…

Main game Loop from the tutorials section that i’m using until I make my own/master delta time and canvas


import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class Game implements Runnable{
   
   final int WIDTH = 1366;
   final int HEIGHT = 768;
   //
   BufferedImageLoader BuffLoad = new BufferedImageLoader();
	BufferedImage sprite_sheet = null;
	BufferedImage sprite;
	Image image;
	ImageIcon ii ;
	public Image bg;
	public Board3 b3;  
   //
	SonageArenaFrame SAF;
	JFrame frame;
   Canvas canvas;
   BufferStrategy bufferStrategy;
   
   public Game(){
		
		
	   frame= new JFrame("DemoCanvas");
	  //. frame = new JFrame("Demo Canvas");
      b3= new Board3();
      
      frame.add(SAF.p, "South");
     JPanel panel = (JPanel) frame.getContentPane();
     
      panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
      panel.setLayout(null);
      
      canvas = new Canvas();
      canvas.addKeyListener(new TAdapter());
      canvas.setBounds(0, 0, WIDTH, HEIGHT);
      canvas.setIgnoreRepaint(true);
      
      panel.add(canvas);
      
      canvas.addMouseListener(new MouseControl());
      
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setResizable(true);
      frame.setVisible(true);
      try {
			bg = javax.imageio.ImageIO.read(new java.net.URL(getClass()
					.getResource("/Trees!.png"), "Trees!.png"));
		} catch (Exception eee) {
			System.out.println(eee.toString());
		}
      
      
	   ii =
		        new ImageIcon(this.getClass().getResource("/FireFlame.png"));
      
      try {
			sprite_sheet = BuffLoad.loadImage("/PetSword2.png");
		} catch (IOException IEE) {
		}
		//ss = new SpriteSheet(sprite_sheet);
      
      
      canvas.createBufferStrategy(3);
      bufferStrategy = canvas.getBufferStrategy();
      
      canvas.requestFocus();
   }
   
        
   private class MouseControl extends MouseAdapter{
      
   }
   
   long desiredFPS =60;
   long desiredDeltaLoop = (1000*1000*1000)/desiredFPS;
    
   boolean running = true;
   
   public void run(){
      
      long beginLoopTime;
      long endLoopTime;
      long currentUpdateTime = System.nanoTime();
      long lastUpdateTime;
      long deltaLoop;
      
      while(running){
         beginLoopTime = System.nanoTime();
         
         render();
         
         lastUpdateTime = currentUpdateTime;
         currentUpdateTime = System.nanoTime();
         update((int) ((currentUpdateTime - lastUpdateTime)/(1000*1000)));
         
         endLoopTime = System.nanoTime();
         deltaLoop = endLoopTime - beginLoopTime;
           
           if(deltaLoop > desiredDeltaLoop){
               //Do nothing. We are already late.
           }else{
               try{
                   Thread.sleep((desiredDeltaLoop - deltaLoop)/(1000*1000));
               }catch(InterruptedException e){
                   //Do nothing
               }
           }
      }
   }
   
   private void render() {
      Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
      g.clearRect(0, 0, WIDTH, HEIGHT);
      render(g);
      g.dispose();
      bufferStrategy.show();
   }
   
   //TESTING
   
   /**
    * Rewrite this method for your game
    */
   protected void update(int deltaTime){
      
	   //b3.setDelta(deltaTime);
	   
	   b3.update(deltaTime);
   System.out.println(deltaTime);
   }
  
   /**
    * Rewrite this method for your game
    */
   protected void render(Graphics2D g){
	 
	 b3.paint(g);
   }
   private class TAdapter extends KeyAdapter {

		public void keyReleased(KeyEvent e) {
			b3.playerSprite.keyReleased(e);
		}

		public void keyPressed(KeyEvent e) {
			b3.playerSprite.keyPressed(e);
		}
	}
   public static void main(String [] args){
      Game ex = new Game();
      new Thread(ex).start();
   }
   
}

It looks fine, but I wonder why you send a millisecond to the update method. You also have a time leak in there.

EDIT: Oh and you are supposed to be using BufferStrategy in a certain way. Refer to code :slight_smile:

Consider this loop:


public void gameLoop() {
    final long DESIRED_LOOP = Math.round(1e9 / FPS);
    
    long lastTime = System.nanoTime();
    
    while(true) {
        long deltaTime = System.nanoTime() - lastTime;
        lastTime += deltaTime;
        
        update(deltaTime);
        
        render();
        
        long sleepTime = Math.round((DESIRED_LOOP)-(System.nanoTime()-lastTime));
        if(sleepTime <= 0)
            continue;
        
        long prevTime = System.nanoTime();
        while(System.nanoTime()-prevTime <= sleepTime) {
            if(System.nanoTime()-prevTime <= sleepTime * 0.9)
                Thread.sleep(1);
            else
                Thread.yield();
        }
    }
}

public void render() {
    do{
        do{
            Graphics2D g = (Graphics2D)strategy.getDrawGraphics();
            
            b3.paint(g);
            
            g.dispose();
        }while(strategy.contentsRestored());
        
        strategy.show();
    }while(strategy.contentsLost());
}

First off are you giving me permission to use that game loop in my game? Second I pasted the code in Eclipse to try it out and it’s saying I need try/catch block XD might want to edit that.

EDIT: Gotcha[quote]EDIT: Oh and you are supposed to be using BufferStrategy in a certain way. Refer to code Smiley
[/quote]
Also I tried out everthing and am getting very weird resutls flashing screen and such.





import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class Game implements Runnable{
   
   final int WIDTH = 1366;
   final int HEIGHT = 768;
   //
   BufferedImageLoader BuffLoad = new BufferedImageLoader();
	BufferedImage sprite_sheet = null;
	BufferedImage sprite;
	Image image;
	ImageIcon ii ;
	public Image bg;
	public Board3 b3;  
   //
	SonageArenaFrame SAF;
	JFrame frame;
   Canvas canvas;
   BufferStrategy bufferStrategy;
   
   public Game(){
		
		
	   frame= new JFrame("DemoCanvas");
	  //. frame = new JFrame("Demo Canvas");
      b3= new Board3();
      
      frame.add(SAF.p, "South");
     JPanel panel = (JPanel) frame.getContentPane();
     
      panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
      panel.setLayout(null);
      
      canvas = new Canvas();
      canvas.addKeyListener(new TAdapter());
      canvas.setBounds(0, 0, WIDTH, HEIGHT);
      canvas.setIgnoreRepaint(true);
      
      panel.add(canvas);
      
      canvas.addMouseListener(new MouseControl());
      
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setResizable(true);
      frame.setVisible(true);
      try {
			bg = javax.imageio.ImageIO.read(new java.net.URL(getClass()
					.getResource("/Trees!.png"), "Trees!.png"));
		} catch (Exception eee) {
			System.out.println(eee.toString());
		}
      
      
	   ii =
		        new ImageIcon(this.getClass().getResource("/FireFlame.png"));
      
      try {
			sprite_sheet = BuffLoad.loadImage("/PetSword2.png");
		} catch (IOException IEE) {
		}
		//ss = new SpriteSheet(sprite_sheet);
      
      
      canvas.createBufferStrategy(3);
      bufferStrategy = canvas.getBufferStrategy();
      
      canvas.requestFocus();
   }
   
        
   private class MouseControl extends MouseAdapter{
      
   }
   
   long desiredFPS =60;
  
    
   boolean running = true;
   
   public void run() {
	    final long DESIRED_LOOP = Math.round(1e9 / desiredFPS);
	    
	    long lastTime = System.nanoTime();
	    
	    while(true) {
	        long deltaTime = System.nanoTime() - lastTime;
	        lastTime += deltaTime;
	        
	        update(deltaTime);
	        
	        render();
	        
	        long sleepTime = Math.round((DESIRED_LOOP)-(System.nanoTime()-lastTime));
	        if(sleepTime <= 0)
	            continue;
	        
	        long prevTime = System.nanoTime();
	        while(System.nanoTime()-prevTime <= sleepTime) {
	            if(System.nanoTime()-prevTime <= sleepTime * 0.9)
					try {
						Thread.sleep(1);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				else
	                Thread.yield();
	        }
	    }
	}
   
   public void render() {
	    do{
	        do{
	            Graphics2D g = (Graphics2D)bufferStrategy.getDrawGraphics();
	            
	            b3.paint(g);
	            
	            g.dispose();
	        }while(bufferStrategy.contentsRestored());
	        
	        bufferStrategy.show();
	    }while(bufferStrategy.contentsLost());
	}
   
   //TESTING
   
   /**
    * Rewrite this method for your game
    */
   protected void update(long deltaTime){
      
	   //b3.setDelta(deltaTime);
	   
	   b3.update((int)deltaTime);
   System.out.println(deltaTime);
   }
  
   /**
    * Rewrite this method for your game
    */
   protected void render(Graphics2D g){
	 
	 b3.paint(g);
   }
   private class TAdapter extends KeyAdapter {

		public void keyReleased(KeyEvent e) {
			b3.playerSprite.keyReleased(e);
		}

		public void keyPressed(KeyEvent e) {
			b3.playerSprite.keyPressed(e);
		}
	}
   public static void main(String [] args){
      Game ex = new Game();
      new Thread(ex).start();
   }
   
}

Oh yeah Thread.sleep(1) needs try-catch XD

1 million nanos is 1 millisecond :wink:

To get delta, divide deltaTime by 1e9.

This is correct right?

  protected void update(long deltaTime){
      
	   //b3.setDelta(deltaTime);
	   
	   b3.update((int)((deltaTime/1e9)*1000));
   
   }

Also can you explain exactly what is going on here?

The render that you gave me.

public void render() {
       do{
           do{
               Graphics2D g = (Graphics2D)bufferStrategy.getDrawGraphics();
               
               b3.paint(g);
               
               g.dispose();
           }while(bufferStrategy.contentsRestored());
           
           bufferStrategy.show();
       }while(bufferStrategy.contentsLost());
   }

Ok everything is ALOT smoother, although Images are now somewhat jittery. Is there something that I don’t have here that is making it do so?

is this paint method correct? Do I need to add any thing, no disposing no super.paint right? the main game class will handle that in the render loop right?

public void paint(Graphics2D g) {
		//super.paint(g);
        
		// Rectangle r = new Rectangle(playerSprite.getX() - 5, playerSprite.getY() - 40, 70, 10);
		
		
		
		g.drawImage(bg, 0, 0, this);
		
		
		g.setColor(Color.RED);
		g.fillRect(playerSprite.getX() - 5, playerSprite.getY() - 40, playerSprite.returnHealth(), 10);// healthbar
																			// fill
		g.setColor(Color.GREEN);
		g.drawRect(playerSprite.getX() - 5, playerSprite.getY() - 40, 70, 10);

		g.setColor(Color.GREEN);
		g.drawString(playerSprite.getMTag(), playerSprite.getX() - 20, playerSprite.getY() - 10); // Monster
																	// Name
		

		g.drawImage(playerSprite.getsprite(), playerSprite.getX(), playerSprite.getY(), this);// Monster
																		// Sprite

		monsterSprite.Render(g);

		
		
		// ED.tempmhp);
		//g.drawImage(UI, 350,600,600,90, this);
		fps(g);
		
	}

========================Everything in main========================================================================




import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;



public class Game implements Runnable{
   
   
   //
   BufferedImageLoader BuffLoad = new BufferedImageLoader();
	BufferedImage sprite_sheet = null;
	BufferedImage sprite;
	Image image;
	ImageIcon ii ;
	
	public Board3 b3;  
   //
	 int WIDTH = 0;
	    int HEIGHT = 0;
	SonageArenaFrame SAF;
	JFrame frame;
   Canvas canvas;
   BufferStrategy bufferStrategy;
   
   public Game(){
		
	   frame= new JFrame("DemoCanvas");
	  //. frame = new JFrame("Demo Canvas");
      b3= new Board3();

	   WIDTH=b3.bg.getWidth(null);
	   HEIGHT= b3.bg.getHeight(null);
      frame.add(SAF.p, "South");
     JPanel panel = (JPanel) frame.getContentPane();
     
      panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
      panel.setLayout(null);
      
      canvas = new Canvas();
      canvas.addKeyListener(new TAdapter());
      canvas.setBounds(0, 0, WIDTH, HEIGHT);
      canvas.setIgnoreRepaint(true);
      
      panel.add(canvas);
      
      canvas.addMouseListener(new MouseControl());
      
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setResizable(true);
      frame.setVisible(true);
    
      
      
	  
      
      
      canvas.createBufferStrategy(3);
      bufferStrategy = canvas.getBufferStrategy();
      
      canvas.requestFocus();
   }
   
        
   private class MouseControl extends MouseAdapter{
      
   }
   
   long desiredFPS =60;
  
    
   boolean running = true;
   
   public void run() {
	    final long DESIRED_LOOP = Math.round(1e9 / desiredFPS);
	    
	    long lastTime = System.nanoTime();
	    
	    while(true) {
	        long deltaTime = System.nanoTime() - lastTime;
	        lastTime += deltaTime;
	       
	        update(deltaTime);
	        
	        render();
	        
	        long sleepTime = Math.round((DESIRED_LOOP)-(System.nanoTime()-lastTime));
	        if(sleepTime <= 0)
	            continue;
	        
	        long prevTime = System.nanoTime();
	        while(System.nanoTime()-prevTime <= sleepTime) {
	            if(System.nanoTime()-prevTime <= sleepTime * 0.9)
					try {
						Thread.sleep(1);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				else
	                Thread.yield();
	        }
	    }
	}
   
   public void render() {
	    do{
	        do{
	            Graphics2D g = (Graphics2D)bufferStrategy.getDrawGraphics();
	            
	            b3.paint(g);
	            
	            g.dispose();
	        }while(bufferStrategy.contentsRestored());
	        
	        bufferStrategy.show();
	    }while(bufferStrategy.contentsLost());
	}
   
   //TESTING
   
   /**
    * Rewrite this method for your game
    */
   protected void update(long deltaTime){
      
	   //b3.setDelta(deltaTime);
	   
	   b3.update((int)((deltaTime/1e9)*1000));
	   System.out.println((int)((deltaTime/1e9)*1000));
   }
  
   /**
    * Rewrite this method for your game
    */
   protected void render(Graphics2D g){
	 
	 b3.paint(g);
   }
   private class TAdapter extends KeyAdapter {

		public void keyReleased(KeyEvent e) {
			b3.playerSprite.keyReleased(e);
		}

		public void keyPressed(KeyEvent e) {
			b3.playerSprite.keyPressed(e);
		}
	}
   public static void main(String [] args){
      Game ex = new Game();
      new Thread(ex).start();
   }
   
}

deltaTime/1e9 * 1000 is the same as deltaTime/1e6.

And yeah, everything looks fine :slight_smile: