I have a University Project to create a simple game in Java. To challenge myself am trying to utilise sprite sheets. My issue is that the whole Sprite sheet is being shown rather than the section that I would like, the whole sprite sheet is shown. Below I will show all my classes. Any help would be much appreciated.

The Game class:

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.swing.JFrame;

public class Game extends Canvas implements Runnable {

    private static final long serialVersionUID = 1L;
    public static final int WIDTH = 320; //Declares width of window
    public static final int HEIGHT = WIDTH / 12 * 9;//Declares height
    public static final int SCALE = 2;// Declares scale of window
    public final String TITLE = "2D Space Game";

    private boolean running =false;
    private Thread thread;

    private BufferedImage image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);
    //Buffers the display of images, "loads" it.
    private BufferedImage spriteSheet = null;

    private Player p;

    public void init(){ //initialise
        BufferedImageLoader loader = new BufferedImageLoader();
        try {

            spriteSheet = loader.loadImage("/Sprite_Sheet.png");

        }catch(IOException e){
            //if image path cannot be found, error produced

        p = new Player(200, 200, this);

    private synchronized void start(){

        if (running)
            return;//if the method is running, leave the method

        running = true;
        thread = new Thread(this);

    private synchronized void stop() {


        running = false;// stops game loop
        try {
            thread.join();//joins all threads
        } catch (InterruptedException e) { //thread joining can sometimes fail. catch identifies this


    public void run() {
        long lastTime = System.nanoTime(); //long = int, but can store higher positive/lower negative numbers
        final double amountOfTicks = 60.0;//Will lock game at 60fps
        double ns = 1000000000 / amountOfTicks;
        double delta = 0; //calculate time passed, so if fps is behind game can catch up
        int updates = 0;// to check fps
        int frames = 0;// to check fps
        long timer = System.currentTimeMillis();

        while(running) {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now; //This negates the time taken to get from above code to here
            if(delta >= 1) {
                delta--;// returns delta to not being >=1

            if(System.currentTimeMillis() - timer > 1000) {
                timer +=1000;
                System.out.println(updates + "Ticks, Fps " + frames); //This code was used to check the ticks and fps of the game
                updates = 0;
                frames = 0;//resets, so we see ticks and fps per second rather than total
        stop();//calling stop method

    //This game loop allows for slow computers to play the game as there is a maximum tick speed. Standard for all games.

    private void tick() {



    private void render() {
        //Buffer strategy handles all the buffering behind the scenes.
        BufferStrategy bs = this.getBufferStrategy(); //Returns a buffer strategy to be used by BufferStrategy, or null if one has not been created
        // Above initilises the buffer strategy

        if(bs == null) {

            return; //If there is no buffer strategy, create 3
            //Three buffer strategy loads 3 images, which will be projected one after another. Increases speed.


        Graphics g = bs.getDrawGraphics(); //creates graphics for buffers
        //Can draw in this area

        g.drawImage(image, 0, 0, getWidth(), getHeight(), this);


        g.dispose(); //gets rid of buffer once done with it


    public static void main(String args[]) {

        Game game = new Game();

        game.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE)); //Creates good aspect ratio
        game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
        game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));

        JFrame frame = new JFrame(game.TITLE);
        frame.pack();//takes all of the components and sizes the frame to the sizes of its components
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//Allows exit button to work
        frame.setResizable(false); //Stops player resizing window
        frame.setLocationRelativeTo(null);//Not run
        frame.setVisible(true);//Window is visible


    public BufferedImage getSpriteSheet() {
        return spriteSheet;

        //setter, so spritesheet doesnt have to be initialised in musltple clasess


The Player Class:

import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class Player {

    private double x;//x coor'd of player
    private double y;//y coor'd of player

    private BufferedImage player;

    public Player(double x, double y, Game game) { //constructor method, will be called when player is initialised

        this.x = x; 
        this.y = y;

        //sets the coordinates of the player when initialised

        /* eg p = new Player(100,100); */

        SpriteSheet ss = new SpriteSheet(game.getSpriteSheet());

        player = ss.grabImage(1, 1, 32, 32);
        //Getter is also in this method, calling the spriteSheet method from the G ame class.

    public void tick() {


    public void render(Graphics g) {
        g.drawImage(player, (int)x, (int)y, null); 
        //.drawImage only works with integers, but we declared as double, so must cast as int



The BufferedImageLoader Class:

import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;

public class BufferedImageLoader {

    private BufferedImage image;

    public BufferedImage loadImage(String path) throws IOException {

        image =ImageIO.read(getClass().getResource(path));
        return image;

//This class is made to load in the buffered images. 

The Sprite Sheet Class:

import java.awt.image.BufferedImage;

public class SpriteSheet {

    private BufferedImage image; // creating another Buffered Image

    public SpriteSheet(BufferedImage image) {
        this.image = image;

    public BufferedImage grabImage(int col, int row, int width, int height) {

        BufferedImage img = image.getSubimage((col * 32) - 32, (row * 32) -32, width, height);
        return image;
        //Selecting the rows and columns of the spritesheet in folder res. 
        //This determines what image from the sprite sheet to display, in this case the player.

I appreciate that here I have dumped alot of code, but it would be challenging for me to pick it apart to just the sprite sheet code lines as the span across multiple classes. I believe the issue lies within the spritesheet class or the player class, but again I cannot be to sure. Thanks for any help!


The sprite I would like to capture is 32 by 32, and the sprite sheet as a whole is 256 by 256.SpriteSheet

  • \$\begingroup\$ could you add the sprite sheet and its dimension? \$\endgroup\$ Mar 13, 2020 at 6:15
  • 1
    \$\begingroup\$ @MartinFrank I have added the Sprite sheet as you asked. Thank you for your help. There are some aspects of this code that I don't quite fully understand as I am just a beginner and this is my first real project. I have used lots of online resources to make this. If you are offering to help explain the code that would be much obliged. Thanks again! \$\endgroup\$
    – RhysGP15
    Mar 13, 2020 at 12:53

1 Answer 1


I think there is a minor typo in your code, see SpriteSheet class

public BufferedImage grabImage(int col, int row, int width, int height) {
    BufferedImage img = image.getSubimage((col * 32) - 32, (row * 32) -32, width, height);
    //return image; typo here! 
    return img;

what actually happens:

  • you crop a sub image (named img) from your spriteSheet image (named image).
  • but instead of return the cropped image (img) you return the original image (named image).
  • fix it by returning the cropped image (return img;)
  • 1
    \$\begingroup\$ Thank you so much @MartinFrank ! Absolute legend. \$\endgroup\$
    – RhysGP15
    Mar 13, 2020 at 14:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .