Sign in to follow this  
stein102

Critique/tips on first breakout attempt?

Recommended Posts

I have followed the advice given by Alpha_ProgDes and made a pong game, followed by a breakout game. I made the game in Java with Slick as my game library. It's pretty basic and has a few errors, but I'm fairly happy with the overall result. There is still work to be done, the errors I need to fix right now are:

 

1) When ball collides with the paddle on the side it still changes the balls dy, not the dx. I feel like it would be easy enough to make another shape and add it onto the ends of the paddle for the ball to collide with.

2) Sometimes when the ball collides with the bricks, instead of bouncing off and destroying the brick, it continues through that brick and destroys another. I'm not sure what causes this but I feel like it has something to do with the order I've set up the collision in.

 

Possibly features to add:

1) Music and sound - This should be easy enough, it's just a matter of finding some sounds to use

2) A menu

3) Actual game levels - Read from a text file, instead of 5 solid lines of brick

4) A level editor - Probably something I'd come back to after gaining more experience

5) Player lives - After #3

6) A score - After #3

 

What do you guys think? Any suggestions of things I can do differently?

 

After typing this all out, I got an error with the uploader, it reads "Upload Skipped(Error503)". Any idea what this means? I'd like to get some input on this project.

Share this post


Link to post
Share on other sites

I'd consider (2) unacceptable. I'm not sure about (1) either.

I strongly suggest to use sweeping collision checking.

I also suggest to do (5) and (6) before (3) as I expect those to be easier. Do easy things first.

 

As a side note, I don't suggest to use text files. Their inability to be "natively set up in columns" makes them hard to deal with in my opinion.

Consider .csv instead: this way, you can edit them in (say) openoffice calc, export it (it's basically a txt anyway) but you gain the explicit aligned cells of a spreadsheet.

In the past, I've experimented with this for a maze-oriented game. The fact each cell can contain nearly arbitrary data without messing up the layout (at least in calc) was a serious bonus for me.

 

No idea about the upload error. I'm fairly sure other people have uploaded executables in the past.

Share this post


Link to post
Share on other sites

After typing this all out, I got an error with the uploader, it reads "Upload Skipped(Error503)". Any idea what this means? I'd like to get some input on this project.

Just post the code here. It'll be easier on everyone.

Share this post


Link to post
Share on other sites

After typing this all out, I got an error with the uploader, it reads "Upload Skipped(Error503)". Any idea what this means? I'd like to get some input on this project.

Just post the code here. It'll be easier on everyone.

 

Main Class:

import java.util.Random;
import org.lwjgl.input.Mouse;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

public class BreakoutMain extends BasicGame {

	static AppGameContainer app;
	Brick[] bricks;
	Paddle paddle;
	Ball ball;
	boolean gameOver = false;
	Item item;

	public BreakoutMain() {
		super("Breakout");

	}

	public void init(GameContainer container) throws SlickException {
		paddle = new Paddle(Mouse.getX());
		bricks = new Brick[60];
		ball = new Ball(Mouse.getX());
		item = new Item(1000, 0);
		int brickx = 5;
		int bricky = 5;

		for (int c = 0; c < 5; c++) {
			for (int i = 0; i < 12; i++) {
				bricks[(c * 12) + i] = new Brick(brickx, bricky);
				brickx += 65;
			}
			bricky += 35;
			brickx = 5;
		}
	}

	public void update(GameContainer container, int delta)
			throws SlickException {
		if (!gameOver) {
			Input input = app.getInput();

			if (input.isMousePressed(0) && !ball.isFree()) {
				ball.setFree(true);
			}

			paddle.update(Mouse.getX());
			ball.update(Mouse.getX());
			item.update();

			collision();
		} else {
			if (Mouse.isButtonDown(0)) {
				System.exit(0);
			}
		}
	}

	public void render(GameContainer container, Graphics g)
			throws SlickException {
		if (!gameOver) {
			paddle.paint(g);
			ball.paint(g);
			item.paint(g);

			for (Brick b : bricks) {
				b.paint(g);
			}
		} else {
			g.drawString("Game Over", 350, 280);
		}
	}

	public static void main(String[] args) throws SlickException {
		app = new AppGameContainer(new BreakoutMain());

		app.setDisplayMode(785, 600, false);
		app.start();
	}

	public void collision() {
		// Ball-Brick
		for (Brick currentBrick : bricks) {
			if (ball.ballCircle.intersects(currentBrick.brickRect)) {
				ball.setDy(-ball.getDy());

				Random rand = new Random();
				// 10% chance to drop item on broken brick
				switch (rand.nextInt(49)) {
				case 0:
					item = new ItemBigPaddle(
							currentBrick.brickRect.getCenterX(),
							currentBrick.brickRect.getCenterY());
					break;
				case 1:
					item = new ItemSmallPaddle(
							currentBrick.brickRect.getCenterX(),
							currentBrick.brickRect.getCenterY());
					break;
				case 2:
					item = new ItemFastBall(
							currentBrick.brickRect.getCenterX(),
							currentBrick.brickRect.getCenterY());
					break;
				case 3:
					item = new ItemSlowBall(
							currentBrick.brickRect.getCenterX(),
							currentBrick.brickRect.getCenterY());
					break;
				}

				currentBrick.brickRect.setX(1000);
			}
		}

		// Ball-Right Wall
		if (ball.ballCircle.getMaxX() >= 785) {
			ball.setDx(-ball.getDx());
		}

		// Ball-Left Wall
		if (ball.ballCircle.getMinX() <= 0) {
			ball.setDx(-ball.getDx());
		}

		// Ball-Top Wall
		if (ball.ballCircle.getMinY() <= 0) {
			ball.setDy(-ball.getDy());
		}

		// Ball-Bottom Wall
		if (ball.ballCircle.getMaxY() >= 600) {
			gameOver = true;
		}

		// Ball-paddle
		if (ball.ballCircle.intersects(paddle.paddleRect)) {
			ball.setDy(-ball.getDy());
		}

		// Paddle-Item
		if (paddle.paddleRect.intersects(item.itemCircle)) {
			item.performAction(ball, paddle);
			item.itemCircle.setCenterX(1000);
		}

	}

}

Ball Class:

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Circle;

public class Ball {

	private float dx = .2f;
	private float dy = .2f;
	private boolean isFree = false;
	Circle ballCircle;

	public Ball(int mouseX) {
		ballCircle = new Circle(mouseX, 550, 10);
	}

	public void update(int mouseX) {
		if (!isFree) {
			ballCircle.setCenterX(mouseX);
		} else {
			ballCircle.setCenterX(ballCircle.getCenterX() + dx);
			ballCircle.setCenterY(ballCircle.getCenterY() - dy);
		}
	}

	public void paint(Graphics g) {
		g.setColor(Color.white);
		g.fillOval(ballCircle.getX(), ballCircle.getY(),
				ballCircle.getHeight(), ballCircle.getWidth());

	}

	// Getters and setters

	public boolean isFree() {
		return isFree;
	}

	public void setFree(boolean isFree) {
		this.isFree = isFree;
	}

	public float getDx() {
		return dx;
	}

	public void setDx(float dx) {
		this.dx = dx;
	}

	public float getDy() {
		return dy;
	}

	public void setDy(float dy) {
		this.dy = dy;
	}

}

Paddle Class:

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Rectangle;

public class Paddle {

	Rectangle paddleRect;

	public Paddle(float MouseX) {
		paddleRect = new Rectangle(MouseX, 560, 60, 15);
	}

	public void paint(Graphics g) {
		g.setColor(Color.white);
		g.fillRect(paddleRect.getX(), paddleRect.getY(), paddleRect.getWidth(),
				paddleRect.getHeight());
	}

	public void update(int mouseX) {
		paddleRect.setCenterX(mouseX);
		if (paddleRect.getMaxX() >= 785)
			paddleRect.setX(785 - paddleRect.getWidth());

		if (paddleRect.getX() <= 0)
			paddleRect.setX(0);
	}

}

Brick Class:

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Rectangle;

public class Brick {

	private boolean destroyed = false;
	Rectangle brickRect;

	public Brick(float x, float y) {

		brickRect = new Rectangle(x, y, 60, 30);
	}

	public void paint(Graphics g) {
		g.setColor(Color.white);
		g.fillRect(brickRect.getX(), brickRect.getY(), brickRect.getWidth(),
				brickRect.getHeight());
	}
}

Item Class:

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Circle;

public class Item {

	Circle itemCircle;
	float dy = .15f;
	Color color;

	public Item(float x, float y) {
		itemCircle = new Circle(x, y, 7);
	}

	public void update() {
		if (itemCircle.getCenterX() != 1000) {
			itemCircle.setCenterY(itemCircle.getCenterY() + dy);
		}
	}

	public void performAction(Ball ball, Paddle paddle) {}

	public void paint(Graphics g) {
		g.setColor(color);
		g.fillOval(itemCircle.getCenterX(), itemCircle.getCenterY(),
				itemCircle.getWidth(), itemCircle.getHeight());
	}

}

 


There are other classes for the various items I've made, they're pretty basic though. Only thing different in them is that I change color and add stuff into the action performed method. The only items I've made are Speed up, Speed down, Bigger paddle and Smaller paddle.

Share this post


Link to post
Share on other sites

Have you looked at what happens if you try to hit a block from on top of it?
If you look at

 

ball.setDy(-ball.getDy()); 

 

 

You should consider using vectors to represent the balls velocity.

Share this post


Link to post
Share on other sites

So how would I use a vector to represent the balls velocity? When the ball hits a stationary object, it's velocity just reverses, so that's simple. When the object hits the paddle though, would I reverse the velocity of the ball and add on the velocity of the paddle?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this