简体   繁体   中英

Tick Method not Recognizing Variable Change

I am currently working on a Pac-Man remake in Java, and I am having a problem with player movement. I use a KeyListener to detect when the WAS or D keys are pressed, and sets a variable as true or false. The variables are up, down, left, right. This works fine, but the "tick" method does not recognize the value change, almost as if there are two variables. For example, I will press the W key and up is set to true. In the tick method, however, up is not true. This also happens when getting the position of the player. It will only get the first position of the player, but after I edit the position in the KeyListener method, the tick method will not recognize that the position has been changed.

I have also found that when I move the position directly from the KeyListener method and print it to the console, it works correctly. But when I print the position from the tick method, it always prints the original position. If I print both, it seems as if there are two variables, because the KeyListener method will always print the correct value, and the tick method will always print the original, but does not reset the KeyListener value.

Sorry if this sounds confusing, please ask if you need me to describe it in a different way.

Anyway, the tick method is being called 60 times every second.

Can someone please help me fix this problem? Help is appreciated.

Here is the class for the Player, containing the tick and KeyListener methods.

package com.graysullivan.entities;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import com.graysullivan.main.Location;

public class Player implements KeyListener {

Location pos;
private int width = 80;
private int height = 80;
private boolean up, down, left, right;

public Player() {
    pos = new Location(360, 701);
}

public void init() {
}

public void tick(double deltaTime) {
//System.out.println(pos.y);
    if(up) {
        System.out.println("up");
        pos.y--;
    } 

    if(down) {
        pos.y++;
    }

    if(left) {
        pos.x--;
    }

    if(right) {
        pos.x++;
    }
}

public void render(Graphics2D g) {
    g.fillRect((int)pos.x,(int)pos.y, 40, 40);
}

@Override
public void keyPressed(KeyEvent e) {
    int key = e.getKeyCode();

    if(key == KeyEvent.VK_W) {
        up = true;
        System.out.println(up);
    }

    if(key == KeyEvent.VK_S) {
        down = true;
    }

    if(key == KeyEvent.VK_A) {
        left = true;
    }

    if(key == KeyEvent.VK_D) {
        right = true;
    }

    if(key == KeyEvent.VK_DELETE) {
        System.exit(0);
    }

}

@Override
public void keyReleased(KeyEvent e) {
    int key = e.getKeyCode();

    if(key == KeyEvent.VK_W) {
        up = false;
    }

    if(key == KeyEvent.VK_S) {
        down = false;
    }

    if(key == KeyEvent.VK_A) {
        left = false;
    }

    if(key == KeyEvent.VK_D) {
        right = false;
    }
}

@Override
public void keyTyped(KeyEvent e) {

}

I think what you need is to declare synchronized on the method which manipulate up , down , right , and left to avoid memory consistency error and thread interference.

Something like this:

public synchronized void tick(double deltaTime) {
    ...
}

Edit: you might want to declare the members with volatile to ensure that the changes in keyPressed method happens before the tick .

Looking at your code, there is a part that look suspicious.

In Game.java you created an instance of Player

frame.addKeyListener(new Player());

Another instance of Player is also created in LevelLoader.java

Player player = new Player();

...which is the one that getting the tick method triggered.

They are two different objects which has nothing to do with each other (other than the fact that they are from the same class). Changing a state of one object doesn't change the state of another. What happen in your case is that the first Player instance listen to key press but the second instance is getting the tick method triggered.

What you need to do is to create a player instance in Game.java and pass the object to LevelLoader.java (via StateManager.java ?) instead of creating another instance in LevelLoader.java itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM