Java Roguelike notes (1/13): Drawing the ‘@’ symbol and moving it around

Following the previous post, I’ll be sharing my notes while developing a Roguelike in Java. This is not a step by step tutorial, but just the code and some comments to clarify why I used something. This may change in future posts if the development requires it. First the final, graphical, result:

Placing the player – Java Roguelike #1

Notes:

Rogue.Java

public class Rogue {

    public static void main(String[] args){

        GameFrame frame = new GameFrame();
    }
}
  • Create the main() method as our unique point of entry to the application
  • Instantiate the GameFrame

GameFrame.java

import javax.swing.*;
import java.awt.*;

public class GameFrame extends JFrame {

        GamePanel panel;
        GameFrame(){
            panel = new GamePanel();
            this.add(panel);
            this.setTitle("Rogue");
            this.setVisible(true); 
            this.setResizable(false);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.pack();
            this.setLocationRelativeTo(null);
        }
}

  • Instantiate the GamePanel
  • Calling setVisible(true) on a JFrame which is already visible works for you because this ends up calling validate() internally, which in turn revalidates all subcomponents in the frame: https://stackoverflow.com/a/21187039
  • this.setResizable(false); ensures that the graphical interface looks the way you intend by preventing the user from re-sizing it
  • this.pack(); sets/fits/adjust the frame to the preferred size of the subcomponent, in this case the GamePanel because I don’t want extra buttons or UI elements. This may change in the future.
  • this.setLocationRelativeTo(null); makes the UI appear in the middle of the screen, rather than in the corner

GamePanel.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.geom.Point2D;
import java.util.List;
import java.util.ArrayList;
import java.util.Random;

public class GamePanel extends JPanel {

    // Panel-specific
    static final int SCREEN_WIDTH = 600;
    static final int SCREEN_HEIGHT = 600;
    static final int UNIT_SIZE = 25;
    static final int GAME_UNITS = (SCREEN_WIDTH*SCREEN_HEIGHT)/UNIT_SIZE;
    private static final Dimension SCREEN_SIZE = new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);

    // Player-specific
    final int x[] = new int[GAME_UNITS];
    final int y[] = new int[GAME_UNITS];
    int bodyParts = 1;
    int playerLocX;
    int playerLocY;
    char direction;
    boolean canPlayerMove = true;

    GamePanel(){

        this.setPreferredSize(SCREEN_SIZE);
        this.setBackground(Color.white);
        this.setFocusable(true);
        this.addKeyListener(new MyKeyAdapter());

        startGame();

    }
    public void startGame(){

        newPlayer();
    }


    public void paintComponent(Graphics g){
        super.paintComponent(g);
        draw(g);
    }

    public void draw(Graphics g){

        // Tile Matrix:
        for(int i=0; i<(SCREEN_HEIGHT/UNIT_SIZE);i++){
            g.drawLine(i*UNIT_SIZE, 0, i*UNIT_SIZE, SCREEN_HEIGHT);
            g.drawLine(0, i*UNIT_SIZE, SCREEN_WIDTH, i*UNIT_SIZE);
        }
        // Player
        for (int i = 0; i < bodyParts; i++){
            g.setColor(Color.green);
            g.setFont(new Font("Ink Free", Font.BOLD, 25));
            g.drawString("@", x[i], y[i]);
        }
    }

    public void newPlayer(){
        playerLocX = 0;
        playerLocY = 0;
    }

    public void move(){

        switch (direction){
            case 'U':
                y[0] = y[0] - UNIT_SIZE;
                break;
            case 'D':
                y[0] = y[0] + UNIT_SIZE;
                break;
            case 'L':
                x[0] = x[0] - UNIT_SIZE;
                break;
            case 'R':
                x[0] = x[0] + UNIT_SIZE;
                break;
        }
        repaint();
    }



    public class MyKeyAdapter extends KeyAdapter {
        @Override
        public void keyPressed(KeyEvent e) {
            switch (e.getKeyCode()){
                case KeyEvent.VK_LEFT:
                    direction = 'L';
                    move();
                    break;
                case KeyEvent.VK_RIGHT:
                    direction = 'R';
                    move();
                    break;
                case KeyEvent.VK_UP:
                    direction = 'U';
                    move();
                    break;
                case KeyEvent.VK_DOWN:
                    direction = 'D';
                    move();
                    break;
            }
        }
    }
}

  • We use .setPreferredSize() when a parent layout manager exists (GameFrame in this case), and .setSize() if doesn’t
  • Upon keyPressed() event, we pass the direction char and call move(), which repaint() the player on its new position
  • The name for int bodyParts = 1; is not the best, I know 🙂 This is just because the core game loop of the game will include a twist and will make sense in the future, otherwise can be refactored easily to a single unit.

One thought on “Java Roguelike notes (1/13): Drawing the ‘@’ symbol and moving it around

Leave a Reply