Breakout ball collision in libgdx - java

I'm currently trying to make a breakout clone using java and libgdx. I'm currently experiencing trouble getting the ball to bounce off of the blocks at the appropriate angle. In short the problem I'm having is that the ball moves 12 pixels every frame and doesn't always line up with the edge of a brick. If anyone has any suggestions on a better way to move the ball or a different way to check collision it would be much appreciated!
Main game class
package com.kyleparker.breakout;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.Array;
public class BreakoutGameScreen implements ApplicationListener {
Texture dropImage;
Sound dropSound;
Music rainMusic;
SpriteBatch batch;
OrthographicCamera camera;
Rectangle bucket;
Paddle paddle;
//Brick bricks[];
Array<Brick> bricks;
Ball ball;
#Override
public void create() {
// load the images for the droplet, 64x64 pixels
dropImage = new Texture(Gdx.files.internal("droplet.png"));
// load the drop sound effect and the rain background "music"
dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
// start the playback of the background music immediately
rainMusic.setLooping(true);
rainMusic.play();
// create the camera and the SpriteBatch
camera = new OrthographicCamera();
camera.setToOrtho(false, 1280, 720);
batch = new SpriteBatch();
paddle = new Paddle(new Texture(Gdx.files.internal("bucket.png")));
bricks = new Array<Brick>();
populateBricks();
ball = new Ball(new Texture(Gdx.files.internal("bucket.png")), paddle, bricks);
}
private void populateBricks() {
bricks.add(new Brick(200,100));
for (int i = 0; i < 5; i++) {
for (int j = 0; j <= 7; j++) {
bricks.add(new Brick (j * 144 + 76, i * 80 + 300)); //Offsets each new brick
}
}
}
#Override
public void render() {
// clear the screen with a dark blue color. The
// arguments to glClearColor are the red, green
// blue and alpha component in the range [0,1]
// of the color to be used to clear the screen.
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// tell the camera to update its matrices.
camera.update();
// tell the SpriteBatch to render in the
// coordinate system specified by the camera.
batch.setProjectionMatrix(camera.combined);
// begin a new batch and draw the bucket and
// all drops
batch.begin();
paddle.render(batch, camera);
ball.move();
ball.render(batch, camera);
for (int x = bricks.size - 1; x > 0; x--) {
bricks.get(x).render(batch,camera);
}
batch.end();
}
#Override
public void dispose() {
// dispose of all the native resources
dropImage.dispose();
dropSound.dispose();
rainMusic.dispose();
batch.dispose();
paddle.dispose();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
Ball class
package com.kyleparker.breakout;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.Array;
public class Ball{
Texture ballImage;
Rectangle ball;
private int xdir;
private int ydir;
Paddle paddle;
Array<Brick> bricks;
final int BALL_SPEED = 12;
public Ball(Texture ballImage, Paddle paddle, Array<Brick> bricks) {
// load the ball image
this.ballImage = ballImage;
xdir = 1;
ydir = -1;
// create a Rectangle for the balls collision
ball = new Rectangle();
ball.x = 1280 / 2 - 64 / 2; // center the ball
ball.y = 100; // put the ball 200px away from the bottom of the screen
ball.width = 64;
ball.height = 64;
this.paddle = paddle;
this.bricks = bricks;
}
public void render(SpriteBatch batch, OrthographicCamera camera) {
// draw the paddle onto the batch of the level
batch.draw(ballImage, ball.x, ball.y);
}
public void move() {
ball.x += xdir * BALL_SPEED;
ball.y += ydir * BALL_SPEED;
if (ball.x <= 0) {
setXDir(1);
}
if (ball.x >= 1280 - 64) {
setXDir(-1);
}
if (ball.y <= 0) {
setYDir(1);
}
if (ball.y >= 720 - 64) {
setYDir(-1);
}
if (ball.overlaps(paddle.getRect())) {
setYDir(1);
}
for (int i = 0; i < bricks.size; i++) {
if (ball.overlaps(bricks.get(i).getRect())) {
if ((ball.x == (bricks.get(i).getRect().x + 128)))
{
setXDir(1);
bricks.get(i).setDestroyed(true);
System.out.println("Collision RIGHT");
}
if (((ball.x + 64) == bricks.get(i).getRect().x))
{
setXDir(-1);
bricks.get(i).setDestroyed(true);
System.out.println("Collision LEFT");
}
if ((ball.y == (bricks.get(i).getRect().y + 64)))
{
setYDir(1);
bricks.get(i).setDestroyed(true);
System.out.println("Collision TOP");
}
if (((ball.y + 64) == bricks.get(i).getRect().y))
{
setYDir(-1);
bricks.get(i).setDestroyed(true);
System.out.println("Collision BOTTOM");
}
}
}// end of for
}
public void setXDir(int x) {
xdir = x;
}
public void setYDir(int y) {
ydir = y;
}
public int getYDir() {
return ydir;
}
public int getXDir() {
return xdir;
}
public Rectangle getRect() {
// return the collision rectangle for checking overlaps
return ball;
}
public void dispose() {
// dispose of all the native resources
ballImage.dispose();
}
}// end of class
Brick code just in case
package com.kyleparker.breakout;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
public class Brick{
Texture brickImage;
Rectangle brick;
boolean destroyed;
public Brick(int x, int y) {
brickImage = new Texture(Gdx.files.internal("brick.png"));
// create a Rectangle for the bricks collision
brick = new Rectangle();
brick.x = x;
brick.y = y;
brick.width = 128;
brick.height = 64;
destroyed = false;
}
public void render(SpriteBatch batch, OrthographicCamera camera) {
// draw the brick onto the batch of the level
batch.draw(brickImage, brick.x, brick.y);
}
public boolean isDestroyed() {
// return the collision rectangle for checking overlaps
return destroyed;
}
public void setDestroyed(boolean destroyed)
{
this.destroyed = destroyed;
if (this.destroyed == true) {
dispose();
brick.x = -1000;
brick.y = -1000;
}
}
public Rectangle getRect() {
return brick;
}
public void dispose() {
// dispose of all the native resources
brickImage.dispose();
}
}

Don't worry about the fact that the ball doesn't always line up with an object for which the collision needs handled -- that's not actually relevant. You can (and should) handle your collisions less 'precisely.' That is, the ball's path is fixed, so you can calculate its position at any future point. Check its position, calculate its position in the next frame (which you have to do to draw it anyway), and add some code to handle the collision that is going to happen, rather than trying to detect and handle the collision which has happened. You can slow down the ball if you really want a clean reflection, or you can speed up your framerate, or you can let the ball be partially 'absorbed' by the object before it reflects:
public class Ball {
. . .
public void move() {
. . .
if (collisionObject.overlaps(new Rectangle(ball.x + xdir, ball.y + ydir, ball.width, ball.height))) {
//a collision will have occurred in the next frame
//handle the collision however you please
}
}
}
I also note that your BALL_SPEED field is inaccurately named. As presently coded, the ball always moves at a 45° angle, with a speed of about 17 pixels per frame (in that direction). You've coded its x- and y-offset as 12 pixels, but if (when?) you change the ball's direction, you'll find that the speed fluctuates wildly depending on what values are placed in for the xdir and ydir fields. For example, if you were to (somewhat) randomize these, but keep the rest of your code as-is, you might find that xdir = 2 and ydir = 4 on one instance, and xdir = 6 and ydir = 12 on another. Note these describe the same direction, but the second version will move three times as fast.
To properly handle the ball's direction and speed, assign an angle, and calculate the xdir and ydir values through the appropriate trigonometric functions (xdir = BALL_SPEED * Math.cos(ballAngle) and ydir = BALL_SPEED * Math.sin(ballAngle)).

I would use box2d for the whole thing. That you haven't used box2d probably means you have no experience in it, so that would be a little hurdle, but I'm sure you'll be able to wrap your head around it quickly. Here's a link for that: http://code.google.com/p/libgdx/wiki/PhysicsBox2D

Related

Event handling in libgdx not working as expected

I've been learning about libgdx recently. In the process of following the instructions on their libgdx wiki I ran into some problems.
Specifically in the GameScreen class at the 99th line I changed the code inside so that it goes back to the previous screen (MainMenuScreen class) and yes you see when the mouse is pressed it worked (I mean go back to the screen before ) but a very very short time after, the screen AUTOMATICALLY switches to the GameScreen class (like I click the mouse once but it makes me 1 more redundant task). I guess when I click on the GameScreen screen it did the code in the if statement on line 99 to go to MainMenuScreen screen. In that screen at line 32 I guess it was true after I got to this screen because when I change the key is listened then it works fine (only converts once). I was intending to try implementing InputProcessor on each screen class but now I'm avoiding it for some reason. Can someone give me some advice recommend.Thank you
Here is the source code for the MainMenuScreen class.
package com.mygdx.game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.utils.ScreenUtils;
//import com.mygdx.game.Drop;
public class MainMenuScreen implements Screen {
final Drop game;
OrthographicCamera camera;
public MainMenuScreen(final Drop gam) {
game = gam;
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
}
#Override
public void render(float delta) {
ScreenUtils.clear(0, 0, 0.2f, 1);
camera.update();
game.batch.setProjectionMatrix(camera.combined);
game.batch.begin();
game.font.draw(game.batch, "Welcome to Drop!!! ", 100, 150);
game.font.draw(game.batch, "Tap anywhere to begin!", 100, 100);
game.batch.end();
if (Gdx.input.isTouched()) { //I guess right after switching to this screen this conditional sentence was true before
game.setScreen(new GameScreen(game));
dispose();
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void show() {
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
}
}
Here is source code for the GameScreen class
package com.mygdx.game;
import java.util.Iterator;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.utils.TimeUtils;
public class GameScreen implements Screen {
final Drop game;
Texture dropImage;
Texture bucketImage;
//Sound dropSound;
//Music rainMusic;
OrthographicCamera camera;
Rectangle bucket;
Array<Rectangle> raindrops;
long lastDropTime;
int dropsGathered;
public GameScreen(final Drop gam) {
this.game = gam;
// load the images for the droplet and the bucket, 64x64 pixels each
dropImage = new Texture(Gdx.files.internal("drop.png"));
bucketImage = new Texture(Gdx.files.internal("bucket.png"));
// load the drop sound effect and the rain background "music"
//dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
//rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
//rainMusic.setLooping(true);
// create the camera and the SpriteBatch
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
// create a Rectangle to logically represent the bucket
bucket = new Rectangle();
bucket.x = 800 / 2 - 64 / 2; // center the bucket horizontally
bucket.y = 20; // bottom left corner of the bucket is 20 pixels above
// the bottom screen edge
bucket.width = 64;
bucket.height = 64;
// create the raindrops array and spawn the first raindrop
raindrops = new Array<Rectangle>();
spawnRaindrop();
}
private void spawnRaindrop() {
Rectangle raindrop = new Rectangle();
raindrop.x = MathUtils.random(0, 800 - 64);
raindrop.y = 480;
raindrop.width = 64;
raindrop.height = 64;
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
#Override
public void render(float delta) {
// clear the screen with a dark blue color. The
// arguments to clear are the red, green
// blue and alpha component in the range [0,1]
// of the color to be used to clear the screen.
ScreenUtils.clear(0, 0, 0.2f, 1);
// tell the camera to update its matrices.
camera.update();
// tell the SpriteBatch to render in the
// coordinate system specified by the camera.
game.batch.setProjectionMatrix(camera.combined);
// begin a new batch and draw the bucket and
// all drops
game.batch.begin();
game.font.draw(game.batch, "Drops Collected: " + dropsGathered, 0, 480);
game.batch.draw(bucketImage, bucket.x, bucket.y);
for (Rectangle raindrop : raindrops) {
game.batch.draw(dropImage, raindrop.x, raindrop.y);
}
game.batch.end();
// process user input
if (Gdx.input.justTouched()) { //This conditional works fine
/* Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
bucket.x = touchPos.x - 64 / 2;
*/
game.setScreen(new MainMenuSceen(game)); //Screen switch
}
if (Gdx.input.isKeyPressed(Keys.LEFT))
bucket.x -= 200 * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Keys.RIGHT))
bucket.x += 200 * Gdx.graphics.getDeltaTime();
// make sure the bucket stays within the screen bounds
if (bucket.x < 0)
bucket.x = 0;
if (bucket.x > 800 - 64)
bucket.x = 800 - 64;
// check if we need to create a new raindrop
if (TimeUtils.nanoTime() - lastDropTime > 1000000000)
spawnRaindrop();
// move the raindrops, remove any that are beneath the bottom edge of
// the screen or that hit the bucket. In the later case we play back
// a sound effect as well.
Iterator<Rectangle> iter = raindrops.iterator();
while (iter.hasNext()) {
Rectangle raindrop = iter.next();
raindrop.y -= 200 * Gdx.graphics.getDeltaTime();
if (raindrop.y + 64 < 0)
iter.remove();
if (raindrop.overlaps(bucket)) {
dropsGathered++;
//dropSound.play();
iter.remove();
}
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void show() {
// start the playback of the background music
// when the screen is shown
//rainMusic.play();
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
dropImage.dispose();
bucketImage.dispose();
//dropSound.dispose();
//rainMusic.dispose();
}
}
Here is source for Drop class
package com.mygdx.game;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class Drop extends Game {
SpriteBatch batch;
BitmapFont font;
public void create() {
batch = new SpriteBatch();
// Use LibGDX's default Arial font.
font = new BitmapFont();
this.setScreen(new MainMenuScreen(this));
}
public void render() {
super.render(); // important!
}
public void dispose() {
batch.dispose();
font.dispose();
}
}
Your analysis of the problem seems correct to me. The method Gdx.input.isTouched() will immediately return true, if the screen is still being touched after you changed to the main menu.
Also you the solution that you already tried seems correct:
I was intending to try implementing InputProcessor on each screen class
When using an InputProcessor you will get one event (the method call to touchDown or touchUp) when the screen is touched, and don't need to pull the touch event using the isTouched method.
A problem when implementing InputProcessor with both classes probably is, that you can only set one to be the input processor of the game using the method Gdx.input.setInputProcessor. (When setting the second input processor, the first one is removed).
A solution to this problem is the InputMultiplexer. You can add this multiplexer as the input processor of the game (using Gdx.input.setInputProcessor(multiplexer)) and then add your input processors (the main menu and game objects) to this multiplexer: multiplexer.addProcessor(mainMenu) or ((InputMultiplexer) Gdx.input.getInputProcessor()).addProcessor(game).
This way you can handle touch events instead of pulling the touched state in both of your classes.

How do I reposition a moving animation during a gameplay?

I am using the Android Studio IDE, with the libGDX framework to develop a game. It is a clone of the Pac-Man game with a similar gameplay to flappy bird. The concept is that the pac man moves through the planks while avoiding the ghosts coming from the right direction, that are moving off straight into the left direction (not chasing the position of the player). I am not sure how I create a 'for loop' for the ghost animations, I want the ghosts to consistently reposition and re-appear from the right side after a few seconds, with the exception that they completely gone off the screen initially.
The class for one of the Ghosts.
public class Blinky {
private Vector3 position; //x y and z axis
private Rectangle bounds;
private Texture texture1;
private Animation blinkyAnimLeft;
public Blinky(int x, int y) {
position = new Vector3(x, y, 0);
Texture texture1 = new Texture("blinkyLeft.png");
blinkyAnimLeft = new Animation(new TextureRegion(texture1), 2, 0.5f);
//bounds = new Rectangle(x,y,texture1.getWidth() / 2, texture1.getHeight());
}
public void update(float dt) {
blinkyAnimLeft.update(dt);
//bounds.setPosition(position.x, position.y);
}
public Vector3 getPosition() {
return position;
}
public TextureRegion getTexture() {
return blinkyAnimLeft.getFrame();
}
//public Rectangle getBounds() {
return bounds;
}
public void dispose() {
texture1.dispose();
}
}
Ghosts and Player initialised in the GamePlayState Class
public class GamePlayState extends State {
//Variables
private float timePassed = 0;
private Texture background;
public static final int WALK = 1;
public static final double GHOST_WALK = 0.5;
private static final int PLANKS_SPACING = 125; //gap betwen the planks
private static final int PLANK_COUNT = 4;
private Array<Obstacle> planks;
private Player player;
private Blinky blinky;
private Inky inky;
private Texture missile;
public GamePlayState(GameStateManager gsm) {
super(gsm);
player = new Player(50, 100);
blinky = new Blinky(400, 220);
inky = new Inky(400, 240);
// missile = new Texture("missile.png");
background = new Texture("black.jpg");
cam.setToOrtho(false, PacMan.WIDTH/2, PacMan.HEIGHT/2);
planks = new Array<Obstacle>();
for (int i = 1; i<= PLANK_COUNT; i++) {
planks.add(new Obstacle(i * (PLANKS_SPACING + Obstacle.PLANK_WIDTH)));
}
}
#Override
public void handleInput() {
}
#Override
public void update(float dt) {
handleInput();
player.update(dt);
blinky.update(dt);
inky.update(dt);
cam.position.x = player.getPosition().x + 80; //update the position of the camera with the bird
//update when pacman cam viewport has passed plank
//make cam follow the player
for (Obstacle plank: planks) {
if (cam.position.x - (cam.viewportWidth/1) > plank.getPosTopPlank().x + plank.getTopPlank().getWidth()) {
plank.respositionPlanks(plank.getPosTopPlank().x + ((Obstacle.PLANK_WIDTH + PLANKS_SPACING * PLANK_COUNT )));
}
if (plank.collision (player.getBounds()))
gsm.set(new GamePlayState(gsm));
}
cam.update();
}
#Override
public void render(SpriteBatch sb) {
sb.setProjectionMatrix(cam.combined);
sb.begin();
sb.draw(background, cam.position.x - (cam.viewportWidth/2), 0);
timePassed += Gdx.graphics.getDeltaTime();
//Moving Inky
sb.draw(inky.getTexture(), inky.getPosition().x, inky.getPosition().y);
inky.getPosition().x -= GHOST_WALK;
//Moving Blinky
sb.draw(blinky.getTexture(), blinky.getPosition().x, blinky.getPosition().y);
blinky.getPosition().x -= GHOST_WALK;
You should get x, y( and z) position from Vector3.
Then check for borders
if (inky.getPosition().x < 0){
Thread.sleep(/*a few sdeconds*/2000);/*Android studio would ask you about wrapping it with try - catch*/
inky.setPostion( x + /*screen x size*/,
inky.getPosition().y,inky.getPosition().z)/*add setter in ghost class*/
}
In fact, this is not the best way to do it, but the simplest one

Layer multiple components in JFrame

I am currently creating a platformer game with classes Level and Robot. The classes are incomplete, but here is the basic structure:
/**
* #(#)Robot.java
*
* Robot application
*
* #author
* #version 1.00 2015/5/15
*/
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Robot extends JComponent {
private int xPos;
private int yPos;
private boolean[] skills;
private boolean[][] collision;
final private int xa = 1; // Subject to Change
final private int ya = 1; // Subject to Change
private final int BLOCK_SIZE = 16;
public Robot() {
xPos = BLOCK_SIZE*5; // variables for sample level
yPos = BLOCK_SIZE*21 - 28;
}
/* Creates the Robot at the beginning of each stage
* Gives the robot skills it can use
* Robot receives map of where each block is for collision
* #startX and startY: block value
* #accessable and map: boolean arrays that are filled
*/
public Robot(int startX, int startY, boolean[] accessable, boolean[][] map) {
xPos = startX;
yPos = startY;
skills = accessable;
collision = map;
}
// Robot moves laterally right one block
public void moveRight() {
if (collision[yPos][xPos + 1] == false) {
xPos += xa;
}
}
// Robot moves laterally left one block
public void moveLeft() {
if (collision[yPos][xPos - 1] == false) {
xPos -= xa;
}
}
// Robot moves vertically up certain distance
public void Jump() {
if (skills[0] == true && collision[yPos - 1][xPos] == false) {
yPos -= ya;
}
}
// Returns x-position of the robot in block number
public int getX() {
return xPos;
}
// Returns y-Position of the robot in block number
public int getY() {
return yPos;
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Image robot = Toolkit.getDefaultToolkit().getImage("RobotRight.png"); // robot
g2.drawImage(robot, 28, 28, this);
}
}
The stage is as follows:
/**
* #(#)SampleLevel.java
*
*
* #author
* #version 1.00 2015/5/15
*/
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class SampleLevel extends JComponent /*implements Environment*/ {
// variables to determine size of blocks being used
private final int BLOCKS_IN_ROW = 40;
private final int BLOCKS_IN_COLUMN = 30;
private final int BLOCK_SIZE = 16;
// the y-value when the black meet the tiles
private final int TILE_BORDER = 21;
public SampleLevel() {
}
// work in progress, method may not be needed
public void fill() {
;
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Image img1 = Toolkit.getDefaultToolkit().getImage("BrickTile.jpg"); // the floor tile
Image img2 = Toolkit.getDefaultToolkit().getImage("SampleBackground1.jpg"); // black background
for (int i = 0; i < BLOCKS_IN_ROW; i++) {
for (int j = 0; j < TILE_BORDER; j++) {
g2.drawImage(img2, BLOCK_SIZE*i, BLOCK_SIZE*j, this);
g2.finalize();
}
}
for (int i = 0; i < BLOCKS_IN_ROW; i++) {
for (int j = TILE_BORDER; j < BLOCKS_IN_COLUMN; j++) {
g2.drawImage(img1, BLOCK_SIZE*i, BLOCK_SIZE*j, this);
g2.finalize();
}
}
// testing overlapping images
g2.drawImage(img1, BLOCK_SIZE*36, BLOCK_SIZE*16, this);
g2.drawImage(img1, BLOCK_SIZE*24, BLOCK_SIZE*13, this);
}
}
However, I want to add both of these components to a main Viewer class, but the JFrame cannot add two components. Does anyone know a way to layer the Robot component on top of the stage?
First of all you need to fix your Robot code. Basically the Robot image should always be painted at (0, 0). Then you need to treat your Robot like any Swing component which means you need to give is a size and location. The size would be the size of the image and the location can be variable as you move the Robot around the screen.
Then you need to add the Robot to the Stage.
Somewhere you need code that looks something like:
Robot robot = new Robot();
SampleLevel stage = new SampleLevel();
stage.add(robot);
frame.add(stage);
Now the frame will paint the stage and the state will paint the robot.
Also, you should not read the Robot image in the paintComponent() method. The image should be read once in the constructor. After you read the image you can then set the size of the robot based on the image size.

LibGdx-Blank Screen that can't be closed

I want to make a simple flappy bird clone while I'm in vacation(The firt time I try game programming since high school) so after looking at ligdx wiki and sort of adapting the code to fit my needs I had something like this:
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;
public class FlappyBall implements ApplicationListener {
Texture ballImage;
Texture chaoImage;
Texture canoImage;
OrthographicCamera camera;
SpriteBatch batch;
Rectangle ball;
int score = 0;
final float gravity = 9.0f;
#Override
public void create() {
ballImage = new Texture(Gdx.files.internal("crystalball_small.png"));
//chaoImage = new Texture(Gdx.files.internal("Flappy-Ground.png"));
camera = new OrthographicCamera(800,480);
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
ball = new Rectangle();
ball.x = 128;
ball.y = 20;
ball.width = 64;
ball.height = 64;
}
#Override
public void dispose() {
ballImage.dispose();
//chaoImage.dispose();
}
#Override
public void render() {
// cleans the screen
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// rendenring ball
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(ballImage, ball.x, ball.y);
batch.end();
// jump(not tested)
if (Gdx.input.isTouched()) {
ball.y += 10;
}
// apply gravity(not tested)
while (ball.y < 480)
ball.y -= gravity * Gdx.graphics.getDeltaTime();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
however this code ends up showing a blank screen that can't even be closed when I press the X button(in order to close it I need to terminate its process in eclipse or use the xkill command :/)
Ps.:That's my Main.java file:
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
public class Main {
public static void main(String[] args) {
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "Flappy Ball";
cfg.useGL20 = false;
cfg.width = 800;
cfg.height = 480;
new LwjglApplication(new FlappyBall(), cfg);
}
}
Ps².:The compiler shows no errors when this code is being executed
Thanks :D
Your render method will probably never finish it's first frame. The while loop will keep going until ball.y becomes greater than or equal to 480. This will never happen because you are subtracting a positive number.
while (ball.y < 480)
ball.y -= gravity * Gdx.graphics.getDeltaTime();
I would rather change it in something like this:
float change = gravity * Gdx.graphics.getDeltaTime();
if(ball.y - change >= 0)
ball.y -= change;

My for loop doesnt appear to run in my paint method

so im building brick breaker on Java and so far I have most of the UI done but Im having an issue with showing my bricks on my UI. I have written the code for it in my paint method which builds my panel and then my panel is added to a JFrame in another class. Everything shows except for my bricks and I cant seem to figure out why..
// AnimationPanel.java
//
// Informatics 45 Spring 2010
// Code Example: Our Ball Animation Becomes a Game
//
// This is relatively similar to our AnimationPanel in the previous version
// of our ball animation, with two changes:
//
// * The paddle is now drawn, in addition to just the ball. For fun, I've
// drawn the paddle in a different color than the ball.
//
// * This panel has a MouseMotionListener attached to it. The job of a
// MouseMotionListener is to listen for mouse movement within a component.
// In this case, any mouse movement within our AnimationPanel will turn
// into events, which we'll handle by adjusting the center x-coordinate
// of the paddle accordingly.
//
// * Because we need to calculate a new position for the paddle as the mouse
// moves, we'll need to be able to convert coordinates in both directions
// (i.e., fractional coordinates to pixel coordinates and pixel coordinates
// to fractional coordinates).
package inf45.spring2010.examples.animation2.gui;
import inf45.spring2009.examples.animation2.model.Animation;
import inf45.spring2009.examples.animation2.model.AnimationState;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AnimationPanel extends JPanel
{
private Animation animation;
private inf45.spring2009.examples.animation2.model.AnimationState currentState;
boolean brickVisible[][];
int bricksInRow = 4;
int bricksInColumn = 8;
int brickWidth;
int brickHeight;
int bricksLeft;
public AnimationPanel(Animation animation)
{
this.animation = animation;
currentState = null;
setBackground(Color.WHITE);
addMouseMotionListener(
new MouseMotionAdapter()
{
public void mouseMoved(MouseEvent e)
{
updatePaddlePosition(e.getX());
}
});
}
public void updateState(AnimationState newState)
{
currentState = newState;
}
private void updatePaddlePosition(int pixelX)
{
double paddleCenterX = convertPixelXToX(pixelX);
animation.updatePaddleCenterX(paddleCenterX);
}
public void paint(Graphics g)
{
super.paint(g);
if (currentState == null)
{
return;
}
int centerPixelX = convertXToPixelX(currentState.getBallCenterX());
int centerPixelY = convertYToPixelY(currentState.getBallCenterY());
int radiusX = convertXToPixelX(currentState.getBallRadius());
int radiusY = convertYToPixelY(currentState.getBallRadius());
int topLeftPixelX = centerPixelX - radiusX;
int topLeftPixelY = centerPixelY - radiusY;
int paddleCenterPixelX = convertXToPixelX(currentState.getPaddleCenterX());
int paddleCenterPixelY = convertYToPixelY(currentState.getPaddleCenterY());
int paddleWidthPixels = convertXToPixelX(currentState.getPaddleWidth());
int paddleHeightPixels = convertYToPixelY(currentState.getPaddleHeight());
int paddleTopLeftPixelX = paddleCenterPixelX - (paddleWidthPixels / 2);
int paddleTopLeftPixelY = paddleCenterPixelY - (paddleHeightPixels / 2);
Graphics2D g2d = (Graphics2D) g;
/* for (int x = 0;x<bricksInRow;x++){
for (int y = 0;y<bricksInColumn;y++){
boolean bricks[][] = null;
brickVisible[x][y] = bricks[x][y] ;
{
g2d.setColor(Color.black);
g2d.fillRect(x*brickWidth,y*brickHeight,brickWidth-1,brickHeight-1);
}
}
}
*/
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.BLUE);
g2d.fillOval(topLeftPixelX, topLeftPixelY, radiusX * 2, radiusY * 2);
g2d.setColor(Color.RED);
g2d.fillRect(
paddleTopLeftPixelX, paddleTopLeftPixelY,
paddleWidthPixels, paddleHeightPixels);
}
private int convertXToPixelX(double x)
{
return (int) (x * getWidth());
}
private int convertYToPixelY(double y)
{
return (int) (y * getHeight());
}
private double convertPixelXToX(int pixelX)
{
return (double) pixelX / getWidth();
}
}
It seems like you don't assign any value to brickHeight and brickWidth in your code. This might be the problem.
What MByD said, although as these fields are package-local you could possibly be setting these elsewhere. Also, there is also a NPE problem here:
boolean bricks[][] = null;
brickVisible[x][y] = bricks[x][y] ;
I'm not sure if you added this in before or after you found things weren't working, but this is a sure-fire NullPointerException which will cause the rest of your paint code to not execute when thrown.
EDIT: I'm assuming you commented out the code that wasn't working, but this is the bit you want to make work.

Categories

Resources