Движение пользователя Jetpack Joyride

#java #if-statement

Вопрос:

я пытаюсь создать игру, похожую на jetpack joyride, в которой пользователь может удерживать пробел, чтобы подняться, и отпускать, чтобы двигаться вниз. Я использую таймеры для имитации силы тяжести и использования keyPressed и keyReleased проверки того, удерживает ли пользователь пробел. Я использую операторы печати, чтобы точно знать, что и нажатие клавиш, и их освобождение работают, но я не знаю, почему физика не работает. Я не знаю, является ли проблема в том, что мои операторы if не обновляются, если это новые таймеры, создаваемые внутри оператора if. В любом случае, гравитация не меняется, и я застрял. Помощь приветствуется.

 import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Calendar;



public class Game implements KeyListener {
    JFrame frame;
    JLabel player;

    public boolean grounded = false;
    public int velocity = 0;
    public int finalY = 0;
    public boolean spaceHeld = false;


    Action spaceAction;

    Game() {
         
        frame = new JFrame("Nicholas Seow-Xi Crouse");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1920, 1080);
        frame.setLayout(null);
        
        frame.setFocusable(true);
        frame.addKeyListener(this);

        player = new JLabel();
        player.setBackground(Color.red);
        player.setBounds(10, 1800, 50, 50);
        player.setOpaque(true);

        frame.add(player);
        frame.setVisible(true);
        
         Timer flightTime = new Timer();
         TimerTask flight = new TimerTask() {
         
            public void run() {
                  if(velocity > -5) {
                  velocity -= 1;
                  }
                  else{
                  velocity = -5;
                  }
                  if (finalY < -61) {
                   finalY = finalY   velocity;
                   }
                   else{
                   finalY = -61;
                   }
                   player.setLocation(player.getX(), player.getY()   finalY);
                   if (player.getY() <= 0){
                   cancel();
                   velocity = 0;
                   finalY = 0;
                   player.setLocation(player.getX(), 0);
                    
                   }  
            }
      };
         

         Timer gravityTime = new Timer();
         TimerTask gravity = new TimerTask() {


            //creates a timer run method that simulates the falling gravity when not grounded
            public void run() {
                if(velocity < 5){
                velocity  = 1;
                }
                else{
                velocity = 5;
                }
                //creates the variable the tells where the player is located
                if (finalY < 61) {
                finalY = finalY   velocity;
                }
                else{
                finalY = 61;
                }
                player.setLocation(player.getX(), player.getY()   finalY);
                if (player.getY() >= 1000){
                cancel();
                velocity = 0;
                finalY = 0;
                player.setLocation(player.getX(), 990); 
                }
                
            }
        };

        if (spaceHeld == false ) {
            gravityTime.scheduleAtFixedRate(gravity, 0, 33);
        }
        if (spaceHeld == true ) {
            flightTime.scheduleAtFixedRate(flight, 0 ,33);
    }
}

public void keyTyped(KeyEvent e) {
}

public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE){
spaceHeld = true;
//debug
System.out.println(spaceHeld);
}
}

public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE){
spaceHeld = false;
//debug
System.out.println(spaceHeld);
}
}
}
 

Ответ №1:

Код основан на событиях, и в настоящее время ничто не запускает ваши таймеры для запуска. Для этого вы можете просто переместить расписание таймера/начать действия внутри ключевых событий:

 public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_SPACE){

            //Cancel the other timer here so that they don't overlap
            gravity.cancel();
            gravityTime.cancel();

            //Create a new instance of the timer
            flightTime = new Timer();
            flight = new TimerTask() {
     
                public void run() {
                    if(velocity > -5) {
                        velocity -= 1;
                    }
                    else{
                        velocity = -5;
                    }
                    if (finalY < -61) {
                        finalY = finalY   velocity;
                    }
                    else{
                        finalY = -61;
                    }

                    player.setLocation(player.getX(), player.getY()   finalY);
                    if (player.getY() <= 0){
                        cancel();
                        velocity = 0;
                        finalY = 0;
                        player.setLocation(player.getX(), 0);
                    }  
                }
            };

            //Now start the timer
            flightTime.scheduleAtFixedRate(flight, 0 ,33);
        }
    }
    
    //Do the same for the gravity method
    public void keyReleased(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_SPACE){

            ......

        }
    }
}
 

Обратите внимание выше, что вы также должны отменить другую запланированную задачу с противоположными ключевыми событиями, чтобы они не перекрывали друг друга и не приводили к странным результатам.

И чтобы сделать flightTime gravityTime их доступными для метода с нажатой клавишей, просто объявите их как переменные класса:

 public class Game implements KeyListener {
    JFrame frame;
    JLabel player;

    public boolean grounded = false;
    public int velocity = 0;
    public int finalY = 0;
    public boolean spaceHeld = false;

    //Move them here but don't assign a value:
    public Timer flightTime;
    public TimerTask flight;
    public Timer gravityTime;
    public TimerTask gravity;
 

Вы все еще можете создать объект позже в игровом методе:

 flightTime = new Timer();
flight = new TimerTask() {
    ....
};
 

Комментарии:

1. Здравствуйте, этот метод сработал для меня, хотя я получаю исключение, в котором говорится, что задача гравитации уже запланирована. Есть какие-нибудь идеи?

2. @ZZBowzer Убедитесь, что он сначала отменяется gravity.cancel(); , прежде чем пытаться запустить его снова, или, если задача уже запущена, нет необходимости запускать ее снова, просто дайте ей запуститься?

3. Вы также можете переместить создание таймера в метод нажатия клавиши (см. Мой отредактированный код выше), но это все равно может создать проблемы с перекрытием таймеров, если они неправильно остановлены. Честно говоря, было бы лучше использовать один таймер/задачу для управления анимацией, которую никогда не нужно отменять/запускать, и просто заставить ее прочитать логическое значение, чтобы увидеть, должна ли она двигаться вверх или вниз.