I'm trying to learn how to program with Java which is more or less my first programming language (had some basic Pascal and C,C++ in school and college) but still a Beginner, with a capital 'B'.
Right now I'm working on a mini game, which is similar to the "breakout" game, but it's going to have my own implementation and won't have any blocks to destroy (I know it sounds weird). I have written some core classes, created a field, a pad and a ball. I'd like to get some feedback on my coding: how could I improve my code so it would be easier to implement new features and I'd like to know some of my bad habits that I should try to avoid doing to become good in writing code?
Here are my classes that I have already written:
Game class:
package game;
import java.awt.EventQueue;
import javax.swing.JFrame;
public class Game extends JFrame {
public Game(){
Field field = new Field();
setContentPane(field);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("BLOCK GAME bETA");
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
Game ex = new Game();
ex.setVisible(true);
});
}
}
Field class:
package game;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JLabel;
public class Field extends JLabel{
//Dimensions of the field.
public final int FIELD_HEIGHT = 800;
public final int FIELD_WIDTH = 480;
//Creates a pad.
static Pad pad = new Pad();
//Creates a ball on top of the pad.
static Ball ball = new Ball(pad.getPadX(), pad.getPadY());
private Timer timer;
//Field constructor, creates a game field.
public Field(){
setPreferredSize(new Dimension(FIELD_WIDTH, FIELD_HEIGHT));
setFocusable(true);
addKeyListener(new Control());
timer = new Timer();
timer.scheduleAtFixedRate(new ScheduleTask(), 100, 20);
}
//Draws all of the components on the screen.
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
setOpaque(true);
setBackground(new Color(27, 89, 195));
drawFieldLimits(g);
drawPad(g);
drawBall(g);
}
private void drawFieldLimits(Graphics g){
// 15 pixel offset from the boarder of the frame.
g.drawLine(15, 15, 15, FIELD_HEIGHT - 15);
g.drawLine(15, 15, FIELD_WIDTH - 15, 15);
g.drawLine(FIELD_WIDTH - 15, 15, FIELD_WIDTH - 15, FIELD_HEIGHT - 15);
}
private void drawPad(Graphics g){
g.fillRect(pad.getPadX(), pad.getPadY(), pad.getPadWidth(), pad.getPadHeight());
}
private void drawBall(Graphics g){
g.fillOval(ball.getBallX(), ball.getBallY(), ball.getBallDiamiter(), ball.getBallDiamiter());
}
private class Control extends KeyAdapter{
@Override
public void keyReleased(KeyEvent e){
pad.keyReleased(e);
}
@Override
public void keyPressed(KeyEvent e){
pad.keyPressed(e);
}
}
private class ScheduleTask extends TimerTask{
@Override
public void run() {
pad.movement();
ball.movement(pad.getPadX(), pad.getPadY());
repaint();
}
}
}
Pad class:
package game;
import java.awt.event.KeyEvent;
public class Pad extends Field{
private final int PAD_WIDTH = 60;
private final int PAD_HEIGHT = 10;
//Starting point of the pad.
private final int INITIAL_X = (FIELD_WIDTH/2) - (PAD_WIDTH/2);
private final int INITIAL_Y = FIELD_HEIGHT - PAD_HEIGHT - 10;
//Starting speed of the pad, may change during the game.
private int initialPadSpeed = 5;
private int padSpeed;
//Pad position.
private int padX, padY;
//Constructor
public Pad(){
padX = INITIAL_X;
padY = INITIAL_Y;
}
//Defines the movement of the pad.
public void movement(){
padX += padSpeed;
if(padX <= 15){
padX = 15;
}
// 15 is the offset.
if(padX >= FIELD_WIDTH - PAD_WIDTH - 15){
padX = FIELD_WIDTH - PAD_WIDTH - 15;
}
}
//Getters.
public int getPadX(){
return padX;
}
public int getPadY(){
return padY;
}
public int getPadWidth(){
return PAD_WIDTH;
}
public int getPadHeight(){
return PAD_HEIGHT;
}
//Action events used to move the pad left and right.
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT){
padSpeed = -initialPadSpeed;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
padSpeed = initialPadSpeed;
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
padSpeed = 0;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
padSpeed = 0;
}
}
}
Ball class:
package game;
public class Ball extends Pad{
//Variables that define the ball.
private int ballX, ballY;
private int initialBallSpeedVertical = 2;
private int initialBallSpeedHorizontal = 2;
private int ballSpeedVertical, ballSpeedHorizontal;
private int ballDiameter = 10;
//Constructor that has pad position coordinates as parameters, so the ball will be created on the pad.
public Ball(int x, int y) {
ballX = x + 30; // + pad width so the ball is at the middle of the pad.
ballY = y;
ballSpeedVertical = initialBallSpeedVertical;
ballSpeedHorizontal = initialBallSpeedHorizontal;
}
//Defines how the ball moves during the game. Consists pad position coordinates
//so the ball could bounce of the pad.
public void movement(int padX, int padY){
ballX -= ballSpeedHorizontal;
ballY -= ballSpeedVertical;
if(ballX <= 15){
ballSpeedHorizontal =-ballSpeedHorizontal;
}
if(ballX >= FIELD_WIDTH - ballDiameter - 15){
ballSpeedHorizontal = ballSpeedHorizontal =-ballSpeedHorizontal;
}
if(ballY <= 15){
ballSpeedVertical = -ballSpeedVertical;
}
if(ballY >= FIELD_HEIGHT - ballDiameter){
ballSpeedHorizontal = 0;
ballSpeedVertical = 0;
}
//Bouncing of the pad.
if((ballX >= getPadX() && (ballX <= padX + getPadWidth()) && (ballY >= padY))){
ballSpeedVertical = -ballSpeedVertical;
}
}
//Getters.
public int getBallX(){
return ballX;
}
public int getBallY(){
return ballY;
}
public int getBallDiamiter(){
return ballDiameter;
}
}
I'd also like to add that I have written this using numerous of online tutorials as an examples and help. I'd also like to know why I get StackOverflowError
if I don't assign pad and ball objects as static in Field class because it worked for people who wrote tutorials that I was using?
Also, I know that I could have made some variables final
but I think they might be changeable on the future versions of the game (e.g. the ones that determine pad and ball speed).
Also, feel free to bash me for my beginner skills (or lack of them) and don't be afraid of giving me some harsh criticism. Any feedback with coding advice will be much appreciated.