Java 如何同时收听多个按键输入

Java 如何同时收听多个按键输入,java,swing,Java,Swing,我试图用Java创建一个简单的乒乓球游戏,但我不知道如何让两个玩家同时使用键盘。游戏不完整,目前我正在为两名玩家进行划桨运动。问题是,当一个玩家按下向上键并向上移动他们的划桨时,如果其他玩家点击了他们的任何键,则会取消先前的玩家操作并导致划桨停止。我想我需要一种同时处理多个键输入的方法。下面是我的代码底部的KeyListeners是我需要帮助的地方。我只是一名1年的Java程序员,所以我的代码中的其他部分要轻松一些 import java.awt.Color; import java.awt.G

我试图用Java创建一个简单的乒乓球游戏,但我不知道如何让两个玩家同时使用键盘。游戏不完整,目前我正在为两名玩家进行划桨运动。问题是,当一个玩家按下向上键并向上移动他们的划桨时,如果其他玩家点击了他们的任何键,则会取消先前的玩家操作并导致划桨停止。我想我需要一种同时处理多个键输入的方法。下面是我的代码底部的KeyListeners是我需要帮助的地方。我只是一名1年的Java程序员,所以我的代码中的其他部分要轻松一些

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.*;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashSet;
import java.util.Set;

public class DrawGame extends JPanel implements ActionListener{
    public static final int XPOS = 0;
    public static final int YPOS = 0;
    public boolean xFlag = true; // true means ballx is going right
    public boolean yFlag = true; // true means bally is going down
    public int ballX = 300; // Ball starting point
    public int ballY = 400; // Ball starting point
    Timer ballTimer; // Starts balls animation

    public int leftScore;
    public int rightScore;

    public int rightPadY; // Right players paddle position
    public int leftPadY; // left players paddle position

    // Constructor
    public DrawGame(){
        addKeyListener(new RightListener());
        addKeyListener(new LeftListener());

        leftScore = 0;
        rightScore = 0;

        rightPadY = YPOS + 230;
        leftPadY = YPOS + 230;

        setBackground(Color.BLACK);
        setPreferredSize(new Dimension(800, 600));
        setFocusable(true);

        ballTimer = new Timer(10, this);
        ballTimer.start();
    }

    // Draws game
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;

        //Drawing Side Boards
        g2d.setColor(Color.WHITE);
        g2d.fillRect(XPOS + 5, YPOS + 20, 775, 25); // Top Board
        g2d.fillRect(XPOS + 5, YPOS + 517, 775, 25); // Bottom board

        //Drawing the center line
        g2d.fillRect(XPOS + 377, YPOS + 45 * 1, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 2, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 3, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 4, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 5, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 6, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 7, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 8, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 9, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 10, 25, 25);
        g2d.fillRect(XPOS + 377, YPOS + 45 * 11, 25, 25);

        //Drawing the paddles
        g2d.fillRect(XPOS + 10, leftPadY, 20, 100);// Left
        g2d.fillRect(XPOS + 755, rightPadY, 20, 100); // Right

        //Drawing the ball
        g2d.fillRect(ballX, ballY, 23, 23); 

        //Drawing the score
        switch(leftScore){
            case 0:
                g2d.fillRect(XPOS + 305, YPOS + 50, 7, 30);
                g2d.fillRect(XPOS + 325, YPOS + 50, 7, 30);
                g2d.fillRect(XPOS + 305, YPOS + 50, 25, 7);
                g2d.fillRect(XPOS + 305, YPOS + 80, 27, 7);
                break;
            case 1:
                g2d.fillRect(XPOS + 325, YPOS + 50, 7, 30);
        }

        switch(rightScore){
            case 0:
                g2d.fillRect(XPOS + 450, YPOS + 50, 7, 30);
                g2d.fillRect(XPOS + 470, YPOS + 50, 7, 30);
                g2d.fillRect(XPOS + 450, YPOS + 50, 25, 7);
                g2d.fillRect(XPOS + 450, YPOS + 80, 27, 7);
                break;
            case 1:
                g2d.fillRect(XPOS + 450, YPOS + 50, 7, 30);
        }
    }

    // Controls the animation of the ball
    public void actionPerformed(ActionEvent e){
        if(xFlag == true && ballX >= 735){
            ballX += 2;
            xFlag = false;
        } else if(xFlag == true){
            ballX += 2;
        }

        if(xFlag == false && ballX <= 25){
            ballX -= 2;
            xFlag = true;
        } else if(xFlag == false){
            ballX -= 2;
        }

        if(yFlag == true && ballY >= 500){
            ballY += 2;
            yFlag = false;
        } else if(yFlag == true){
            ballY += 2;
        }

        if(yFlag == false && ballY <= 45){
            ballY -= 2;
            yFlag = true;
        } else if(yFlag == false){
            ballY -= 2;
        }
        repaint();
        ballTimer.restart();
    }

    // Keylistener for right player
    private class RightListener implements KeyListener{

        @Override
        public synchronized void keyPressed(KeyEvent event) {
            if(event.getKeyCode() == KeyEvent.VK_UP){
                rightPadY -= 5;
            }else if(event.getKeyCode() == KeyEvent.VK_DOWN){
                rightPadY += 5;
            }
            repaint();
        }

        @Override
        public synchronized void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public synchronized void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub

        }
    }

    // Keylistener for left player
    private class LeftListener implements KeyListener{
        @Override
        public synchronized void keyPressed(KeyEvent event) {
            if(event.getKeyCode() == KeyEvent.VK_W){
                leftPadY -= 5;
            } else if(event.getKeyCode() == KeyEvent.VK_S){
                leftPadY += 5;
            }
            repaint();
        }

        @Override
        public synchronized void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public synchronized void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub

        }
    }




}
导入java.awt.Color;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入javax.swing.*;
导入java.awt.*;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.KeyEvent;
导入java.awt.event.KeyListener;
导入java.util.HashSet;
导入java.util.Set;
公共类DrawGame扩展JPanel实现ActionListener{
公共静态最终int XPOS=0;
公共静态最终int YPOS=0;
public boolean xFlag=true;//true表示ballx运行正常
公共布尔值yFlag=true;//true表示bally正在下降
public int ballX=300;//球的起点
public int ballY=400;//球的起点
计时器ballTimer;//启动球动画
公共积分;
公共积分;
public int rightPadY;//右球员划桨位置
public int leftPadY;//左球员的划桨位置
//建造师
公众游戏(){
addKeyListener(新的RightListener());
addKeyListener(新的LeftListener());
leftScore=0;
rightScore=0;
rightPadY=YPOS+230;
leftPadY=YPOS+230;
挫折背景(颜色:黑色);
设置首选尺寸(新尺寸(800600));
设置聚焦(真);
ballTimer=新计时器(10,此);
ballTimer.start();
}
//平局
公共组件(图形g){
超级组件(g);
Graphics2D g2d=(Graphics2D)g;
//绘图侧板
g2d.setColor(Color.WHITE);
g2d.fillRect(XPOS+5,YPOS+20775,25);//顶板
g2d.fillRect(XPOS+5,YPOS+51775,25);//底板
//画中心线
g2d.fillRect(XPOS+377,YPOS+45*1,25,25);
g2d.fillRect(XPOS+377,YPOS+45*2,25,25);
g2d.fillRect(XPOS+377,YPOS+45*3,25,25);
g2d.fillRect(XPOS+377,YPOS+45*4,25,25);
g2d.fillRect(XPOS+377,YPOS+45*5,25,25);
g2d.fillRect(XPOS+377,YPOS+45*6,25,25);
g2d.fillRect(XPOS+377,YPOS+45*7,25,25);
g2d.fillRect(XPOS+377,YPOS+45*8,25,25);
g2d.fillRect(XPOS+377,YPOS+45*9,25,25);
g2d.fillRect(XPOS+377,YPOS+45*10,25,25);
g2d.fillRect(XPOS+377,YPOS+45*11,25,25);
//划桨
g2d.fillRect(XPOS+10,leftPadY,20100);//左
g2d.fillRect(XPOS+755,rightPadY,20100);//右
//拉球
g2d.fillRect(ballX,ballY,23,23);
//得分
开关(左键){
案例0:
g2d.fillRect(XPOS+305,YPOS+50,7,30);
g2d.fillRect(XPOS+325,YPOS+50,7,30);
g2d.fillRect(XPOS+305,YPOS+50,25,7);
g2d.fillRect(XPOS+305,YPOS+80,27,7);
打破
案例1:
g2d.fillRect(XPOS+325,YPOS+50,7,30);
}
开关(右键){
案例0:
g2d.fillRect(XPOS+450,YPOS+50,7,30);
g2d.fillRect(XPOS+470,YPOS+50,7,30);
g2d.fillRect(XPOS+450,YPOS+50,25,7);
g2d.fillRect(XPOS+450,YPOS+80,27,7);
打破
案例1:
g2d.fillRect(XPOS+450,YPOS+50,7,30);
}
}
//控制球的动画
已执行的公共无效操作(操作事件e){
if(xFlag==true&&ballX>=735){
ballX+=2;
xFlag=false;
}else if(xFlag==true){
ballX+=2;
}
如果(xFlag==false&&ballX=500){
ballY+=2;
yFlag=假;
}else if(yFlag==true){
ballY+=2;
}

如果(yFlag==false&&ballY最好使用一个线程来制作动画。当你按下
键时,我们会告诉程序键已按下。在
键已释放时,我们会告诉程序键已打开。在线程中,我们会读取该值并确定是否要移动。这也会更加平滑

首先,您需要在某些类中实现
Runnable
,甚至可以在主类中实现。 添加
public void run
方法

在它里面会有这样的东西:

while(true)
{
    if(player1.upkeyIsDown() && player1.downKeyIsUp())
    {
         //move Player1 Up
    }
    else if(player1.downKeyIsDown() && player1.upKeyIsUp())
    {
         //move Player1 Down
    }
    //do similar for player 2
    try{
        Thread.sleep(50);
    }
    catch(InterruptedException ie)
    {
        ie.printStackTrace();
    }
}
这是半伪代码,您必须实现如何保存关闭的密钥。在KeyListener中,您需要调用main类中的某些内容来更改这些值,然后此线程将处理其余的


此线程也需要启动。在主/构造函数的某处编写
新线程(This).start();

不要使用KeyListener。应该使用
键绑定

有关更多信息,请参阅

我从上面的链接将以下代码添加到
KeyboardAnimation
示例中,这将允许您执行所需操作:

JLabel label2 = new JLabel( new ColorIcon(Color.GREEN, 40, 40) );
label2.setSize( label2.getPreferredSize() );
label2.setLocation(500, 500);
contentPane.add( label2 );

KeyboardAnimation animation2 = new KeyboardAnimation(label2, 24);
animation2.addAction("A", -3,  0);
animation2.addAction("D", 3,  0);
animation2.addAction("W",    0, -3);
animation2.addAction("S",  0,  3);

避免将
KeyListener
用于非文本组件。请改用。请去掉
synchronized
关键字,因为1)由于所有Swing代码都在单个线程上运行,因此不需要它。使用KeyDown和KeyUp与线程一起使用,而不是使用KeyPressed。KeyPressed取决于系统的按键重复速度。一个