I am creating a game in java. In it, you control a square that follows your mouse. I want to implement collision detection for the square so that it stops slightly within the JFrame and not at the edge. This is very easy when doing this with the arrow keys, but I can't figure it out with the mouseMoved method. Here is the code where the mouseMoved method is:
public void mouseMoved(MouseEvent e){
repaint();
if(e.getX() <= 0)
playerX = 0;
if(e.getX() >= 300)
playerX = 500;
if(e.getY() <= 0)
playerY = 0;
if(e.getY() >= 300)
playerY = 500;
else
playerX = e.getX()-25;
playerY = e.getY()-25;
repaint();
}
Here's the code where the square is created:
public void paintComponent(Graphics g) {
Rectangle player = new Rectangle(playerX, playerY, 50, 50);
g.setColor(Color.blue);
g.fillRect(player.x, player.y, player.width, player.height);
repaint();
}
I don't think you'll need this, but just in case, here's all the code for the GamePanel class, which serves as the panel for my JFrame in the Main class. If you need the Main class let me know but I doubt you will:
package main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable{
//Global variables
//Double buffering
private Image dbImage;
private Graphics dbg;
//JPanel variables
static final int GWIDTH = 500, GHEIGHT = 500;
static final Dimension gameDim = new Dimension(GWIDTH, GHEIGHT);
//Game variable
private Thread game;
private volatile boolean running = false;
public boolean mouseClicked = false;
//Character variables
int playerX = 150, playerY = 150;
public class Mouse extends MouseAdapter{
public void mousePressed(MouseEvent e){
mouseClicked = true;
}
public void mouseReleased(MouseEvent e){
mouseClicked = false;
}
public void mouseMoved(MouseEvent e){
repaint();
if(e.getX() <= 0)
playerX = 0;
if(e.getX() >= 300)
playerX = 500;
if(e.getY() <= 0)
playerY = 0;
if(e.getY() >= 300)
playerY = 500;
else
playerX = e.getX()-25;
playerY = e.getY()-25;
repaint();
}
}
public GamePanel(){
addMouseMotionListener(new Mouse());
setPreferredSize(gameDim);
setBackground(Color.BLUE);
setFocusable(true);
requestFocus(true);
}
public void run(){
while(running){
}
}
public void addNotify(){
super.addNotify();
startGame();
}
private void startGame(){
if(game == null || !running){
game = new Thread(this);
game.start();
running = true;
}
}
public void stopGame(){
if(running){
running = false;
}
//Paint method
}
public void paint(Graphics g){
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
Rectangle player = new Rectangle(playerX, playerY, 50, 50);
g.setColor(Color.blue);
g.fillRect(player.x, player.y, player.width, player.height);
repaint();
}
private void log(String s){
System.out.println(s);
}
}
Thank you for your help. Please let me know if you need anything.
Your movement code is a bit off. You set the x position only if the Y is not out of bounds and always replace the Y value. Can I suggest full blocks in future - they help avoiding problems like this.
playerX = e.getX()-25;
playerY = e.getY()-25;
if(e.getX() <= 0){
playerX = 0;
}
else if(e.getX() >= 300){
playerX = 500;
}
if(e.getY() <= 0){
playerY = 0;
}
else if(e.getY() >= 300){
playerY = 500;
}
This sets the position first and then corrects it if the player is out of the bounds.
Related
I have been trying my best to work out collision detection between Pacman and the walls, however my implementation doesn't seem to work as correctly
Does collision detection work at all? Yes
Does it behave correctly? No
How is it currently behaving? When you hit a wall it stops Pacman
from moving which is okay, however any new key presses to move only changes
the images axis (up, right, down or left depending on key press),
it will not move the Pacman beyond its current location after hitting the wall.
Any assistance would be greatly appreciated. thanks in advance
GamePanel.java
package pacman;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable{
private Thread animator;
private boolean isRunning;
private Map map = new Map();
public GamePanel(){
this.setBackground(Color.BLACK);
this.setDoubleBuffered(true);
addKeyListener(new TAdapter());
setFocusable(true);
}
#Override
public void run() {
isRunning = true;
System.out.println("Is running? "+isRunning);
long startTime, timeDiff, sleepTime;
startTime = System.currentTimeMillis();
while(isRunning){
repaint();
gameUpdate();
timeDiff = System.currentTimeMillis() - startTime;
sleepTime = 5 - timeDiff;
try{
Thread.sleep(sleepTime);
}
catch(InterruptedException ex){
System.exit(0);
}
startTime = System.currentTimeMillis();
}
// gameOver(); not implemented yet, will focus on this when I have some basic animation and the game loop working to satisfaction.
}
#Override
public void addNotify(){
super.addNotify();
startGame();
}
public void startGame(){
if(animator == null || !isRunning){
animator = new Thread(this);
animator.start();
}
} //end of StartGame method
public void gameUpdate(){
map.getPlayer().move();
checkCollision();
} //implementation of ingame updates such as pacman getting killed.
public void checkCollision(){ //this is where I officially set collision up
for(int i = 0; i < map.tiles.length; i++){
for(int j = 0; j < map.tiles.length; j++){
if(map.tiles[i][j] != null){
if(map.getPlayer().getPlayerBox().intersects(map.tiles[i][j].getR())){
map.getPlayer().setColliding(true);
System.out.println("OWW"+map.tiles[i][j].getR().getLocation());
}
}
}
}
}
public void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g);
if(isRunning){
drawDot(g2d);
drawPlayer(g2d);
map.drawMap(g2d);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void drawDot(Graphics2D g){
g.setColor(Color.GREEN);
for(int x= 0; x < 400; x++){
for(int y = 0; y < 400; y++){
g.drawRect(x * 20, y * 20, 1, 1);
}
}
}
public void drawPlayer(Graphics2D g){
g.drawImage(map.getPlayer().getImage(), map.getPlayer().getX(),map.getPlayer().getY(), this);
}
private class TAdapter extends KeyAdapter{
#Override
public void keyPressed(KeyEvent e) {
map.getPlayer().keyPressed(e);
}
#Override
public void keyReleased(KeyEvent e) {
map.getPlayer().keyReleased(e);
}
}
}
Player.java
package pacman;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class Player extends Commons{
private int dx, dy;
private int speed = 1;
private static int playerWidth = 52; //these figures seem off, but that is because the image is not designed correctly or the pacman image is not obeying the logic of not going passed the frame size.
private static int playerHeight = 82;
private Rectangle playerBox;
private Image playerImg = new ImageIcon(Player.class.getResource("Pacman.png")).getImage();
private Image playerImgUp = new ImageIcon(Player.class.getResource("PacmanUp.png")).getImage();
private Image playerImgLeft = new ImageIcon(Player.class.getResource("PacmanLeft.png")).getImage();
private Image playerImgDown = new ImageIcon(Player.class.getResource("PacmanDown.png")).getImage();
private boolean isColliding = false;
public Player(){
this.setX(320);
this.setY(280);
playerBox = new Rectangle(this.getX(), this.getY(),40,40);
}
public void setSpeed(int sp){
speed = sp;
}
public Image getImage(){
if(dy == 1){
return playerImgDown;
}
else if(dy == -1){
return playerImgUp;
}
else if(dx == -1){
return playerImgLeft;
}
else
return playerImg;
}//Responsible for displaying pacman image based on direction of pacman's movement.
void move(){
int x = this.getX();
int y = this.getY();
/*
* This is the part where I am trying to implement some degree of logic to stop it from moving
*/
if(isColliding == false){
this.setX(x += dx);
playerBox.setLocation(x, y);
this.setY(y += dy);
}else if(isColliding == true){
this.setColliding(false);
this.setX(this.getX());
this.setY(this.getY());
}
if (this.getX() <= 1) {
this.setX(1);
}
if (this.getX() >= 400 - playerWidth) {
this.setX(400 - playerWidth);
}
if (this.getY() <= 2) {
this.setY(2);
}
if (this.getY() >= 400 - playerHeight ) {
this.setY(400 - playerHeight);
}
}//Most simplist form of collision detection, stops pacman from leaving the JFrame
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_LEFT ){
dx = -speed;
dy = 0;
}
if(key == KeyEvent.VK_RIGHT){
dx = speed;
dy = 0;
}
if(key == KeyEvent.VK_UP){
dx = 0;
dy = -speed;
}
if(key == KeyEvent.VK_DOWN){
dx = 0;
dy = speed;
}
if(key == KeyEvent.VK_ESCAPE){
System.exit(0);
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_LEFT){
dy = 0;
}
if(key == KeyEvent.VK_RIGHT){
dy = 0;
}
if(key == KeyEvent.VK_UP){
dx = 0;
}
if(key == KeyEvent.VK_DOWN){
dx = 0;
}
}//end of key release
public Rectangle getPlayerBox() {
return playerBox;
}
public void setPlayerBox(Rectangle playerBox) {
this.playerBox = playerBox;
}
public boolean isColliding() {
return isColliding;
}
public void setColliding(boolean isColliding) {
this.isColliding = isColliding;
}
}// end of class
It looks like what happens is the player enters a tile which causes collision and isColliding is set to true.
The next iteration of the game update calls movement code which checks the player's isColliding boolean. That condition is true and no movement occurs. Next, collision is checked and we haven't moved out of the tile causing the collision so we are stuck in this tile.
I suggest when collision happens to move the player just out of the colliding tile.
We know which direction the player is moving so we can use the inverse direction (multiply dx and dy by -1) to move the player out of the colliding tile.
I've tried every solution I could find here and on forums but I cannot close the wind JFrame no matter what I do and I have no idea why. I need to dispose of the JFrame and launch a different one by creating a WarioWareGUI object.
Right now, the best I seem to be able to do is stop the ball from moving and just leave the old JFrame in the background, but that's not quite good enough. I need the wind JFrame to close
I've tried infinitely disposing, I've tried setting the JFrame as public static and initializing it as an object of BallGame so that I can dispose from anywhere. I've tried simply disposing it immediately after creating it. Nothing seems to get rid of it.
I even tried just setting the ball speed to 0 and making the frame invisible but wind.setVisible(false); doesn't do anything either.
package GameProject;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public final class BallGame extends JComponent implements ActionListener, MouseMotionListener, KeyListener {
private int ballx = 150;
private int bally = 30;
private int paddlex = 0;
private static int ballySpeed = 7;
private static int ballxSpeed = 5;
private int score = 0;
private int round = 1;
private int bounces = 0;
private static int delay = 20;
public static boolean gameOver = false;
public static boolean gameOverFlag = false;
public boolean started;
public static void main(int round) {
//only true the first time the game is run
if ((gameOver == false) && (gameOverFlag == false)) {
gameMake(round);
}
//only true after the game has resulted in a loss
if ((gameOver == true) && (gameOverFlag==true)) {
gameOver = false;
//gameMake(round);
WarioWareGUI gui = new WarioWareGUI();
}
//only true after the game has resulted in a loss and
//returned to main menu
if ((gameOver == false) && (gameOverFlag==true)) {
}
}
public static void gameMake(int round) {
JFrame wind = new JFrame("RedBall/GamePinfo");
BallGame g = new BallGame();
wind.add(g);
wind.pack();
wind.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
wind.setLocationRelativeTo(null);
wind.setVisible(true);
wind.addMouseMotionListener(g);
wind.dispose();
//speed up the timer each round
Timer tt = new Timer(delay, g);
tt.start();
}
public void newball(int ballx, int bally, int ballxspeed, int ballyspeed) {
ballx = 150;
bally = 30;
ballxspeed = 5;
ballyspeed = 7;
JOptionPane.showMessageDialog(null, "new ball !");
return;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
#Override
protected void paintComponent(Graphics g) {
//draw the sky
g.setColor(Color.cyan);
g.fillRect(0, 0, 800, 600);
g.setColor(Color.GREEN);
g.fillRect(0, 550, 800, 100);
//draw the paddel
g.setColor(Color.black);
g.fillRect(paddlex, 500, 100, 20);
//draw the ball
g.setColor(Color.RED);
g.fillOval(ballx, bally, 30, 30);
g.setColor(Color.white);
g.setFont(new Font("Arial", 8, 50));
g.drawString(String.valueOf(score), 30, 80);
}
#Override
public void actionPerformed(ActionEvent e) {
//Manages ball movement
ballx = ballx + ballxSpeed;
bally = bally + ballySpeed;
if (gameOverFlag) {
round = 1;
BallGame.main(round);
}
else if (gameOver) {
gameOverFlag = true;
//displays the dialog box indicating victory
JOptionPane.showMessageDialog(this, "You lost on round"
+ round + "!");
ballx = 150;
bally = 30;
}
else if (bounces==10) {
//reset score
bounces = 0;
round++;
JOptionPane.showMessageDialog(this,"You Win! You move on to"
+ " round " + round + "!");
}
// Sets ball speed upward if it hits the paddle
else if (ballx >= paddlex && ballx <= paddlex + 100 && bally >= 475) {
ballySpeed = -7 - (round*2);
//monitors the number of times the ball is successfully hit
score++;
bounces++;
}
// Handles loss condition
else if (bally >= 500 ) {
gameOver = true;
}
// Sets ball movement down if it hits the ceiling
else if (bally <= 0) {
ballySpeed = 7 + (round*2);
}
// Sets ball
else if (ballx >= 775) {
ballxSpeed = -5 - (round*2);
}
// Window left
else if (ballx <= 0) {
ballxSpeed = 5 + (round*2);
}
//**********************************************************************
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
//places paddle in middle of mouse
paddlex = e.getX() - 50;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
I expect calling wind.dispose to shut down the GUI but it won't, no matter where I put it or how I declare the JFrame. I can't just make it invisible either.
The code right now is just where it was when I gave up, I'm not trying to just dispose of it right away of course, but once I can get it to just dispose once successfully, hopefully I can get it to do that at the right time.
I'm recreating the classic snake game. I've already finished coding the snake. What I have to do now is code the walls (that are supposed to be located at the edges of the frame).
As the painter of the snake "repaints" every 30 miliseconds, I thought it would not be really efficient to let this painter draw the walls as well, as the walls stay on the same place during the whole game so it isn't really necessary to redraw the walls every 30 miliseconds.
Thus, I was wondering whether it was possible to have two painters in my game, one that repaints the snake every 30 miliseconds, and one that paints only once (it paints the walls at the beginning of the game)? How should I do that?
These are the most important parts of the code related to the question (full code can be found below this):
//this is in the main class
public Snake(){
painter = new Painter(this);
this.add(painter, BorderLayout.CENTER);
this.setSize(500, 500);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.addKeyListener(this);
this.requestFocusInWindow();
timer = new Timer(30, this);
startGame();
}
public void startGame(){
snakeList = new LinkedList<Point>();
snakeList.addFirst(new Point(10, 10));
snakeSegments(3);
setFood(30, 30);
movementX = 0;
movementY = 0;
timer.start(); //timer triggers gameUpdate();
}
public void gameUpdate(){
snakeMove(movementX, movementY);
snakeInstructor();
snakeEat();
snakeCollision();
painter.repaint();
}
-
// this is in the painter class
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 500, 500);
paintSnake(g);
paintFood(g);
}
This is the full code:
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Snake extends JFrame implements KeyListener, ActionListener{
Painter painter;
LinkedList<Point> snakeList;
Timer timer;
Point foodLocation;
int direction;
int snakeSize;
int movementX, movementY;
public static void main(String[] arg){
new Snake();
}
public Snake(){
painter = new Painter(this);
this.add(painter, BorderLayout.CENTER);
this.setSize(500, 500);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.addKeyListener(this);
this.requestFocusInWindow();
timer = new Timer(30, this);
startGame();
}
public void startGame(){
snakeList = new LinkedList<Point>();
snakeList.addFirst(new Point(10, 10));
snakeSegments(3);
setFood(30, 30);
movementX = 0;
movementY = 0;
timer.start();
}
public void gameUpdate(){
snakeMove(movementX, movementY);
snakeInstructor();
snakeEat();
snakeCollision();
painter.repaint();
}
public void snakeCollision(){
for(int i = 4; i < getSnakeSize(); i++){
if(getFirst().equals(snakeList.get(i))){
gameOver();
}
}
}
public void gameOver(){
timer.stop();
}
public void snakeEat(){
if(getFirst().equals(getFood())){
newFood();
setSnakeSize();
snakeSegments(4);
}
}
public void snakeSegments(int i){
snakeSize = i;
while(snakeSize > 0){
snakeList.addLast(new Point(getLast()));
snakeSize--;
}
}
public void snakeInstructor(){
int currentDirection = getDirection();
if (currentDirection == 1){
snakeMove(-1, 0);
} else if (currentDirection == 2){
snakeMove(1, 0);
} else if (currentDirection == 3){
snakeMove(0, -1);
} else if (currentDirection == 4){
snakeMove(0, 1);
}
}
public void snakeMove(int directionX, int directionY){
snakeList.getFirst().x = snakeList.getFirst().x + directionX;
snakeList.getFirst().y = snakeList.getFirst().y + directionY;
for(int i = getSnakeSize()-1; i >=1; i--) {
snakeList.get(i).setLocation(snakeList.get(i-1));
}
}
public void newFood(){
Random generator = new Random();
int x = generator.nextInt(49);
int y = generator.nextInt(47);
setFood(x, y);
}
public void setFood(int x, int y){
foodLocation = new Point(x, y);
}
public Point getFood(){
return foodLocation;
}
public void setDirection(int newDirection){
direction = newDirection;
}
public int getDirection (){
return direction;
}
Point getFirst(){
return snakeList.getFirst();
}
Point getLast(){
return snakeList.getLast();
}
Point get(int i){
return snakeList.get(i);
}
public void addFirst(Point p){
snakeList.addFirst(p);
}
public void addLast(Point p){
snakeList.addLast(p);
}
public int getSnakeSize(){
return snakeList.size();
}
public void setSnakeSize(){
snakeSize = getSnakeSize() + 1;
}
#Override
public void actionPerformed(ActionEvent event) {
gameUpdate();
}
#Override public void keyReleased(KeyEvent e){ }
#Override public void keyTyped(KeyEvent e){ }
#Override public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
if((key == KeyEvent.VK_LEFT) && direction != 2){
setDirection(1);
} else if ((key == KeyEvent.VK_RIGHT) && direction != 1){
setDirection(2);
} else if ((key == KeyEvent.VK_UP) && direction != 4){
setDirection(3);
} else if ((key == KeyEvent.VK_DOWN) && direction != 3){
setDirection(4);
} else if (key == KeyEvent.VK_SPACE){
startGame();
}
}
}
-
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
public class Painter extends JPanel{
Snake snake;
public Painter(Snake snake){
this.snake = snake;
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 500, 500);
paintSnake(g);
paintFood(g);
}
public void paintSnake(Graphics g){
for(int i = 0; i < snake.getSnakeSize(); i++){
g.setColor(Color.WHITE);
Point p = snake.snakeList.get(i);
g.fillRect(p.x*10, p.y*10, 10, 10);
}
}
public void paintFood(Graphics g){
Point p = snake.getFood();
g.setColor(Color.RED);
g.fillRect(p.x*10, p.y*10, 10, 10);
}
}
Yes and no...
You could make the Painter transparent and overlay the snake on top of the walls, but the call to g.fillRect(0, 0, 500, 500); would make that redundant, as it fills the entire component with the current color...
Seen as the paintComponent method for both painters would be called every time you want to update the UI, it's also kind of pointless.
A better solution would be to render the map to BufferedImage and paint it inside the painter before painting the snake.
I've been having trouble with this for quite a while now
I am trying to make a space shooter but to no avail, I'm trying to make the bullet move across the screen like in space invaders etc
when the player presses the space bar a bullet should appear where the player's X position is and move right across the screen.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class game extends JFrame{
boolean run = true;
boolean fired = false;
Image player;
Image bullet;
int playerX = 100;
int playerY = 200;
int bulletX;
int bulletY;
public game(){
//Load Images:
ImageIcon playerI = new ImageIcon("C:/Users/Dan/workspace/shooterProject/bin/shooterProject/ship.png");
player = playerI.getImage();
ImageIcon bulletI = new ImageIcon("C:/Users/Dan/workspace/shooterProject/bin/shooterProject/bullet.png");
bullet = bulletI.getImage();
//Set up game
addKeyListener(new AL());
addMouseListener(new Mouse());
init();
}
private Image dbImage;
private Graphics dbg;
public static void main(String[] args) {
new game();
}
//When the program runs, thins are initialised here
public void init(){
windowManager();
}
public void paintComponent(Graphics g){
if(run == true){
g.drawImage(player, playerX, playerY, this);
}
if(fired == true){
g.drawImage(bullet, bulletX, bulletY, this);
}
repaint();
}
public void paint(Graphics g){
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage,0,0,this);
}
public void bullet(){
bulletX = playerX;
bulletY = playerY;
while(fired == true){
bulletX = bulletX + 10;
if(bulletX == 800){
bullet = null;
fired = false;
}
}
}
public void windowManager(){
JFrame f = new JFrame();
setTitle("Engine");
setVisible(true);
setResizable(false);
setSize(800,400);
setBackground(Color.BLACK);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public class AL extends KeyAdapter{
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if((keyCode == KeyEvent.VK_UP) && (run == true) && (playerY - 20 > 0)){
playerY = playerY - 10;
}else if((keyCode == KeyEvent.VK_DOWN) && (run == true) && (playerY + 20 < 400)){
playerY = playerY + 10;
}
if((keyCode == KeyEvent.VK_SPACE) && (fired == false)){
fired = true;
if(fired == true){
bullet();
}
}
}
public void keyReleased(KeyEvent e){
}
}
public class Mouse extends MouseAdapter {
public void mousePressed(MouseEvent e) {
double x = e.getX();
double y = e.getY();
}
}
}
HOWEVER
When I run the code without the while loop the bullet appears at the player's X position
but
When the while loop is there when the player presses the X button nothing happens, the bullet doesnt even appear!
would anybody be able to assist me in how i can make the bullet appear and move across the screen?
thanks
This is because you are not drawing the bullet until it's out of range, you should not use the while loop this way, you probably need to google for 'Game Loop' but until you do here is a snipet that may help, Note that very bad but should work:
public void paintComponent(Graphics g){
if(run == true){
g.drawImage(player, playerX, playerY, this);
if(fired == true) {
bulletX = bulletX + 10;
if(bulletX > 800 || bulletX < 0){
fired = false;
}
g.drawImage(bullet, bulletX, bulletY, this);
}
repaint();
}
}
public void bullet(){
bulletX = playerX;
bulletY = playerY;
}
one final note, move this code in the paint methode dbImage = createImage(getWidth(), getHeight()) to the constructor or the init() because you are creating a new image every frame.
I am following a series of tutorials for Java game development tutorials. I already have a basic knowledge of Java, from thenewboston, if that helps. Anyway, I was stuck on this tutorial: http://www.youtube.com/watch?v=hN1v1ZhITDc&feature=c4-overview-vl&list=PL54DB126285ED0420 The program I am creating for this tutorial is sort of like a 2D Minecraft, and at this point, the program should display a window with several tiles of dirt, stone, and sky in specific order. When I run it, it just displays a blank JFrame and I get these errors:
at mineGameMain.World.draw(World.java:80)
at mineGameMain.GamePanel.draw(GamePanel.java:91)
at mineGameMain.GamePanel.gameRender(GamePanel.java:85)
at mineGameMain.GamePanel.run(GamePanel.java:51)
at java.lang.Thread.run(Unknown Source)
I have three classes, Main:
package mineGameMain;
import javax.swing.JFrame;
public class Main extends JFrame{
GamePanel gp;
public Main(){
gp = new GamePanel();
setSize(500, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setResizable(false);
add(gp);
}
public static void main(String[] args){
Main m = new Main();
}
}
GamePanel:
package mineGameMain;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GamePanel extends JPanel implements Runnable{
//Double Buffering
private Image dbImage;
private Graphics dbg;
//JPanel variables
static final int GWIDTH = 500, GHEIGHT = 400;
static final Dimension gameDim = new Dimension(GWIDTH, GHEIGHT);
//Game Variables
private Thread game;
private volatile boolean running = false;
//Game Objects
World world;
public GamePanel(){
world = new World();
setPreferredSize(gameDim);
setBackground(Color.WHITE);
setFocusable(true);
requestFocus();
//Handle all key inputs
addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
}
public void keyReleased(KeyEvent e){
}
public void Typed(KeyEvent e){
}
});
}
public void run(){
while(running){
gameUpdate();
gameRender();
paintScreen();
}
}
private void gameUpdate(){
if(running && game != null){
//Update game state
}
}
private void gameRender(){
if(dbImage == null){
dbImage = createImage(GWIDTH, GHEIGHT);
if(dbImage == null){
System.err.println("dbImage IS STILL NULL SO SHUTUPBEQUIET!");
return;
}else{
dbg = dbImage.getGraphics();
}
}
//Clear the screen
dbg.setColor(Color.WHITE);
dbg.fillRect(0, 0, GWIDTH, GHEIGHT);
//draw Game Methods
draw(dbg);
}
/*Draw all game content in this method*/
private void draw(Graphics g) {
world.draw(g);
}
private void paintScreen(){
Graphics g;
try{
g = this.getGraphics();
if(dbImage != null && g != null){
g.drawImage(dbImage, 0, 0, null);
}
Toolkit.getDefaultToolkit().sync();
}catch(Exception e){
System.err.println(e);
}
}
public void addNotify(){
super.addNotify();
startGame();
}
private void startGame(){
if(game == null || !running){
game = new Thread(this);
game.start();
running = true;
}
}
public void stopGame(){
if(running){
running = false;
}
}
private void log(String s){
System.out.println(s);
}
}
And finally, World:
package mineGameMain;
import java.awt.Image;
import java.awt.*;
import javax.swing.ImageIcon;
public class World {
private Rectangle[] blocks;
private Image[] blockImg;
private final int arrayNum = 500;
//Block images
private Image BLOCK_DIRT_TOP, BLOCK_DIRT, BLOCK_STONE, BLOCK_SKY;
private int x, y;
public World(){
BLOCK_DIRT_TOP = new ImageIcon("/MineGame/src/mineGameMain/Tile_Grass.png").getImage();
BLOCK_DIRT = new ImageIcon("/MineGame/src/mineGameMain/Tile_Dirt.png").getImage();
BLOCK_STONE = new ImageIcon("/MineGame/src/mineGameMain/Tile_Stone.png").getImage();
BLOCK_STONE = new ImageIcon("/MineGame/src/mineGameMain/Tile_Sky.png").getImage();
blocks = new Rectangle[500];
blockImg = new Image[500];
loadArrays();
}
private void loadArrays(){
for(int i = 0; i < arrayNum; i++){
if(x >= 500){
x = 0;
y += 20;
}
if( i >= 0 && i < 100){
blockImg[i] = BLOCK_SKY;
blocks[i] = new Rectangle(x, y, 20, 20);
}
if( i >= 100 && i < 120){
blockImg[i] = BLOCK_DIRT_TOP;
blocks[i] = new Rectangle(x, y, 20, 20);
}
if( i >= 125 && i < 220){
blockImg[i] = BLOCK_DIRT;
blocks[i] = new Rectangle(x, y, 20, 20);
}
if( i >= 225 && i < 500){
blockImg[i] = BLOCK_STONE;
blocks[i] = new Rectangle(x, y, 20, 20);
}
x += 20;
}
}
public void draw(Graphics g){
for(int i = 0; i < arrayNum; i++){
g.drawImage(blockImg[i], blocks[i].x, blocks[i].y, null);
}
}
}
Thank you for your time. If I did something wrong by posting this or if I left out any details please let me know.
Find below a way to turn your question into an SSCCE (actually it is a fixed version of one)
There are quite a few mistakes you should avoid in your code
No need to implement double buffering yourself, Swing is double buffered by default
All access to the UI should be made on the EDT (the Event Dispacthing Thread), not from a random Thread you created. You should also start your UI from the EDT, using invokeLater
To paint a component, override paintComponent and invoke repaint() whenever you want it to be called.
Never use getGraphics on JComponent, always Graphics objects provided as method-arguments (like in paintComponent).
No need to extends JFrame here --> don't extend if you don't need to (you don't actually add behaviour to the JFrame)
Make sure to call setVisible(true) as your last statement for the JFrame.
You forgot to handle block 120 to 125 and block 220 to 225 (probably causing NullPointerException in your draw method (this is likely the root of your error).
When you post a Java error, make sure to post the whole stacktrace and the message provided above the stacktrace (make also sur that people can identify your line numbers, by adding a comment like // this is line 80 of the World class)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Main extends JFrame {
GamePanel gp;
public Main() throws MalformedURLException {
gp = new GamePanel();
setSize(500, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(gp);
pack();
setVisible(true);
}
public static class World {
private Rectangle[] blocks;
private Image[] blockImg;
private final int arrayNum = 500;
// Block images
private Image BLOCK_DIRT_TOP, BLOCK_DIRT, BLOCK_STONE, BLOCK_SKY;
private int x, y;
public World() throws MalformedURLException {
BLOCK_DIRT_TOP = new ImageIcon(new URL("http://i909.photobucket.com/albums/ac298/XxEnoAsaIxX/grass2test.png?t=1303852677"))
.getImage();
BLOCK_DIRT = new ImageIcon(new URL(
"http://i909.photobucket.com/albums/ac298/XxEnoAsaIxX/sparsedirtandgrasstile.png?t=1300172998")).getImage();
BLOCK_STONE = new ImageIcon(new URL("http://www.stonetilesupply.com/v/vspfiles/photos/MARBL-BTTCNCLASSICO-2S.jpg")).getImage();
BLOCK_SKY = new ImageIcon(new URL("http://lacoste.scene7.com/is/image/lacoste/swatch_10_CH0783-00_SVH_24?$swatch$")).getImage();
blocks = new Rectangle[500];
blockImg = new Image[500];
loadArrays();
}
private void loadArrays() {
for (int i = 0; i < arrayNum; i++) {
if (x >= 500) {
x = 0;
y += 20;
}
if (i >= 0 && i < 100) {
blockImg[i] = BLOCK_SKY;
blocks[i] = new Rectangle(x, y, 20, 20);
}
if (i >= 100 && i < 120) {
blockImg[i] = BLOCK_DIRT_TOP;
blocks[i] = new Rectangle(x, y, 20, 20);
}
// Here missing block for 120 to 125
if (i >= 120 && i < 125) {
blockImg[i] = BLOCK_STONE;
blocks[i] = new Rectangle(x, y, 20, 20);
}
if (i >= 125 && i < 220) {
blockImg[i] = BLOCK_DIRT;
blocks[i] = new Rectangle(x, y, 20, 20);
}
// Here missing block for 220 to 225
if (i >= 220 && i < 225) {
blockImg[i] = BLOCK_SKY;
blocks[i] = new Rectangle(x, y, 20, 20);
}
if (i >= 225 && i < 500) {
blockImg[i] = BLOCK_STONE;
blocks[i] = new Rectangle(x, y, 20, 20);
}
x += 20;
}
}
public void draw(Graphics g) {
for (int i = 0; i < arrayNum; i++) {
g.drawImage(blockImg[i], blocks[i].x, blocks[i].y, null);
}
}
}
public static class GamePanel extends JPanel {
// JPanel variables
// Game Objects
World world;
public GamePanel() throws MalformedURLException {
world = new World();
setPreferredSize(new Dimension(500, 400));
setBackground(Color.WHITE);
setFocusable(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
world.draw(g);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
new Main();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}