I am trying to make a space ship (PlayerShip.gif) in my game move left, right, up, and down when the coresponding keys are pressed. I know i need an keyboardListener but im having issues figuring out where it goes and how it is actually implimented. my code is as follows.
public class GamePanel extends JPanel implements KeyListener {
Timer timer1;
Timer timer2;
ArrayList<Ships> ship;
int x;
int y;
double speed;
int size;
int shipxCoord;
int shipyCoord;
int shipHeight;
int shipWidth;
int shipRise;
int shipRun;
boolean left = false;
boolean right = false;
boolean up = false;
boolean down = false;
Image enemyShip1;
Image enemyShip2;
Image playerShip;
ImageIcon ic = new ImageIcon("Ship.gif");
ImageIcon ic2 = new ImageIcon("Ship2.gif");
int width = ic.getIconWidth();
int height = ic.getIconHeight();
Image background = Toolkit.getDefaultToolkit().createImage("background.jpg");
public GamePanel(int size, double speed) {
super();
x = 450;
y = 510;
ship = new ArrayList<Ships>();
// call timer for 1st type of enemy Ship with a delay of 5 seconds between ships
enemy1Timer(5);
// call timer for 2nd type of enemy Ship with a delay of 3 seconds between ships
enemy2Timer(3);
this.size = size;
this.speed = speed;
enemyShip1 = new ImageIcon("ship.gif").getImage();
enemyShip2 = new ImageIcon("ship2.gif").getImage();
playerShip = new ImageIcon("playerShip.gif").getImage();
// this.add(image);
} // end constructor
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, null);
for (Ships s : ship) {
s.paintComponent(g);
}
g.drawImage(playerShip, x, y, this);
//g.drawImage(enemyShip2,x,y,this);
}// end method paintComponent
public void move() {
for (Ships s : ship) {
s.moveship(this);
// s.detectCollision(ship);
}
if (left) {
x -= speed;
}
if (right) {
x += speed;
}
if (up) {
y -= speed;
}
if (down) {
y += speed;
}
if (x > getWidth() - size) {
x = getWidth() - size;
}
if (x < 0) {
x = 0;
}
if (y > getHeight() - size) {
y = getHeight() - size;
}
if (y < 0) {
y = 0;
}
}// end method move
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == e.VK_LEFT) {
left = true;
}
if (e.getKeyCode() == e.VK_RIGHT) {
right = true;
}
if (e.getKeyCode() == e.VK_UP) {
up = true;
}
if (e.getKeyCode() == e.VK_DOWN) {
down = true;
}
} // end method keyPressed
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == e.VK_LEFT) {
left = false;
}
if (e.getKeyCode() == e.VK_RIGHT) {
right = false;
}
if (e.getKeyCode() == e.VK_UP) {
up = false;
}
if (e.getKeyCode() == e.VK_DOWN) {
down = false;
}
}
public void enemy1Timer(int seconds) {
timer1 = new Timer();
timer1.schedule(new ShipSwarm1(), 1000, seconds * 1000);
}// end method enemy1Timer
class ShipSwarm1 extends TimerTask {
public void run() {
for (int Wave = 1; Wave > 0; Wave--) {
Ships enemy = new Ships(ic, enemyShip1);
ship.add(enemy);
}// end for
}// end method run
}// end class Enemy1Swarm
public void enemy2Timer(int seconds) {
timer2 = new Timer();
timer2.schedule(new ShipSwarm2(), 3000, seconds * 1000);
}// end method enemy1Timer
class ShipSwarm2 extends TimerTask {
public void run() {
for (int Wave = 1; Wave > 0; Wave--) {
Ships enemy = new Ships(ic2, enemyShip2);
ship.add(enemy);
}// end for
}// end method run
}
}
Take a look at this link for a game impelemented in Java and it does exactly what you are looking for. Key presses - up left right and down keys.
Its the famous 15-game
An excerpt from that,
private void processKeys(){
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(
new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e){
if(e.getID() == KeyEvent.KEY_PRESSED){
handleKeyPress(e.getKeyCode());
if(areThingsInPlace() && !dialogShown){
dialogShown = true;
JOptionPane.showMessageDialog(null,"Congratulations!!! YOU WIN!!");
System.exit(1);
}
}
return false;
}
});
}
The handleKeyPress() method for handling the arrow keys
private void handleKeyPress(int keyCode) {
int emptyIndex = findEmptyIndex();
int x = emptyIndex/SIZE;
int y = emptyIndex%SIZE;
switch (keyCode) {
case 37://LEFT KEY
if(y==SIZE-1) return;
doSwap(x,y,x,y+1);
break;
case 38://UP KEY
if(x==SIZE-1) return;
doSwap(x,y,x+1,y);
break;
case 39://RIGHT KEY
if(y==0) return;
doSwap(x,y,x,y-1);
break;
case 40://DOWN KEY
if(x==0) return;
doSwap(x,y,x-1,y);
break;
}
}
Also consider adding conrol over all eight (semi-) cardinal directions, as shown in this game. For greater flexibility, consider actions and key bindings, discussed here.
Related
I have created a game similar to snake in which the user is first prompted with a jpanel asking which difficulty they want, and whatever JButton they pick influences the size of the map as well as the delay between the snake movements. I have the map size working just fine, but the delay variable never seems to change. I suspect it has something to do with the way the timer is being casted, but I have no idea how to fix it. I am also wondering how when the program is first ran it seems some of the variables don't update, but the second time it is ran all of them are updated. Here is my class with the original variables and collision detection:
import java.util.Random;
import javax.swing.JLabel;
public class GameEngine extends JPanel implements ActionListener{
//creates the size of the panel as well as creating the resolution for all objects, including the players and food.
static final int sWidth = 600;
static final int sHeight = 600;
public static int size = 24;
static int objectSize = (sHeight*sWidth) / size;
public static int delay = 100;
final int playerX[] = new int[objectSize];
final int playerY[] = new int[objectSize];
int bodySize = 4;
int score = 0;
int appleX;
int appleY;
char direction = 'D';
boolean started = false;
Random random;
Timer timer;
boolean easy;
JLabel score1;
public static String difficulty;
GameEngine(){
random = new Random();
this.setPreferredSize(new Dimension(sWidth,sHeight));
this.setBackground(Color.black);
this.setFocusable(true);
this.addKeyListener(new UserMovement());
gameStart();
}
public void gameStart() {
newApple();
started = true;
timer = new Timer(delay,this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void drawHead(Graphics g) {
g.setColor(new Color(100,252,0));
g.fillRect(playerX[0], playerY[0], size, size);
}
public void draw(Graphics g) {
if(started) {
//draws the apples
g.setColor(Color.red);
g.fillOval(appleX, appleY, size, size);
for (int i = 0; i < bodySize; i++) {
if(i == 0) {
drawHead(g);
}
else {
g.setColor(new Color(60,180,0));
g.fillRect(playerX[i], playerY[i], size, size);
}
}
g.setColor(Color.white);
g.setFont(new Font("Bold", Font.BOLD, 20));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString("Score: " + score,(sWidth - metrics.stringWidth("Score: " + score))/2,g.getFont().getSize());
}
}
public void newApple(){
appleX = random.nextInt((int)(sWidth/size))*size;
appleY = random.nextInt((int)(sHeight/size))*size;
}
//moves the player by using and modifying their coordinates
public void move() {
for (int i = bodySize; i > 0; i--) {
playerX[i] = playerX[i-1];
playerY[i] = playerY[i-1];
}
switch(direction) {
case 'W':
playerY[0] = playerY[0] - size;
break;
case 'S':
playerY[0] = playerY[0] + size;
break;
case 'A':
playerX[0] = playerX[0] - size;
break;
case 'D':
playerX[0] = playerX[0] + size;
break;
}
}
public void checkFood() {
if(playerX[0] == appleX && playerY[0] == appleY)
{
bodySize++;
score++;
newApple();
}
}
public void checkCol() {
//checks for head collision with the body
for(int i = bodySize; i > 0; i--) {
if((playerX[0] == playerX[i]) && (playerY[0] == playerY[i])) {
started = false;
}
}
//checks if head touches any of the walls of the program
if(playerX[0] < 0) {
started = false;
}
if(playerX[0] > sWidth) {
started = false;
}
if(playerY[0] < 0) {
started = false;
}
if(playerY[0] > sHeight) {
started = false;
}
if(started != true) {
timer.stop();
}
}
public void actionPerformed(ActionEvent e){
if(started == true) {
move();
checkFood();
checkCol();
}
repaint();
}
public class UserMovement extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if(direction != 'D') {
direction = 'A';
}
break;
case KeyEvent.VK_RIGHT:
if(direction != 'A') {
direction = 'D';
}
break;
case KeyEvent.VK_UP:
if(direction != 'S') {
direction = 'W';
}
break;
case KeyEvent.VK_DOWN:
if(direction != 'W') {
direction = 'S';
}
break;
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
}
and here is the code calling and changing the delay and size variables:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class StartMenu extends JPanel {
StartMenu()
{
JButton easy = new JButton();
JButton hard = new JButton();
this.setPreferredSize(new Dimension(350,240));
this.setLayout(null);
this.setBackground(Color.black);
this.setFocusable(true);
easy.setBounds(75,40,200,40);
hard.setBounds(75,120,200,40);
this.add(easy);
this.add(hard);
easy.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
setVisible(false);
new SnakeStart();
GameEngine.size = 48;
GameEngine.delay = 140;
}
});
hard.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
setVisible(false);
new SnakeStart();
GameEngine.size = 24;
GameEngine.delay = 70;
}
});
}
}
I assume your GameEngine instance is created before the StartMenu action listeners are executed. If that assumption is correct, that means that GameEngine.timer with the default value of delay is created in the GameEngine constructor and is not updated after the delay is changed.
You need to make sure that you explicitly update your timer with the new delay value after StartMenu actions are called.
I am trying to make the sprite stop continuously moving. Right now, the code makes the sprite move in the direction indicated by the user through arrow keys without stopping. I want to press an arrow key and make the sprite move once (ex. 10 steps only) in that direction.
public class Contents extends JPanel implements ActionListener, KeyListener {
Timer t = new Timer(100, this);
private Image man;
int x=0, y=0;
public Contents() {
super.setDoubleBuffered(true);
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
#Override
public void paintComponent (Graphics g) {
super.paintComponent(g);
super.setBackground(Color.white);
ImageIcon ii = new ImageIcon("guy.png");
man = ii.getImage();
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(man, x, y, this);
}
double xv = 0;
double yv = 0;
public void move() {
x += xv;
y += yv;
}
public void up() {
yv = -1;
xv = 0;
}
public void down() {
yv = 1;
xv = 0;
}
public void left () {
xv = -1;
yv = 0;
}
public void right () {
xv = 1;
yv = 0;
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
//Collision for left and right walls
if (x==0) {
xv = 1;
}
else if (x==900-240) {
xv = -1;
}
// Collision for top and bottom walls
if (y==0) {
yv = 1;
}
else if (y==600-320) {
yv = -1;
}
move();
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
up();
}
if (code == KeyEvent.VK_DOWN) {
down();
}
if (code == KeyEvent.VK_LEFT) {
left();
}
if (code == KeyEvent.VK_RIGHT) {
right();
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
}
It works when I delete the boundaries under ActionEvent. The boundaries prevent the sprite from going off screen. But I want to keep the boundaries and control the sprite too.
I figured it out. Under keyReleased, set xv=0. Then when you release the arrow key, the sprite will stop moving.
Brand new to this forum. Tried to learn Java by tutorials for a while, which have worked fine until now when I'm playing around with Swing making a Pong game..
My problem is that when I try to change level in my game my player's keylistener stops working.
I have tried to remove all unnecessary code, hopefully I haven't missed any that causes confusion.
This is what happens in my Main-class, where Data is basically a JPanel working as my background and Player is Another JPanel, I'll get to the Player-class after main.
public class Main {
Data data = new Data(Color.RED);
Player player = new Player(700, 500, 20, 100);
public Main() throws InterruptedException{
run(data, player);
ballRecursive();
}
public void run(Data data) throws InterruptedException {
frame.add(player, BorderLayout.WEST);
frame.add(data, BorderLayout.CENTER);
}
public void ballRecursive() throws InterruptedException {
if(playerScore.returnScore()==1){
Data data = new Data(Color.GREEN);
run(data);
}
This is my Player, tried to remove anything unnecessary here aswell:
public class Player extends JPanel implements ActionListener, KeyListener{
Timer timer = new Timer(5, this);
double yPos = 0, movementY = 0;
int squareSize = 60;
int yBound;
public Player(int w, int h, int width, int height) {
timer.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
yBound = (windowHeight - squareSize);
}
public void actionPerformed(ActionEvent e) {
yPos += movementY;
if (yPos < 0) {
yPos = 0;
} else if (yPos + squareSize > yBound) {
yPos = yBound - squareSize;
}
repaint();
}
public void moveUp()
{
if (yPos == 0)
{
movementY = 0;
}
movementY = -1;
}
public void moveDown()
{
if (yPos == yBound)
{
movementY = 0;
}
movementY = 1;
}
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP) {
moveUp();
}
if (keyCode == KeyEvent.VK_DOWN) {
moveDown();
}
}
public void keyReleased(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP)
{
movementY = 0;
}
if (keyCode == KeyEvent.VK_DOWN)
{
movementY = 0;
}
I transferred a few programs from a computer at my school(a mac) at school to my home pc. Once on my computer, I noticed the keys now do not work in each program. I've spent hours try to figure out why KeyPressed isn't working. Both computers used Eclipse
Is it because of different Java version or because of a different OS?
Thank you!
example of code:
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.text.DecimalFormat;
import java.util.Random;
import javax.swing.JApplet;
public class Skeleton extends JApplet implements Runnable, MouseMotionListener, MouseListener, KeyListener {
Random generator = new Random();
boolean GameRunning = true, PlayAgain = true;
int width, height;
int score = 0;
Image offscreenImage;
int XX;
int XY;
Image Cart;
Image candy[];
int candyX[];
int candyY[];
boolean up = false, down = false, left = false, right = false;
boolean candyRemaining[];
Graphics offscr;
Random r;
Thread t;
boolean inBounds = true;
boolean onScreen = true;
Image Title;
boolean hasStarted = false;
public Skeleton() {
r = new Random();
t = new Thread(this);
t.start();
}
public void init() {
XX = 0;
XY = 0;
candy = new Image[3];
candyRemaining = new boolean[3];
candyY = new int[3];
candyX = new int[3];
addKeyListener(this);
addMouseMotionListener(this);
addMouseListener(this);
setVisible(true);
setSize(500, 500);
width = getSize().width;
height = getSize().height;
Title = getImage(getCodeBase(), "BKG.png");
offscreenImage = createImage(width, height);
// offscr = offscreenImage.getGraphics();
Cart = getImage(getCodeBase(), "Untitled-1.png");
candy[0] = getImage(getCodeBase(), "candy1.png");
candy[1] = getImage(getCodeBase(), "candy2.png");
candy[2] = getImage(getCodeBase(), "candy3.png");
candyRemaining[0] = true;
candyRemaining[1] = true;
candyRemaining[2] = true;
candyX[0] = 100;
candyX[1] = 300;
candyX[2] = 400;
candyY[0] = 425;
candyY[1] = 0;
candyY[2] = 210;
}
public void paint(Graphics g) {
super.paint(g);
DecimalFormat df = new DecimalFormat("0.00");
Random generator = new Random();
if (hasStarted) {
if (inBounds) {
g.drawImage(Cart, XX, XY, this);
this.Candy(g);
if (left) {
XX -= 5;
if (XX < 0) {
XX += 5;
}
}
if (right) {
XX += 5;
if (XX > 500) {
XX -= 5;
}
}
if (down) {
XY += 5;
if (XX > 500) {
XY -= 5;
}
}
if (up) {
XY -= 5;
if (XY < 0) {
XY += 5;
}
}
} else {
GameRunning = false;
}
} else {
g.drawImage(Title, 0, 0, this);
}
}
public void Candy(Graphics g) {
for (int count = 0; count < 3; count++) {
if (candyRemaining[count]) {
g.drawImage(candy[count], candyX[count], candyY[count], this);
if (candyX[count] < XX + 50 && candyX[count] + 50 > XX) {
if (candyY[count] < XY + 50 && candyY[count] + 50 > XY) {
System.out.println(count);
candyRemaining[count] = false;
}
}
}
}
}
public void update(Graphics g) {
paint(g);
}
public void run() {
while (PlayAgain == true) {
while (GameRunning == true) {
repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
};
}
if (GameRunning == false) {
}
}
}
public void mouseDragged(MouseEvent ev) {
}
public void mouseMoved(MouseEvent ev) {
}
public void mouseClicked(MouseEvent ev) {
if (!hasStarted) {
hasStarted = true;
}
if (GameRunning == false) {
if (ev.getX() > 0 && ev.getX() < 1000 && ev.getY() > 0 && ev.getY() < 1000) {
GameRunning = true;
}
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
onScreen = true;
inBounds = true;
}
public void mouseExited(MouseEvent ev) {
onScreen = false;
inBounds = false;
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Pressed");
int key = e.getKeyCode();
if (key == e.VK_A) {
left = true;
}
if (key == e.VK_D) {
right = true;
}
if (key == e.VK_S) {
down = true;
}
if (key == e.VK_W) {
up = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("Released");
int key = e.getKeyCode();
if (key == e.VK_A) {
left = false;
}
if (key == e.VK_D) {
right = false;
}
if (key == e.VK_S) {
down = false;
}
if (key == e.VK_W) {
up = false;
}
}
#Override
public void keyTyped(KeyEvent e) {
}
}
Don't use the object e for your keycodes, use the static KeyEvent class. In addition your code will look prettier if you use a switch statement instead of if statements:
switch (e.getKeyCode()) {
case KeyEvent.VK_A: // here's the change
left = true;
break;
For comparing the keypressed or released you are using the current KeyEvent class's object.
As everytime the key is pressed the new KeyEvent object is created and for keypressed you are checking with the current object which doesn't hold the keyvalue, it just hold's that which key was pressed.
So to check refer to the static variables of the KeyEvent Class.
switch(e.getKeyCode){
case: KeyEvent.VK_A;
Left =false;
break;
case: KeyEvent.VK_D;
right=false;
break;
.
.
.
.
}
KeyListener is nutritiously fickle about focus. A KeyListener can only be notified of key events when the component is focusable and has focus
The short answer would be to use
setFocusable(true);
requestFocusInWindow();
at the end of the init method
The more appropriate answer would be to use key bindings API, which provides you with the ability to control the level of focus required in order to generate key events
As a side note, it would be more appropriate to use something like a JPanel and override it's paintComponent and use it as the primary gaming component instead of the JApplet, which isn't double buffered and can flash when it's updated...
You should also move you gaming logic out of your paint method and probably into you main gaming loop (or called from your gaming loop). A paint cycle could be called at any time, many times outside of your control, which could effect your output.
I also doubt you need 500fps, Thread.sleep(40); or even Thread.sleep(16); will probably give you far more stable results
I want to creat a circle in on a panel which appears and dissapears every 2 seconds.
Here is that i have:
public class Board extends JPanel implements ActionListener {
private final int DELAY = 2000;
private Timer timer;
/*
* constructor
*/
public Board() {
setFocusable(true);
initGame();
}
/*
* initialize board
*/
public void initGame() {
timer = new Timer(DELAY, this);
timer.start();
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.gray);
// draw an oval starting at 20,20 with a width and height of 100 and
// fill it
g.drawOval(20, 20, 100, 100);
g.fillOval(20, 20, 100, 100);
g.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
thank you guys. Now I wanna control my circle. But again something is wrong and it is not moving as I want.
here are new methods:
private boolean left = false;
private boolean right = true;
private boolean up = false;
private boolean down = false;
private Timer timer;
public int x = 20;
public int y = 20;
public int x2 = 100;
public int y2 = 100;
...
public void paint(Graphics g) {
super.paint(g);
if (drawCircle) {
g.setColor(Color.gray);
// draw an oval starting at 20,20 with a width and height of 100 and
// fill it
g.drawOval(x, y, x2, y2);
g.fillOval(x, y, x2, y2);
}
// removes native non-Java recourses
g.dispose();
}
public void move() {
if (left) {
x -= 5;
}
if (right) {
x += 5;
}
if (up) {
y -= 5;
}
if (down) {
y += 5;
}
}
#Override
public void actionPerformed(ActionEvent e) {
move();
repaint();
}
private class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!right)) {
left = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!left)) {
right = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_UP) && (!down)) {
up = true;
right = false;
left = false;
}
if ((key == KeyEvent.VK_DOWN) && (!up)) {
down = true;
right = false;
left = false;
}
}
}
/****/
Solved , i just added
addKeyListener(new TAdapter());
to my Board constructor!
You just need to have your Timer modify some state. Try something like this:
private boolean drawCircle = false;
public void actionPerformed(ActionEvent e) {
drawCircle = !drawCircle;
repaint();
}
public void paintComponent(Graphics g) {
//...
if ( drawCircle ) {
g.setColor(Color.gray);
//...
}
}
Aren't you supposed to formulate the question... as a question?
Anyway, add a boolean to your class, toggle it on each action event, and paint the oval only if it is true.
Edit/Notes:
- Override paintComponent instead of paint
- Don't dispose of a Graphics you haven't created. Either drop the line, or use g.create() to make a copy. See http://java.sun.com/products/jfc/tsc/articles/swing2d/ for details.