I have asked a question regarding this same program before. I solved the issues I had then, and I now have rooted out a different problem. When I run the code it shows a small blue box on the screen. It is supposed to move when you press the arrow keys and I have discovered that if you click the character and hold an arrow key for a moment then it will move. What I need is to make it refreshes the screen automatically, I believe I need an update() method for that, but I am not sure. If anybody can help me figure this out or improve my code in some way that would be helpful. I made some changes based off of some comments I received on my previous question.
CharacterTest.java:
import javax.swing.JFrame;
import java.awt.Graphics;
import javax.swing.JPanel;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.awt.BorderLayout;
import java.awt.Canvas;
//import java.awt.event.KeyEvent;
import java.awt.event.*;
public class CharacterTest extends JFrame{
public CharacterTest()
{
super("Character Test"); //instantiate a window to draw the character in
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //this will stop the program when it closes
setSize(800, 800); //create the window
MCharacter C = new MCharacter(); //call the box so that it can be affected
getContentPane().add(C); //draws the character on the window
setVisible(true); //show the window
while(C.determine(C.getX(), C.getY()) == false) //as long as the character is witin a particular area
{
if(C.getUpKey() == true) //if the up arrow key is pressed
{
C.up(); //set the y variable to a higher position
}
if(C.getDownKey() == true) //if the down arrow key is pressed
{
C.down(); //set the y variable to a lower positon
}
if(C.getRightKey() == true) //if the right arrow key is pressed
{
C.right(); //set the x variable ro a more right position
}
if(C.getLeftKey() == true) //if the left key is pressed
{
C.left(); //set the x variable to a more left position
}
repaint(); //repaint the character at a new position
try {
Thread.sleep(20);
}
catch (InterruptedException ex){
}
}
}
public static void main(String[] args) {
CharacterTest test = new CharacterTest(); //calls the method which creates the screeen, the character, and checks for key srokes
}
}
MCharacter.java:
import javax.swing.JFrame;
import java.awt.Graphics;
import javax.swing.JPanel;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.awt.BorderLayout;
import java.awt.Canvas;
//import java.awt.event.KeyEvent;
import java.awt.event.*;
public class MCharacter extends Canvas{
//these will be the instance variables for the character's parameters- its size and its location
private int width;
private int height;
private int x;
private int y;
//these will be turned true if the corresponding key is pressed - defined in the private class line 132
private boolean leftKey = false;
private boolean rightKey = false;
private boolean upKey = false;
private boolean downKey = false;
//some constructors that would easily be called
public MCharacter()
{
setBackground(Color.WHITE);
setWidth(10);
setHeight(10);
setX(400);
setY(400);
addKeyListener(new MyKeyListener()); //adds a key listener as the private class below (line 152)
}
public MCharacter(int xPos, int yPos)
{
setBackground(Color.WHITE);
setWidth(10);
setHeight(10);
setX(xPos);
setY(yPos);
addKeyListener(new MyKeyListener()); //adds a key listener as the private class below (line 152)
}
public MCharacter(int wth, int hgt, int xPos, int yPos)
{
setBackground(Color.WHITE);
setWidth(wth);
setHeight(hgt);
setX(xPos);
setY(yPos);
addKeyListener(new MyKeyListener()); //adds a key listener as the private class below (line 152)
}
//setters for each of the variables
public void setWidth(int wth)
{
width = wth;
}
public void setHeight(int hgt)
{
height = hgt;
}
public void setX(int xPos)
{
x = xPos;
}
public void setY(int yPos)
{
y = yPos;
}
//getters for each of the varaibles
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
//used to determine if the character should move
public void setUpKey(boolean setUp)
{
upKey = setUp;
}
public void setDownKey(boolean setDown)
{
downKey = setDown;
}
public void setRightKey(boolean setRight)
{
rightKey = setRight;
}
public void setLeftKey(boolean setLeft)
{
leftKey = setLeft;
}
public boolean getUpKey()
{
if(upKey == true)
{
return true;
}
return false;
}
public boolean getDownKey()
{
if(downKey == true)
{
return true;
}
return false;
}
public boolean getRightKey()
{
if(rightKey == true)
{
return true;
}
return false;
}
public boolean getLeftKey()
{
if(leftKey == true)
{
return true;
}
return false;
}
//the following class is goign to be used to determine if an arrow key is being pressed
private class MyKeyListener extends KeyAdapter{
public void keyPressed(KeyEvent e){
switch (e.getKeyCode()){
case KeyEvent.VK_LEFT: //if left key is pressed
setLeftKey(true); //set this boolean to true
break;
case KeyEvent.VK_RIGHT: //if right key is pressed
setRightKey(true); //set this boolean to true
break;
case KeyEvent.VK_UP: //if the up key is pressed
setUpKey(true); //set this boolean to true
break;
case KeyEvent.VK_DOWN: //if the down key is pressed
setDownKey(true); //set this boolean to true
break;
}
}
public void keyReleased(KeyEvent e){
switch (e.getKeyCode()){
case KeyEvent.VK_LEFT: //if left key is released
setLeftKey(false); //set this boolean to false
break;
case KeyEvent.VK_RIGHT: //if right key is released
setRightKey(false); //set this boolean to false
break;
case KeyEvent.VK_UP: //if up key is released
setUpKey(false); //set this boolean to false
break;
case KeyEvent.VK_DOWN: //if down key is released
setDownKey(false); //set this boolean to false
break;
}
}
}
//I am going to call the paint method here and create a small box that I will use as the character
public void paint(Graphics window)
{
window.setColor(Color.BLUE); //sets the color of the character
window.fillRect(x, y, width, height); //sets the dimensions of the character
}
//this method will be used to keep checking for a key pressed: while this is false check for a keytyped
public boolean determine(int x, int y)
{
if( x >= 10 && x <= 790 && y >= 10 && y <= 790)
{
return false;
}
return true;
}
//the following methods will be to move the character
public void up()
{
setY(getY()-2);
}
public void down()
{
setY(getY()+2);
}
public void right()
{
setX(getX()+2);
}
public void left()
{
setX(getX()-2);
}
}
To do this smoothly, you will have to move the while-loop out of the CharacterTest constructor and execute this on a separate Thread. Also define your leftKey, rightKey, upKey and downKey fields as volatile to prevent synchronization issues between the AWT/Swing Event Thread and your rendering Thread (since the event thread and your rendering thread may be accessing these fields at the same time).
If you execute the Canvas' repaint() from your own separate Thread, you should also setIgnoreRepaint(true) in MCharacter's constructor to prevent Swing from repainting your Canvas as well.
Also, to make your code more readable, I suggest you define a method in MCharacter called move() and execute the contents of your while loop there (it makes sense to 'move' a character). the run() method with the loop will then look like this:
#Override public void run() {
while (character.determine()) {
character.move();
}
}
Related
I'm new to swing and I am trying to make the square move but only when the key is released (ex W) but when i hold down the key the square just moves
KeyListener Class
I want to make sure that a key was pressed and if it is still pressed it should return false but true if it was pressed then released
package javaGD.GameAssistant.Input;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyManager implements KeyListener {
private boolean[] keys;
public KeyManager() {
keys = new boolean[256];
}
#Override
public void keyPressed(KeyEvent e) {
keys[e.getKeyCode()] = true;
}
#Override
public void keyReleased(KeyEvent e) {
keys[e.getKeyCode()] = false;
}
#Override
public void keyTyped(KeyEvent e) {
}
public boolean KeyPressed(int keycode) {
return keys[keycode];
}
public boolean KeyReleased(int keycode) {
return keys[keycode];
}
}
Class where the square should move.
KeyListener is inherited from GameAssistant(JFrame is created with the KeyListener)
package TestCode;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import javaGD.GameAssistant.GameAssistant;
public class Game extends GameAssistant {
public int x, xSpeed, y, ySpeed;
public Game(String title, int width, int height, boolean makeResizable) {
super(title, width, height, makeResizable);
}
#Override
public void setup() {
x = 0;
y = 0;
xSpeed = 5;
ySpeed = 5;
}
#Override
public void update() {
if (this.Keyboard().KeyReleased(KeyEvent.VK_D)) {
x += xSpeed;
}
if (this.Keyboard().KeyReleased(KeyEvent.VK_A)) {
x -= xSpeed;
}
if (this.Keyboard().KeyReleased(KeyEvent.VK_W)) {
y -= ySpeed;
}
if (this.Keyboard().KeyReleased(KeyEvent.VK_S)) {
y += ySpeed;
}
}
#Override
public void draw(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(x, y, 20, 20);
}
}
KeyReleased should be returning !keys[keycode] Otherwise it will return false when released and true when pressed
public boolean KeyReleased(int keycode) {
return !keys[keycode];
}
I would also recommend using the Key bindings API over KeyListener as it's more reliable and re-usable.
If you are only planning on a limited number of input operations, I would use Set and a enum, this way you can decouple the "how" from the "what".
You update method doesn't care "how" the inputs are managed, only the "what is the state"
Conceptually, maybe something like...
public enum GameInput {
UP, DOWN, LEFT, RIGHT;
}
public class KeyManager implements KeyListener {
private Set<GameInput> inputs = new HashSet<>();
public KeyManager() {
}
#Override
public void keyPressed(KeyEvent e) {
// Check the key code, verify if it's one of the configured
// actions keys
// The key code could come from a configuration file which might
// be customisable by the user...
if (e.getKeyCode() == KeyEvent.VK_W) {
inputs.add(GameInput.UP);
} else if (e.getKeyCode() == KeyEvent.VK_S) {
// etc...
} // etc...
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
inputs.remove(GameInput.UP);
} else if (e.getKeyCode() == KeyEvent.VK_S) {
// etc...
} // etc...
}
#Override
public void keyTyped(KeyEvent e) {
}
public boolean isKeyPressed(GameInput input) {
return inputs.contains(input);
}
public boolean isKeyReleased(GameInput input) {
return !isKeyPressed(input);
}
}
And your update method might look like...
#Override
public void update() {
if (this.Keyboard().isKeyReleased(GameInput.RIGHT)) {
x += xSpeed;
}
if (this.Keyboard().isKeyReleased(GameInput.LEFT)) {
x -= xSpeed;
}
if (this.Keyboard().isKeyReleased(GameInput.UP)) {
y -= ySpeed;
}
if (this.Keyboard().isKeyReleased(GameInput.DOWN)) {
y += ySpeed;
}
}
Now your update method doesn't care "how" the inputs are generated, only what to do when they are (or aren't) set.
Personally, I'd use a InputManager class and further decouple it, so inputs could be generate via other means, like buttons, mouse inputs, game pads, etc...
Runnable example...
Conceptually, this should work. I say "conceptually", because while I was testing I came across a number of "weird" issues that I can't contribute to either Java (1.8) or MacOS - or because they are a combination of both...more details below...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Box box = new Box();
public TestPane() {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Up.pressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Up.released");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Down.pressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Down.released");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Left.pressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Left.released");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Right.pressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Right.released");
am.put("Up.pressed", new KeyAction(InputAction.UP, true));
am.put("Up.released", new KeyAction(InputAction.UP, false));
am.put("Down.pressed", new KeyAction(InputAction.DOWN, true));
am.put("Down.released", new KeyAction(InputAction.DOWN, false));
am.put("Left.pressed", new KeyAction(InputAction.LEFT, true));
am.put("Left.released", new KeyAction(InputAction.LEFT, false));
am.put("Right.pressed", new KeyAction(InputAction.RIGHT, true));
am.put("Right.released", new KeyAction(InputAction.RIGHT, false));
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
box.update(getBounds());
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
box.draw(g);
}
}
public class Box {
public int x, xSpeed, y, ySpeed, width, height;
public Box() {
x = 0;
y = 0;
xSpeed = 1;
ySpeed = 1;
width = 10;
height = 10;
}
public void update(Rectangle bounds) {
if (!InputManager.INSTANCE.isSet(InputAction.LEFT)) {
x -= xSpeed;
}
if (!InputManager.INSTANCE.isSet(InputAction.RIGHT)) {
x += xSpeed;
}
if (InputManager.INSTANCE.isSet(InputAction.UP) && InputManager.INSTANCE.isSet(InputAction.DOWN)) {
//
} else if (!InputManager.INSTANCE.isSet(InputAction.UP)) {
y -= ySpeed;
} else if (!InputManager.INSTANCE.isSet(InputAction.DOWN)) {
y += ySpeed;
}
if (x < bounds.x) {
x = 0;
} else if (x + width > (bounds.x + bounds.width)) {
x = bounds.x + (bounds.width - width);
}
if (y < bounds.y) {
y = 0;
} else if (y + height > (bounds.y + bounds.height)) {
y = bounds.y + (bounds.height - height);
}
}
public void draw(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(x, y, width, height);
}
}
public enum InputAction {
UP, DOWN, LEFT, RIGHT;
}
public enum InputManager {
INSTANCE;
private Set<InputAction> actions = new HashSet<>();
public void set(InputAction action) {
actions.add(action);
}
public void remove(InputAction action) {
actions.remove(action);
}
public boolean isSet(InputAction action) {
return actions.contains(action);
}
}
public class KeyAction extends AbstractAction {
private InputAction action;
private boolean apply;
public KeyAction(InputAction action, boolean apply) {
this.action = action;
this.apply = apply;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("!");
if (apply) {
System.out.println("Apply " + action);
InputManager.INSTANCE.set(action);
} else {
System.out.println("Remove " + action);
InputManager.INSTANCE.remove(action);
}
}
}
}
TL;DR
While testing the above example, I came across a bizarre number of issues, I've not seen before (not that I've been doing this kind of thing recently).
When using KeyListener, if I pressed (and held) two buttons, I could see the "pressed" action, but there was no repeating events, which is something I would normally expect (for any keys). When I released on key, I saw the "release" action, but when I pressed (and held it), no new "press" action was generated.
I tried the key bindings API (as demonstrated above) and still had no success (similar results).
I then attached a AWTEventListener directly to the event queue and monitored ALL the key strokes.
I noted that, some times (even is just tapping a key repeatedly) that "pressed" might not be generated.
I also noted that holding one or more keys down, releasing and pressing a key again, more often then not, did not generate a new press event (only release events)
I'm using macOS 10.13.6 and Java 1.8.0_144-b01 - it could be bug in either or both, but I don't have the means to test it otherwise
Update...
So, after updating from Java 1.8 to Java 1.10, the above mentioned issue seems to be resoled - however, this highlights another, hardware issue, where only a certain number of keys can be actively pressed at a time - See How do I remove the limit on PC keyboard button presses? for more details
I wanted to create a caterpillar game using Java Frame. It basically has two players trying to occupy a square to increase their scores. I've been using two classes:
the caterpillar class
package caterpillar;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
class Caterpillar {
private Color color;
private Point position;
private char direction;
private Queue<Point> body;
private Queue<Character> commands;
private int score;
public Caterpillar (Color c, Point p){
color = c;
direction = 'E';
body = new LinkedList<Point>();
score = 0;
commands = new LinkedList<Character>();
for (int i = 0; i < 10; i++){
position= new Point(p.x + i, p.y);
body.offer(position);
}
}
public void setDirection(char direction){
commands.offer(new Character(direction));
}
public void move(CaterpillarGame game){
if(commands.size()>0){
Character c = (Character)commands.peek();
commands.poll();
direction = c.charValue();
if(direction == 'Z')
return;
}
Point np = newPosition();
if(game.canMove(np)){
body.poll();
body.offer(np);
position = np;
}
score+=game.squareScore(np);
}
private Point newPosition(){
int x = position.x;
int y = position.y;
if(direction == 'E')
x++;
else if(direction == 'W')
x--;
else if(direction == 'N')
y--;
else if(direction == 'S')
y++;
return new Point(x, y);
}
public boolean inPosition(Point np){ //check if position has alredy been occupied
Iterator <Point>it = body.iterator();
while(it.hasNext()){
Point location = it.next();
if(np.equals(location))
return true;
}
return false;
}
public int getScore(){
return score;
}
public void paint(Graphics g){
g.setColor(color);
Iterator <Point>it = body.iterator();
while(it.hasNext()){
Point p = it.next();
g.fillOval(5 + CaterpillarGame.SegmentSize * p.x,
15 + CaterpillarGame.SegmentSize * p.y,
CaterpillarGame.SegmentSize,
CaterpillarGame.SegmentSize);
}
}
}
the game class:
package caterpillar;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;
import javax.swing.JLabel;
public class CaterpillarGame extends Frame{
final static int BoardWidth = 60;
final static int BoardHeight = 40;
final static int SegmentSize = 10;
private Caterpillar playerOne;
private Caterpillar playerTwo;
private Point square;
private int number; //points the players will get if occupy the square
private Random generator;
private JLabel score1, score2;// scores of two players
public static void main(String[] args){
CaterpillarGame game= new CaterpillarGame();
game.run();
}
public CaterpillarGame(){
setBackground(Color.GREEN);
setVisible(true);
setSize((BoardWidth+1)*SegmentSize, BoardHeight*SegmentSize + 30);
addKeyListener(new KeyReader());
playerOne = new Caterpillar(Color.blue, new Point(20, 10));
playerTwo = new Caterpillar(Color.red, new Point(20, 30));
addWindowListener(new CloseQuit());
generator = new Random();
number = 1;
score1 = new JLabel("Player One: "+playerOne.getScore());
score2 = new JLabel("Player Two: "+playerTwo.getScore());
this.add(score1);
this.add(score2);
square = new Point(newSquare());
}
public void run(){
while(true){
movePieces();
repaint();
try{
Thread.sleep(100);
}catch(Exception e){}
}
}
public void paint(Graphics g){
playerOne.paint(g);
playerTwo.paint(g);
g.setColor(Color.white);
g.fillRect(square.x, square.y, 10,10); //line 62, exception thrown
g.setColor(Color.BLACK);
g.drawString(Integer.toString(number), 10, 10);
}
public void movePieces(){
playerOne.move(this);
playerTwo.move(this);
}
public boolean canMove(Point np){
int x = np.x;
int y = np.y;
if((x<=0)||(y<=0))
return false;
if((x>=BoardWidth)||(y>=BoardHeight))
return false;
if(playerOne.inPosition(np))
return false;
if(playerTwo.inPosition(np))
return false;
return true;
}
private class KeyReader extends KeyAdapter{
public void keyPressed(KeyEvent e){
char c = e.getKeyChar();
switch(c){
case 'q': playerOne.setDirection('Z');
break;
case 'a': playerOne.setDirection('W');
break;
case 'd': playerOne.setDirection('E');
break;
case 'w': playerOne.setDirection('N');
break;
case 's': playerOne.setDirection('S');
break;
case 'p': playerTwo.setDirection('Z');
break;
case 'j': playerTwo.setDirection('W');
break;
case 'l': playerTwo.setDirection('E');
break;
case 'i': playerTwo.setDirection('N');
break;
case 'k': playerTwo.setDirection('S');
break;
}
}
}
public Point newSquare(){
Point p = new Point(generator.nextInt(51), generator.nextInt(31));
while(playerOne.inPosition(p)||playerTwo.inPosition(p)){
p = new Point(generator.nextInt(51), generator.nextInt(31));
}
number++;
return square = p;
}
public int squareScore(Point p){
if(p.equals(square)){
newSquare();
return number;
}
return 0;
}
private class CloseQuit extends WindowAdapter{
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
}
this is what i have so far, but i got several problems when i ran the program:
the JLabels, square, and string didn't show up
it kept throwing java.lang.NullPointerException
how do i have the program stopped when the score of one player reaches a certain number?
how to check if a caterpillar touches the square?
Thanks in advance.
the JLabels, square, and string didn't show up
They are, you're just screwing with the paint process so badly that you're preventing them from been painted. Also, I "believe" that java.awt.Frame uses a BorderLayout.
This is one of the reasons we generally discourage people from overriding paint, it's far to easy to break the paint chain
Add a call to super.paint before you perform any custom painting.
#Override
public void paint(Graphics g) {
super.paint(g);
I'd prefer that you used paintComponent from a JComponent based class and add that object to your frame, but you seem to have restrictions from doing so...
Also, change the layout manager to something like FlowLayout to get both labels on the screen.
See Painting in AWT and Swing and Laying Out Components Within a Container for more details
it kept throwing java.lang.NullPointerException
This seems to be a race condition. Essentially, you are calling setVisible on the frame BEFORE you've finished initialising the requirements of the UI, which is causing paint to be called BEFORE the frame is fully initialized.
Call setVisible last. Better yet, don't call setVisible from within the constructor...
how do i have the program stopped when the score of one player reaches a certain number?
... In your "game loop" you need to be checking that state of the score and breaking out of the "game loop" when the required state is meet...
how to check if a caterpillar touches the square?
That's a much more complicated question. Essentially you could use the interests or contains method of a Rectangle (or other Shape object). You know where the Point of the square and "segments" of the Caterpillar are. You know the size of the square and the "segments".
You need to compare each of the segments to see if they intersect the are of the square. Take a closer look at java.awt.Rectangle for more details
SO I'm making a game where the user moves on a horizontal, vertical tiled map. However I dont want the user to be able to press 2 keys and make the player move diagonal. ony left,right,up and down.
I currently have a code that does it but if the user presses another key and then lifts it, the player stops moving due to how I have coded it
#Override
public boolean keyDown(int keycode) {
if (keyNotDown) {
switch (keycode) {
case Keys.RIGHT:
playScreen.setXD(2);
break;
case Keys.LEFT:
playScreen.setXD(-2);
break;
case Keys.DOWN:
playScreen.setYD(-2);
break;
case Keys.UP:
playScreen.setYD(2);
break;
}
keyNotDown = false;
}
return false;
}
#Override
public boolean keyUp(int keycode) {
player.stopMove();
keyNotDown = true;
return false;
}
As you can see if a person presses a key while another one is pressed, it will not work but when they lift that said key, then it'll stop moving
EDIT
When the user presses down a key it sends the xd,yD values to the render method and because render keeps being called, it keeps on moving the player with the xD,yD values. The stop move method resets those values to 0 so it stops moving when the key is not being pressed.
Try this following code and let me know, because I haven't test it.
private KEY_PRESSE keyPressed = KEY_PRESSE.NONE;
#Override
public boolean keyDown(int keycode) {
switch (keycode) {
case Keys.RIGHT:
if (keyPressed.equals(KEY_PRESSE.RIGHT) || keyPressed.equals(KEY_PRESSE.NONE)) {
playScreen.setXD(2);
keyPressed = KEY_PRESSE.RIGHT;
break;
}
case Keys.LEFT:
if (keyPressed.equals(KEY_PRESSE.LEFT) || keyPressed.equals(KEY_PRESSE.NONE)) {
playScreen.setXD(-2);
keyPressed = KEY_PRESSE.LEFT;
break;
}
case Keys.DOWN:
if (keyPressed.equals(KEY_PRESSE.DOWN) || keyPressed.equals(KEY_PRESSE.NONE)) {
playScreen.setYD(-2);
keyPressed = KEY_PRESSE.DOWN;
break;
}
case Keys.UP:
if (keyPressed.equals(KEY_PRESSE.UP) || keyPressed.equals(KEY_PRESSE.NONE)) {
playScreen.setYD(2);
keyPressed = KEY_PRESSE.UP;
break;
}
}
return false;
}
#Override
public boolean keyUp(int keycode) {
player.stopMove();// I don't know exactly but can you remove this ligne, I
// think its useless , when no key is pressed
// the player will stop no?
keyPressed = KEY_PRESSE.NONE;
return false;
}
enum KEY_PRESSE {
RIGHT, LEFT, DOWN, UP, NONE
}
Well normally I don't post a full solution but its fairly simple what you want to do. The solution offers you a different way to implement your design. Since your speed is constant I figure out don't need to set the delta but only change the direction.
You can keep track of the key presses and based on what is pressed you can determine the direction to move your character. So for instance, when you press the up arrow, it sets the direction to up, but when you press left I track it but ignore the button. If you release the up arrow, then your character will move left and at no point will it move in more than 1 direction.
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
public class Move implements ApplicationListener {
private static final Map<Integer, Direction> MOVE_KEYS = new HashMap<Integer, Direction>(){{
this.put(Keys.RIGHT, Direction.RIGHT);
this.put(Keys.LEFT, Direction.LEFT);
this.put(Keys.UP, Direction.UP);
this.put(Keys.DOWN, Direction.DOWN);
}};
private static enum Direction {
RIGHT, LEFT, UP, DOWN;
}
private static class Player {
public float x;
public float y;
public float speed;
public Queue<Direction> dirStack = new LinkedList<Direction>();
public Player(float x, float y, float speed) {
this.x = x;
this.y = y;
this.speed = speed;
}
public void update(float delta) {
if (!dirStack.isEmpty()) {
switch(dirStack.peek()) {
case DOWN:
y -= speed;
break;
case LEFT:
x -= speed;
break;
case RIGHT:
x += speed;
break;
case UP:
y += speed;
break;
}
}
}
public void render(ShapeRenderer render) {
render.begin(ShapeType.FilledRectangle);
render.setColor(1, 0, 0, 1);
render.filledRect(x, y, 20, 20);
render.end();
}
}
private static class MoveController extends InputAdapter {
private final Player player;
public MoveController(Player player) {
this.player = player;
}
#Override public boolean keyDown(int keycode) {
if (MOVE_KEYS.containsKey(keycode)) {
final Direction dir = MOVE_KEYS.get(keycode);
Gdx.app.log("D", dir.toString());
return player.dirStack.add(dir);
}
return false;
}
#Override public boolean keyUp(int keycode) {
if (MOVE_KEYS.containsKey(keycode)) {
final Direction dir = MOVE_KEYS.get(keycode);
Gdx.app.log("U", dir.toString());
return player.dirStack.remove(dir);
}
return false;
}
}
private Camera cam;
private ShapeRenderer render;
private Player player;
#Override public void create() {
Gdx.app.log("CREATE", "App Opening");
this.player = new Player(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 5);
Gdx.input.setInputProcessor(new MoveController(player));
this.cam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
this.render = new ShapeRenderer();
cam.apply(Gdx.gl10);
Gdx.gl10.glClearColor(0f, 0f, 0f, 1);
}
#Override public void render() {
Gdx.gl10.glClear(GL20.GL_COLOR_BUFFER_BIT);
player.update(Gdx.graphics.getDeltaTime());
player.render(render);
}
#Override public void dispose() {
Gdx.app.log("DISPOSE", "App Closing");
}
#Override public void resize(final int width, final int height) {
Gdx.app.log("RESIZE", width + "x" + height);
Gdx.gl10.glViewport(0, 0, width, height);
}
#Override public void pause() {}
#Override public void resume() {}
}
I want to move the character left, right up, and down in applet, but it is not moving at all. here is my code, help please
import javax.swing.JPanel;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import java.applet.*;
import java.awt.event.*;
import java.awt.*;
public class drawCenter extends Applet
{
private int x,y;// the x and y of the position of the player
private BufferedImage image, pos;
public void init( )
{
try
{
image = ImageIO.read(new File("pokemonCenter.png"));
pos = ImageIO.read(new File("player/maleInGame.png"));
}
catch (IOException ex)
{
}
x = 150; y = 171;
}
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
switch( keyCode )
{
case KeyEvent.VK_UP: if( y>0 )
{
y=y-19;
repaint();
}
break;
case KeyEvent.VK_DOWN: if( y<171 )
{
y=y+19;
repaint();
}
break;
case KeyEvent.VK_LEFT:if( x>0 )
{
x=x-15;
repaint();
}
break;
case KeyEvent.VK_RIGHT:if( x<285 )
{
x=x+15;
repaint();
}
break;
}
e.consume();
}
public void keyReleased(){
}
public void paint( Graphics g )
{
g.drawImage(image, 0, 0, null);
g.drawImage(pos, x, y, null);
}
}
Your code is pretending to have a KeyListener, but there is no KeyListener anywhere to be found, much less one added to a component of the GUI. Your solution: create a class that implements KeyListener or that extends KeyAdapter, and then add it to a GUI component that has focus.
Please check out: How to Write a KeyListener.
Also, I recommend that you avoid having your GUI class, your Applet, implement KeyListener since that can give the class too much to be responsible for. Better I think to either create an anonymous inner class or even a separate stand-alone class for your KeyListener.
Make your class implement KeyListener and then call super.addKeyListener(this) in your constructor. As you have it now, you're neither specifying the class implements the interface (despite implementing the methods it would need to) nor are you ever registering a listener with the Applet.
Try this.
import javax.swing.*;
import java.awt.*;
import static java.awt.event.KeyEvent.*;
public class DrawCenter extends JApplet implements KeyListener {
Image character = null;
int x = 0;
int y = 0;
public Image loadImage(String name){
return new ImageIcon(getClass().getClassLoader().getResource(name)).getImage();
}
public void init(){
character = getImage("pokemonCenter.png");
x = getWidth()/2 - character.getWidth(null)/2;
y = getHeight()/2 - character.getHeight(null)/2;
addKeyListener(this);
}
public void keyPressed(KeyEvent e){
switch (e.getKeyCode()){
case VK_LEFT: x--; break;
case VK_RIGHT: x++; break;
case VK_UP: y--; break;
case VK_DOWN: y++; break;
}
repaint();
}
public void paint(Graphics g){
g.drawImage(character, x, y, null);
}
}
If you're making a game see the game loops or try a Game-Engine (If you'r interested, go to
http://game-engine-for-java.googlecode.com/ )
You should be something like this:
package stack;
import java.applet.*;
import java.awt.event.*;
import java.awt.*;
public class DrawCenter extends Applet implements KeyListener{
private int x=50,y=50;// the x and y of the position of the player
public void init( ){
addKeyListener(this);
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
switch( keyCode ) {
case KeyEvent.VK_UP: if( y>0 ){ //when up key is pressed and the position of the player is not on the edge
y=y-19;
repaint();
}
break;
case KeyEvent.VK_DOWN: if( y<171 ){//when down key is pressed and the position of the player is not on the edge
y=y+19;
repaint();
}
break;
case KeyEvent.VK_LEFT: if( x>0 ){
x=x-15;
repaint();
}
break;
case KeyEvent.VK_RIGHT: if( x<285 ){
x=x+15;
repaint();
}
break;
}
}
public void keyReleased(){
}
public void paint( Graphics g ){ //will draw the background and the character
g.fillRect(x, y, 20, 20);
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
I'm making a game, and I have a Main Menu that works perfectly. When I select one of the options, it brings up another Menu in a new window. However in this new window, the KeyListener is not responding. If I click back to the Main Menu window, the KeyListener is still working there. Here is the code:
MainMenu:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.*;
public class DisplayMainMenu extends JFrame implements KeyListener{
static int width = 799, height = 463;
int arrowPos = 310;
boolean clear = true;
BufferedImage menu = null;
BufferedImage arrow = null;
LevelSkip test = new LevelSkip();
boolean done = false;
static DisplayMainMenu main;
public static void main(String[] args){
main = new DisplayMainMenu();
main.setResizable(false);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setVisible(true);
main.init();
}
public void init() {
try{
menu = ImageIO.read(new File("Main Menu.png"));
arrow = ImageIO.read(new File("arrow.png"));
}catch(IOException ie) {
System.out.println(ie.getMessage());
}
this.setSize(width, height);
this.addKeyListener(this);
clear = true;
paint(getGraphics());
}
public void paint (Graphics g){
if(clear==true){
g.drawImage(menu,0,0,null);
clear = false;
}
g.drawImage(arrow,275,arrowPos,null);
}
public void keyPressed(KeyEvent e){
String key = e.getKeyText(e.getKeyCode());
if(key == "Up"){
clear = true;
if (arrowPos > 310)
arrowPos -= 30;
else
arrowPos = 370;
paint(getGraphics());
}
if(key == "Down"){
clear = true;
if (arrowPos < 370)
arrowPos += 30;
else
arrowPos = 310;
paint(getGraphics());
}
if(key == "Space"){
done = true;
switch(arrowPos){
case 310: System.out.println("RUN NEW GAME"); test.init();
break;
case 340: System.out.println("RUN HIGH SCORES");
break;
case 370: System.exit(0);
}
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
LevelSkip:
import java.awt.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.*;
public class LevelSkip extends JFrame implements KeyListener {
static int width = 799, height = 463;
int arrowPos = 109;
boolean clear = true;
BufferedImage menu = null;
BufferedImage arrow = null;
public void init() {
LevelSkip main = new LevelSkip();
main.setSize(width, height);
main.requestFocusInWindow();
main.addKeyListener(main);
main.setResizable(false);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setVisible(true);
try{
menu = ImageIO.read(new File("level skip.png"));
arrow = ImageIO.read(new File("arrow2.png"));
}catch(IOException ie) {
System.out.println(ie.getMessage());
}
clear = true;
paint(main.getGraphics());
}
public void paint (Graphics g){
if(clear==true){
g.drawImage(menu,0,0,null);
clear = false;
}
g.drawImage(arrow,arrowPos,355,null);
}
public void keyPressed(KeyEvent e){
String key = e.getKeyText(e.getKeyCode());
if(key == "Left"){
clear = true;
if (arrowPos > 109)
arrowPos -= 260;
else
arrowPos = 629;
paint(getGraphics());
}
if(key == "Right"){
clear = true;
if (arrowPos < 629)
arrowPos += 260;
else
arrowPos = 109;
paint(getGraphics());
}
if(key == "Space"){
switch(arrowPos){
case 109: System.out.println("ADD 1 TO LEVEL AND RUN BATTLE");
break;
case 369: System.out.println("ADD 5 TO LEVEL AND RUN BATTLE");
break;
case 629: System.out.println("ADD 10 TO LEVEL AND RUN BATTLE");
}
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
I'm not exactly sure what the problem is, the Level Skip window displays fine, it just doesn't register any key presses.
If you've searched on this problem at all, you'll see that it almost always means that the component being listened to doesn't have focus. 90% of the time the solution is to use Key Bindings.
Your other problem is that you're comparing Strings ==. You don't want to do this. Use the equals or the equalsIgnoreCase(...) method instead. Understand that == checks if the two objects are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of
if (fu == "bar") {
// do something
}
do,
if (fu.equals("bar")) {
// do something
}
or,
if (fu.equalsIgnoreCase("bar")) {
// do something
}
You're also
calling paint(...) directly, something you should almost never do.
Drawing in a top level window's paint(...) method which you also should avoid instead of drawing in a JPanel's (or other JComponent) paintComponent(...) method.
Not calling the paint or paintComponent's super method at the start of the method
Putting program logic in a paint or paintComponent method.
etc...
You will want to go through the Swing tutorials before going much further to learn from the pros.