1
\$\begingroup\$

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){
            e.printStackTrace();
            //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);
        thread.start();
    }

    private synchronized void stop() {

        if(!running)
            return;

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

            e.printStackTrace();
        }
        System.exit(1);
    }


    public void run() {
        init();
        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) {
                tick();
                updates++; 
                delta--;// returns delta to not being >=1
            }
            render();
            frames++;

            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() {

        p.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) {

            createBufferStrategy(3);
            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);

        p.render(g);

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


    }


    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.add(game);
        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

        game.start();
    }


    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!

EDIT

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

\$\endgroup\$
  • \$\begingroup\$ could you add the sprite sheet and its dimension? \$\endgroup\$ – Martin Frank Mar 13 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 at 12:53
1
\$\begingroup\$

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;)
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Thank you so much @MartinFrank ! Absolute legend. \$\endgroup\$ – RhysGP15 Mar 13 at 14:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.