keyPressed() event carries on firing even after i stop pressing the key - java

So the object that I've drawn starts moving either up or down depending on what arrow key I've pressed but once i let go it carries on moving in the same direction not stopping unless i press a random key. If i press up it starts moving up and carries on moving up even after letting go of up. If i then press down it starts moving down and carries on moving down even after i am no longer pressing it. If any key other than up arrow key or down arrow key is pressed whilst it is moving it stops moving.
MAIN SKETCH:
Defender defender1;
PImage background;
int x=0; //global variable background location
void setup() {
size(800,400);
background = loadImage("spaceBackground.jpg");
background.resize(width,height);
defender1 = new Defender(200,200);
}
void draw () {
image(background, x, 0); //draw background twice adjacent
image(background, x+background.width, 0);
x -=4;
if(x == -background.width)
x=0; //wrap background
defender1.render();
defender1.keyPressed();
}
Defender Class:
class Defender {
int x;
int y;
Defender(int x, int y) {
this.x = x;
this.y = y;
}
void render() {
fill(255,0,0);
rect(x,y,50,20);
triangle(x+50,y,x+50,y+20,x+60,y+10);
fill(0,0,100);
rect(x,y-10,20,10);
}
void keyPressed() {
if (key == CODED) {
if (keyCode == UP) {
defender1.y = y-1;
} else if (keyCode == DOWN) {
defender1.y = y+1;
}
}
}
}

You're calling your defender1.keyPressed() function every time draw() is called.
The key and keyCode variables hold the most recently pressed key, regardless of whether that key is currently being held down.
To check whether any key is currently being pressed, you could use the keyPressed variable.
Or you could change your code to only call defender1.keyPressed() from the sketch-level keyPressed() function.
You can find more info in the reference.
Shameless self-promotion: here is a tutorial on user input in Processing.

Related

How to fix Java listening to more than 1 key at a time?

Me and my partner are attempting to create the game Pong for our computer science final project. We created a reference code where 2 cubes can be controlled upwards and downwards and it works fine. The problem occurs when attempting to control both cubes at the same time (only 1 cube will move at a time). We want to make both cubes move at the same time.
WE want to say that:
yPos - is the y position of the black cube
xPos - is the x position of the black cube
xPos2 - is the x position of the blue cube
YPos2 - is the y position of the blue cube
Keys:
A - Go up for black cube
Z - Go down for black cube
K - Go up for blue cube
M - go down for blue cube
We have tried using a more complicated version which used j-label animation. How ever we want to make our pong game through the graphics function. But we do not understand:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class PongHelpNeed extends JFrame implements KeyListener
{
// booleans to tell which key is pressed
boolean upKey;
boolean downKey;
boolean upKey2;
boolean downKey2;
// the position variables
int yPos;
int xPos;
int xPos2;
int yPos2;
public PongHelpNeed ()
{
//create window
super ("Controller");
setSize (660, 700);
// set keys to false and original positions
upKey = false;
downKey = false;
upKey2 = false;
downKey2 = false;
xPos = 100;
yPos = 350;
xPos2 = 500;
yPos2 = 350;
// add the frame as a listener to your keys
addKeyListener (this);
// Show the frame
setVisible(true);
}
//needs to be here because the class implements KeyListener
public void keyTyped (KeyEvent e)
{
System.out.println (e.getKeyCode () + " Typed");
}
//needs to be here because the class implements KeyListener
public void keyPressed (KeyEvent e) {
//check if keys a,z or k,m are pressed
if (e.getKeyCode () == KeyEvent.VK_A)
{
upKey = true;
}
else if (e.getKeyCode () == KeyEvent.VK_Z)
{
downKey = true;
}
else if (e.getKeyCode () == KeyEvent.VK_K)
{
upKey2 = true;
}
else if (e.getKeyCode () == KeyEvent.VK_M)
{
downKey2 = true;
}
//repaint the window everytime you press a key
repaint ();
}
//needs to be here because the class implements KeyListener
public void keyReleased (KeyEvent e)
{
System.out.println (e.getKeyCode () + " Released");
}
//paints the pictures
public void paint (Graphics g)
{
//set background
g.setColor(Color.WHITE);
g.fillRect(0, 0, 660, 700);
//cube 1
g.setColor(Color.BLACK);
g.fillRect(xPos,yPos,50, 50);
//draw cube 2
g.setColor(Color.BLUE);
g.fillRect(xPos2,yPos2, 50, 50);
//if keys are pressed move the cubes accordingly up or down
if (upKey == true)
{
yPos = yPos - 15;
upKey = false;
}
else if (downKey == true)
{
yPos = yPos + 15;
downKey = false;
}
else if (downKey2 == true){
yPos2 = yPos2 + 15;
downKey2 = false;
}
else if (upKey2 == true) {
yPos2 = yPos2 - 15;
upKey2 = false;
}
}
public static void main (String[] args)
{
new PongHelpNeed ();
}
}
Our expected results are we are trying to move both cube at the same time. So when we press the A key and the K key the black square should move and the blue cube should move.
Calling repaint() does not trigger a call to the paint immediately, so it's possible that the keyPressed is triggered twice (or more) before paint.
In your paint method you are checking the keys in if-else, which means that if one of the flags is true, the rest are not checked. You also have a race condition where the keyPressed is fighting with paint over the flags. Also, if you press a key quickly multiple times, you'll lose all the extra key presses between the first handled event and the next repaint.
Instead of doing the move within paint, you should do it within the keyPressed handler. Don't set a flag to e.g. upKey = true;, but instead do the action directly: yPos = yPos - 15;. The paint method will then just refresh the view to reflect the current (updated) state.

Save first mouseposition while 'mouseDragged'

I've created a Java-Application to add/remove and show a random number of points on a JPanel. It is possible to move the points per drag&drop. To undo the last actions I buffer the points.
My question: if a point will moved via 'mouseDragged', is it possible to save the first mouseposition while the drag begins? I've tried the following:
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (!points.isEmpty() && curPointIndex > -1) {
if (move == false) {
pointmove = new Point(x,y);
move = true;
}
}
}
The method mouseReleased change the variable move back to false. The variable pointmove should save the first point, but it changes all the time while the mouse is dragged.
Could anyone discribe why or what I can to do differently?
As Arnaud mentioned, you can use mousePressed to store the initial point:
#Override
public void mousePressed(MouseEvent e)
{
Point initialPoint = e.getPoint();
}

Rocket move through class. Processing

I have a moving image as a background
PImage background;
int x=0; //global variable background location
rocket Rocket;
void setup(){
size(800,400);
background = loadImage("spaceBackground.jpg");
background.resize(width,height);
Rocket = new rocket();
}
void draw ()
{
image(background, x, 0); //draw background twice adjacent
image(background, x+background.width, 0);
x -=4;
if(x == -background.width)
x=0; //wrap background
Rocket.defender();
Rocket.move();
}
In a different class i'm trying to make a rocket move up and down
class rocket {
float x;
float y;
float speedy;
boolean up;
boolean down;
rocket(){
x = 50;
y = 200;
speedy = 3;
}
void move() {
if(up)
{
y = y - speedy;
}
if(down)
{
y = y + speedy;
}
}
void defender(){
fill(255,0,0);
rect(x,y,50,20);
triangle(x+50,y,x+50,y+20,x+60,y+10);
fill(0,0,100);
rect(x,y-10,20,10);
}
void keyPressed(){
if(keyCode == UP)
{
up = true;
}
if(keyCode == DOWN)
{
down = true;
}
}
void keyReleased(){
if(keyCode == UP)
{
up = false;
}
if(keyCode == DOWN)
{
down = false;
}
}
}
The rocket will display but won't move. I tried everything I know but nothing works. I also tried the rocket class just as a project by itself and the rocket moves, so it has to be something with the class. i'm quite new to coding so please keep that in mind, thank you in advance.
The keyPressed() and keyReleased() functions (and any other event function) need to be at the sketch level, not inside another class. If they're inside another class, Processing doesn't know how to find them.
So, what you need to do is move the keyPressed() and keyReleased() functions to the sketch, and then call functions on your Rocket class (class names should start with an upper-case letter, btw), similar to how you're calling rocket.defender() and rocket.move() (variable names should start with a lower-case letter) from the sketch-level draw() function.

Game lag when releasing a key

I am making a java 2d side scroller and im having problems with multiple keys at the same time. Such as right + up. Whenever you release the up you stop moving right as you slowly go back to the ground even though right is still being pressed. Here are the keyboard listeners I have setup. dx is my horizontal movement speed and dy is the vertical height. Below is from the character class
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = -5;
mainCharacterImageFacing = l.getImage();
}
if (key == KeyEvent.VK_RIGHT) {
dx = 5;
mainCharacterImageFacing = r.getImage();
}
if (key == KeyEvent.VK_UP) {
dy = 1;
mainCharacterImageFacing = r.getImage();
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT);
dx = 0;
if (key == KeyEvent.VK_RIGHT)
dx = 0;
if (key == KeyEvent.VK_UP)
{dy = 0;
mainCharacterImageFacing = r.getImage();
}
This is some code from the main game window that deals with calling the key press/release methods as well as dealing with the jump.
private class AL extends KeyAdapter{
public void keyReleased(KeyEvent e) {
p.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
p.keyPressed(e);
}
}
#Override
public void run()
{
long beforeTime;
long timeDiff;
long sleep;
beforeTime = System.currentTimeMillis();
while(done == false)
{
cycle();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = 10 - timeDiff;
if (sleep < 0 )
sleep = 2;
try {
Thread.sleep(sleep);
} catch (Exception e)
{}
beforeTime = System.currentTimeMillis();
}
done = false;
h = false;
k = false;
}
boolean h = false;
boolean done = false;
public void cycle() {
if (h == false)
v = v - 2; //jump speed falling
if (v == 350) //max y value of jump. Lower numbers = higher jumps
h = true;
if (h == true && v <= 470) //starting y value
{
v = v + 2; //jump speed rising
if (v == 470)
done = true;
}
}
Do not handle your movement directly in the AL class. Instead, use booleans and set them to true/false accordingly:
private class AL extends KeyAdapter{
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
left = true;
}
if (key == KeyEvent.VK_RIGHT) {
right = true
}
if (key == KeyEvent.VK_UP) {
//...
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
left = false
if (key == KeyEvent.VK_RIGHT)
right = false
if (key == KeyEvent.VK_UP)
//...
}
}
The reason for this is because keyPressed and keyReleased are called when the keys are acted upon, though that means it will not be in sync with your main loop.
To move your sprite call a method in the loop which, if your conditions are true, moves your sprite accordingly, else does nothing.
EDIT: After reviewing your code some more I have a few suggestions.
First of all, look up sub-pixel rendering. Sub-pixel rendering is used to make the movement of sprites look smoother.
Another thing to look up is variable timesteps (sometimes referred to as delta timesteps). Delta time can be used to make sure that actions are performed in sync with a players fps. If one player has 60fps and another has 30fps, the player with 30fps will see actions performed at half the speed. With a delta timestep however, actions are always performed at the same speed. Here's a good article.
The third thing is your timing. Currently you're using System.getCurrentTimeMills. This is bad, and not precise. Instead, use System.nanoTime.
A fourth thing I've spotted is your jumping algorithm. A better way is to include acceleration. First you need to declare a constant for acceleration (0.1 or 0.2 are good) and tally a vertical speed. You can then fall when the vertical speed gets to a certain value. Here's a small snippet, though if you have gravity you may want to edit it. First of all set vSpeed to say -8 by default.
public void jump() {
vSpeed += ACCELERATION;
if(vSpeed < 8)
dy += vSpeed;
else
vSpeed = -8;
falling = false;
}
I just wrote this off the top of my head, but basically, since moving upwards is taking away a number, you appear to jump when it adds negative numbers, then you'll start falling when it reaches 0, and land when reaches 8 again.
The problem is the way the OS handles key events and passes them to your application. When you press a key, it fires an event for down. Then based on your settings for repeating, it will start pressing the key again after some amount of time, at some amount of frequency. (you can see this when typing. Press a key, and hold it).
When you press another key, it stops the repeated triggers for the other key. You can see this while typing as well. Hold a key, then start holding another. The original key stops, as you would expect.
This won't even be consistent with every os, and people could cheat in your game as it is, by making the repeat timer on their keyboard faster.
For these reasons, it's a very bad idea to do animations inside of key listeners. You should be settings flags to true/false and reading them in a game loop. (As demonstrated in #Troubleshoot's answer).

Does Swing keep scanning for keyboard input (java)?

I am trying to move an image that I have drawn onto a Jpanel using g.drawImage(). I need to know why this code isn't working (I am trying to reposition the image using the w key to move it up)
int CharX = 1;
int CharY = 30;
public void keyPressed(KeyEvent w) {
CharY = CharY + 1;
repaint();
}
public void keyReleased(KeyEvent w) {
CharY = CharY + 1;
repaint();
}
You're not actually checking for the w key just by naming the KeyEvent w. You need to check if (w.getKeyCode() == KeyEvent.VK_W)
Y-coordinates in Java start with 0 at the top, so you might want to subtract from CharY to make it go up.
This will update twice, once when the key is pressed, and again when you let it go. Not sure if that's what you actually want.
Without knowing what's inside your paint function, or if you even implemented it, it's hard to say if the problem isn't actually in there, but it should look something like
public void paint(Graphics g) {
g.drawImage(yourImage, CharX, CharY, null);
}
You should not call repaint() inside the keyPressed() or keyReleased() method.
public void keyPressed(w.getKeyCode() == KeyEvent.VK_W) {
CharY = CharY + 1;
}
Call repaint() later.

Categories