如何修复java keyPressed Lag / Late事件

时间:2014-05-18 09:38:55

标签: java swing keypress lag event-listener

我有点像这样的菜鸟但是试图创造我自己的马里奥游戏。 它进展顺利,但我需要一个名为distanceTraveled的变量来确定

它根本不可靠,当我按住箭头键数字比我点击它们时更快。

这是我的代码(一切都在右边评论):

frame.java

package EvilMario;                                                                               //Include this class in the EvilMario game package

import javax.swing.JFrame;                                                                       //Import the JFrame

public class frame {                                                                             //Run this class to run the game
    public static void main(String[] args) {                                                     //The first method called by java
        JFrame frame = new JFrame("EvilMario v.1.0.0 by Max Mastalerz");                         //Create JFrame called frame

        frame.getContentPane().add(new board());                                                 //Go to board class
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);                                    //Make frame close on X click
        frame.setSize(600,413);                                                                  //Set the frame size to the size of the background
        frame.setVisible(true);                                                                  //Make the frame visible
        frame.setResizable(false);                                                               //Make sure the user can't resize the frame
    }
}

player.java

package EvilMario;                                                                               //Include this class in the EvilMario game package

import java.awt.Image;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;

public class player {
    int x, dx, y, nx, nx2, distanceTraveled;                                                     //x coordinate,change in x coordinate,y coordinate,1st rep bg,2nd rep bg,dist traveled
    Image player;                                                                                //The player variable
    ImageIcon playerFacingLeft = new     ImageIcon("D:/ICS3U1/EvilMario/images/MarioLeft.png");  //Image for player while he is     turning left
    ImageIcon playerFacingRight = new     ImageIcon("D:/ICS3U1/EvilMario/images/MarioRight.png");//Image for player while he is turning right

        public player() {
            player = playerFacingRight.getImage();                                           //Give the player the image
            x = 75;                                                                          //The original x position of the player
            y = 265;                                                                         //The original y position of the player
            nx = -0;                                                                         //Repeating background 1
            nx2 = -575;                                                                      //Repeating background 2
            distanceTraveled = 0;
        }

        public void move() {
            if(x>0 && x<300) {                                                               //If the player is within the moving area
                x = x+dx;                                                                    //The x position is updated to become itself+the amount you moved
                nx = nx+dx;                                                                  //Place the repeating background at regular speed
                nx2 = nx2+dx;                                                                //Place the repeating background at regular speed
            }
            if(x==0) {                                                                       //If the player has reached he very left side of the screen(0px)
                x=1;                                                                         //Move him up a pixel so he can move again

                nx = nx+(dx*(int)0.5);                                                       //Place the background at a slower speed since Mario stops moving
                nx2 = nx2+(dx*(int)0.5);                                                     //Place the background at a slower speed since Mario stops moving

            }
            if(x==300) {                                                                     //If the player has reached the center of the screen(300px)
                x=299;                                                                       //Move him down a pixel so he can move again
                nx = nx+(dx*(int)0.5);                                                       //Place the background at a slower speed since Mario stops moving
                nx2 = nx2+(dx*(int)0.5);                                                     //Place the background at a slower speed since Mario stops moving
            }
            System.out.println(distanceTraveled);
        }

        public int   getX()     { return x;      }                                           //This method will return the x.      Is used by other classes
        public int   getY()     { return y;      }                                           //This method will return the y.      Is used by other classes
        public Image getImage() { return player; }                                           //This method will return the player. Is used by other classes

        public void keyPressed(KeyEvent e) {                                                 //Called from the board class, the argument is whatever key was pressed
            int key = e.getKeyCode();                                                        //The key originally sent from the board class

            if(key == KeyEvent.VK_LEFT) {                                                    //If the key sent was LEFT
                player = playerFacingLeft.getImage();                                        //Make the player face leftwards
                dx = -1;
                distanceTraveled--;
            }

            if(key == KeyEvent.VK_RIGHT) {                                                   //If the key sent was RIGHT
                player = playerFacingRight.getImage();                                       //Make the player face rightwards
                dx = 1;                                                                      //Move right
                distanceTraveled++;
            }
        }

        public void keyReleased(KeyEvent e) {                                                //Called from the board class, the argument is whatever key was released
             int key = e.getKeyCode();                                                        //The key originally sent from the board class

            if(key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT)                          //If the left or right key was released
                dx = 0;                                                                      //Stop moving
        }
}

board.java

package EvilMario;                                                                           //Include this class in the EvilMario game package

import java.awt.*;                                                                           //Imported to allow use of Image
import java.awt.event.*;                                                                     //Imported to allow use of ActionListener

import javax.swing.*;

public class board extends JPanel implements ActionListener {
player p;                                                                                        //Instance of player class
Image background;                                                                            //The background variable
Timer time;                                                                                  //A timer

    public board() {
        p = new player();                                                                    //Start running player class
        addKeyListener(new AL());                                                            //Listen for keys
        setFocusable(true);                                                                  //Allows movement                      
        ImageIcon i = new ImageIcon("D:/ICS3U1/EvilMario/images/EvilMario_Background.png");  //Image for background
        background = i.getImage();                                                           //Give the background the image
        time = new Timer(7,this);                                                            //Timer set to update "this" class every 5 milliseconds
        time.start();                                                                        //Actually start the timer
    }

    public void actionPerformed(ActionEvent e) {
        p.move();                                                                            //Call the move method from the player class
        repaint();                                                                           //Repaint
    }

    public void paint(Graphics g) {                                                          //Graphics method
        super.paint(g);
            Graphics2D g2d = (Graphics2D) g;                                                 //casts 2d graphics(or however you would explain it)

            g2d.drawImage(background, -p.nx, 0, null);                                       //Draw the background image
            g2d.drawImage(background, -p.nx2, 0, null);                                      //Draw the background image

            if(-p.nx<-575)                                                                   //If going forwards
                p.nx=-575;                                                                   //Start placing forwards every 575px in front on the last one
            else if(-p.nx>575)                                                               //If going backwards
                p.nx=575;                                                                    //Start placing backwards every 575px behind the last one

             if(-p.nx2<-575)                                                                  //If going forwards
                p.nx2=-575;                                                                  //Start placing forwards every 575px in front on the last one
            else if(-p.nx2>575)                                                              //If going backwards
                p.nx2=575;                                                                   //Start placing backgrounds every 575px behind the last one

            g2d.drawImage(p.getImage(), p.getX(), p.getY(), null);                           //Draw the player at the position he is currently(Coordinate values taken from player class)
        }

    private class AL extends KeyAdapter {                                                    //Action Listener extends key adapter
        public void keyPressed(KeyEvent e) {                                                 //On key press
            p.keyPressed(e);                                                                 //Send whatever key was pressed  TO the keyPressed  method in the player class
        }
        public void keyReleased(KeyEvent e) {                                                //On key release
            p.keyReleased(e);                                                                //Send whatever key was released TO the keyReleased method in the player class
        }
    }
}

如果你想自己测试这个游戏,你将需要这三个图像

EvilMario_Background.png

EvilMario_Background.png

MarioLeft.png

MarioLeft.png

MarioRight.png

MarioRight.png

同时更改目录 我一直在尝试太多的东西并没有想出任何东西,如果你想到这一点,我将永远感激:)

1 个答案:

答案 0 :(得分:2)

而不是尝试计算关键事件处理程序中的距离,而是在move方法中计算它。这将基于dx的值大于或小于0

  • 您确实应该按惯例使用paintComponent,而不是paint
  • 您应该考虑使用key bindings API,因为它解决了与KeyListener
  • 相关的许多问题
  • 我更依赖于width的实际heightJPanel属性,而不是&#34;魔法&#34;数字。这里的问题是不同的平台和外观有不同的框架边框大小,这将影响这些值。考虑覆盖getPreferredSize中的board以返回游戏画布的首选大小。然后,您可以在框架上使用pack
  • 在尝试调整大小或显示窗口之前调用setResizable,这会改变框架边框的大小并更改可视区域的大小......
  • 7毫秒延迟类似于143fps ......我非常怀疑你真的需要那种刷新率。 40毫秒是25fps,我敢告诉你区别,事件60fps只有16毫秒。不要改变刷新率的速度,改变delta值的速度来改变游戏的速度......只是说;)