求助,Java如何响应同时按多个键盘按键?

时间:2023-02-20 09:25:48
求助,Java如何响应同时按多个键盘按键?
现在写个小游戏,当人物有移动和发射子弹的功能。
但是在移动的过程中发射子弹,人物就会停下来。
我想同时响应两个按键,互不影响。

还想问一下,
测试时感觉操作很不好,比如想一直往右走,按住右键会卡顿一下,才一直移动,
不知道有什么解决办法。

谢谢各位。

8 个解决方案

#1


上代码,okay?

#2


发上来代码:

public class PlayAct1 extends JPanel implements Runnable,KeyListener {

//背景图片
BufferedImage backgroundImage;
//主角
Gava gava;


public PlayAct1() {
// TODO Auto-generated constructor stub
init();
setBounds(0, 0, screenHeight, screenHeight);
setFocusable(true);
addKeyListener(this);
backgroundImage=Resource.backGrpundImages[0];
setVisible(true);
}

private void init() {

gava=new Gava(160, 560, 80, 80,Resource.gavaImages);
}

private void UpDateBG(){
gava.UpDateBullet();
}

public void run(){
while(true){
this.UpDateBG();
this.repaint();
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

@Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.drawImage(backgroundImage, 0, 0,this);
gava.DrawGava(g, this);
}

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

}

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

int key=e.getKeyCode();
switch (key) {
case KeyEvent.VK_W://跳跃
gava.Jump();break;
case KeyEvent.VK_A://向左移
gava.ToLeft();break;
case KeyEvent.VK_D://向右移
gava.ToRight();break;
case KeyEvent.VK_J://
gava.Shoot();break;
case KeyEvent.VK_F:
//gava.GetBullet(bullet);
default:
break;
}

}

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

}


}

#3


代码不全,Gave的代码呢?


#4


发子弹的时候人会停下来,我猜你就只有一个主线程控制整个游戏吧。如果说人在移动,并且可以发子弹,需要用两个线程控制,一个控制移动,一个控制发子弹。

#5


引用 3 楼 qq118194716 的回复:
代码不全,Gave的代码呢?


public class Gava{
//子弹数组用于保存3种子弹
private Bullet[] bullet=new Bullet[3];
//当前子弹的序号(0~2)
private int bulletID=0;
//速度
public int speed=10;
//跳跃高度
public int Jumpheight=90;
//0向左 1向右
public int direction=1;
//血量
public int hp=100;
//图像数组 0右立 1右跑 2左立 3左跑 4跳上 5跳下
public BufferedImage []image;
//当前显示图片,初始为右立
private BufferedImage nowImage;
//储存发射出的子弹
public Vector<Bullet> bullets;
//坐标
int x;
int y;
//宽高
int width;
int heigth;

public Gava(int x,int y,int width,int height,BufferedImage []image) {
this.x=x;
this.y=y;
this.width=width;
this.height=height;
//创建基础子弹,其他设为null
this.bullet[0]=new Bullet(x, y, 40, 40, 5, 300, 5,Resource.bulletImages[0]);
this.bullet[1]=null;
this.bullet[2]=null;
bullets=new  Vector<Bullet>(5, 5);
this.image=image;
nowImage=image[0];
}
//拾取武器,替换当前武器
public void GetBullet(Bullet bullet){
this.bullet[bulletID]=bullet;
}
//切换武器,改变当前武器的序号
public void SwitchBullet(){
bulletID++;
if(bulletID==3){
bulletID=0;
}
}
//向左走
public void ToLeft() {
//nowImage=image[]
direction=0;
x-=speed;
}
//向右走
public void ToRight() {
direction=1;
x+=speed;
}
//跳跃
public void Jump() {

}
//发射子弹
public void Shoot() {
if(direction==1){
bullet[bulletID].SetLocation(x+this.width, y+this.height/2-bullet[bulletID].height/2);
if(bullet[bulletID].speed<=0){
bullet[bulletID].speed=-bullet[bulletID].speed;
}
}else if(direction==0){
bullet[bulletID].SetLocation(x-bullet[bulletID].width, y+this.height/2-bullet[bulletID].height/2);
if(bullet[bulletID].speed>=0){
bullet[bulletID].speed=-bullet[bulletID].speed;
}
}
bullets.add(new Bullet(bullet[bulletID]));
}

public void UpDateBullet(){
for(int i=0;i<bullets.size();i++){
bullets.get(i).x+=bullets.get(i).speed;
}
}
public void DrawGava(Graphics g,JPanel panel){
g.drawImage(nowImage, x, y, width, height, (ImageObserver)panel);
for(int i=0;i<bullets.size();i++){
bullets.get(i).DrawBullet(g, panel);
}
}
}

public class Bullet{
//子弹的伤害
private int damageValue;
//射程,
public int range;
//射速,x轴每次移动距离
public int speed;
//子弹图片
public BufferedImage bulletImage;
//坐标
int x;
int y;
//宽高
int width;
int heigth;

public Bullet(int x,int y,int width,int height,int damageValue,int range,int speed,BufferedImage image) {
this.x=x;
this.y=y;
this.width=width;
this.height=height;
this.damageValue=damageValue;
this.range=range;
this.speed=speed;
this.bulletImage=image;
}
//构造 函数
public Bullet(Bullet bullet){
super(bullet.x, bullet.y, bullet.width, bullet.height);
damageValue=bullet.damageValue;
range=bullet.range;
speed=bullet.speed;
bulletImage=bullet.bulletImage;
}
//设置坐标
public void SetLocation(int x,int y){
this.x=x;
this.y=y;
}

//显示子弹
public void DrawBullet(Graphics g,JPanel mypanel){
g.drawImage(bulletImage, this.x, this.y,this.width,this.height,(ImageObserver)mypanel);
}
}

#6


引用 4 楼 crazypandariy 的回复:
发子弹的时候人会停下来,我猜你就只有一个主线程控制整个游戏吧。如果说人在移动,并且可以发子弹,需要用两个线程控制,一个控制移动,一个控制发子弹。


我是在面板里监听键盘,根据按键调用人物的移动和射击函数,我感觉是没有同时响应两个按键的原因。
能不能详细说一下怎么加线程。

#7


引用 6 楼 bihaobo 的回复:
Quote: 引用 4 楼 crazypandariy 的回复:

发子弹的时候人会停下来,我猜你就只有一个主线程控制整个游戏吧。如果说人在移动,并且可以发子弹,需要用两个线程控制,一个控制移动,一个控制发子弹。


我是在面板里监听键盘,根据按键调用人物的移动和射击函数,我感觉是没有同时响应两个按键的原因。
能不能详细说一下怎么加线程。

就是在你的程序启动后,创建俩线程,一个线程Move控制移动(该线程提供一个移动的方法),另一个线程Shoot 控制射击(提供一个射击的方法)。接收到移动按钮事件,调用Move的移动方法。收到射击按钮事件,调用Shoot方法。
给你一个简单的示例代码:
public class MoveThread extends Thread {

private XXX xxx;//
private LinkedBlockingQueue<Point> queue = new LinkedBlockingQueue<Point>();

public MoveThread(XXX xxx){
this.xxx = xxx;
}

public void move(int x,int y){
queue.add(new Point(x, y));
}

@Override
public void run() {
while(!Thread.interrupted()){
Point point = queue.take();
//下面根据point进行移动操作
xxx.xxx();
}
}
}

或者
public class MoveThread extends Thread {

private XXX xxx;//
private Point point;

public MoveThread(XXX xxx){
this.xxx = xxx;
}

public void move(int x,int y){
synchronized (this) {
point = new Point(x, y);
this.notifyAll();
}
}

@Override
public void run() {
while(!Thread.interrupted()){
synchronized (this) {
if(point==null){
this.wait();
}else{
//移动处理
point = null;//处理完之后,将point置为null
}
}
}
}
}

#8


需要看性价比高的键盘的,可以戳 【idzcp.com/?a=index&m=article&id=12】 看看,里边有按预算详细介绍的,整理的不错的,能节省不少挑选时间。  求助,Java如何响应同时按多个键盘按键?

#1


上代码,okay?

#2


发上来代码:

public class PlayAct1 extends JPanel implements Runnable,KeyListener {

//背景图片
BufferedImage backgroundImage;
//主角
Gava gava;


public PlayAct1() {
// TODO Auto-generated constructor stub
init();
setBounds(0, 0, screenHeight, screenHeight);
setFocusable(true);
addKeyListener(this);
backgroundImage=Resource.backGrpundImages[0];
setVisible(true);
}

private void init() {

gava=new Gava(160, 560, 80, 80,Resource.gavaImages);
}

private void UpDateBG(){
gava.UpDateBullet();
}

public void run(){
while(true){
this.UpDateBG();
this.repaint();
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

@Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.drawImage(backgroundImage, 0, 0,this);
gava.DrawGava(g, this);
}

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

}

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

int key=e.getKeyCode();
switch (key) {
case KeyEvent.VK_W://跳跃
gava.Jump();break;
case KeyEvent.VK_A://向左移
gava.ToLeft();break;
case KeyEvent.VK_D://向右移
gava.ToRight();break;
case KeyEvent.VK_J://
gava.Shoot();break;
case KeyEvent.VK_F:
//gava.GetBullet(bullet);
default:
break;
}

}

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

}


}

#3


代码不全,Gave的代码呢?


#4


发子弹的时候人会停下来,我猜你就只有一个主线程控制整个游戏吧。如果说人在移动,并且可以发子弹,需要用两个线程控制,一个控制移动,一个控制发子弹。

#5


引用 3 楼 qq118194716 的回复:
代码不全,Gave的代码呢?


public class Gava{
//子弹数组用于保存3种子弹
private Bullet[] bullet=new Bullet[3];
//当前子弹的序号(0~2)
private int bulletID=0;
//速度
public int speed=10;
//跳跃高度
public int Jumpheight=90;
//0向左 1向右
public int direction=1;
//血量
public int hp=100;
//图像数组 0右立 1右跑 2左立 3左跑 4跳上 5跳下
public BufferedImage []image;
//当前显示图片,初始为右立
private BufferedImage nowImage;
//储存发射出的子弹
public Vector<Bullet> bullets;
//坐标
int x;
int y;
//宽高
int width;
int heigth;

public Gava(int x,int y,int width,int height,BufferedImage []image) {
this.x=x;
this.y=y;
this.width=width;
this.height=height;
//创建基础子弹,其他设为null
this.bullet[0]=new Bullet(x, y, 40, 40, 5, 300, 5,Resource.bulletImages[0]);
this.bullet[1]=null;
this.bullet[2]=null;
bullets=new  Vector<Bullet>(5, 5);
this.image=image;
nowImage=image[0];
}
//拾取武器,替换当前武器
public void GetBullet(Bullet bullet){
this.bullet[bulletID]=bullet;
}
//切换武器,改变当前武器的序号
public void SwitchBullet(){
bulletID++;
if(bulletID==3){
bulletID=0;
}
}
//向左走
public void ToLeft() {
//nowImage=image[]
direction=0;
x-=speed;
}
//向右走
public void ToRight() {
direction=1;
x+=speed;
}
//跳跃
public void Jump() {

}
//发射子弹
public void Shoot() {
if(direction==1){
bullet[bulletID].SetLocation(x+this.width, y+this.height/2-bullet[bulletID].height/2);
if(bullet[bulletID].speed<=0){
bullet[bulletID].speed=-bullet[bulletID].speed;
}
}else if(direction==0){
bullet[bulletID].SetLocation(x-bullet[bulletID].width, y+this.height/2-bullet[bulletID].height/2);
if(bullet[bulletID].speed>=0){
bullet[bulletID].speed=-bullet[bulletID].speed;
}
}
bullets.add(new Bullet(bullet[bulletID]));
}

public void UpDateBullet(){
for(int i=0;i<bullets.size();i++){
bullets.get(i).x+=bullets.get(i).speed;
}
}
public void DrawGava(Graphics g,JPanel panel){
g.drawImage(nowImage, x, y, width, height, (ImageObserver)panel);
for(int i=0;i<bullets.size();i++){
bullets.get(i).DrawBullet(g, panel);
}
}
}

public class Bullet{
//子弹的伤害
private int damageValue;
//射程,
public int range;
//射速,x轴每次移动距离
public int speed;
//子弹图片
public BufferedImage bulletImage;
//坐标
int x;
int y;
//宽高
int width;
int heigth;

public Bullet(int x,int y,int width,int height,int damageValue,int range,int speed,BufferedImage image) {
this.x=x;
this.y=y;
this.width=width;
this.height=height;
this.damageValue=damageValue;
this.range=range;
this.speed=speed;
this.bulletImage=image;
}
//构造 函数
public Bullet(Bullet bullet){
super(bullet.x, bullet.y, bullet.width, bullet.height);
damageValue=bullet.damageValue;
range=bullet.range;
speed=bullet.speed;
bulletImage=bullet.bulletImage;
}
//设置坐标
public void SetLocation(int x,int y){
this.x=x;
this.y=y;
}

//显示子弹
public void DrawBullet(Graphics g,JPanel mypanel){
g.drawImage(bulletImage, this.x, this.y,this.width,this.height,(ImageObserver)mypanel);
}
}

#6


引用 4 楼 crazypandariy 的回复:
发子弹的时候人会停下来,我猜你就只有一个主线程控制整个游戏吧。如果说人在移动,并且可以发子弹,需要用两个线程控制,一个控制移动,一个控制发子弹。


我是在面板里监听键盘,根据按键调用人物的移动和射击函数,我感觉是没有同时响应两个按键的原因。
能不能详细说一下怎么加线程。

#7


引用 6 楼 bihaobo 的回复:
Quote: 引用 4 楼 crazypandariy 的回复:

发子弹的时候人会停下来,我猜你就只有一个主线程控制整个游戏吧。如果说人在移动,并且可以发子弹,需要用两个线程控制,一个控制移动,一个控制发子弹。


我是在面板里监听键盘,根据按键调用人物的移动和射击函数,我感觉是没有同时响应两个按键的原因。
能不能详细说一下怎么加线程。

就是在你的程序启动后,创建俩线程,一个线程Move控制移动(该线程提供一个移动的方法),另一个线程Shoot 控制射击(提供一个射击的方法)。接收到移动按钮事件,调用Move的移动方法。收到射击按钮事件,调用Shoot方法。
给你一个简单的示例代码:
public class MoveThread extends Thread {

private XXX xxx;//
private LinkedBlockingQueue<Point> queue = new LinkedBlockingQueue<Point>();

public MoveThread(XXX xxx){
this.xxx = xxx;
}

public void move(int x,int y){
queue.add(new Point(x, y));
}

@Override
public void run() {
while(!Thread.interrupted()){
Point point = queue.take();
//下面根据point进行移动操作
xxx.xxx();
}
}
}

或者
public class MoveThread extends Thread {

private XXX xxx;//
private Point point;

public MoveThread(XXX xxx){
this.xxx = xxx;
}

public void move(int x,int y){
synchronized (this) {
point = new Point(x, y);
this.notifyAll();
}
}

@Override
public void run() {
while(!Thread.interrupted()){
synchronized (this) {
if(point==null){
this.wait();
}else{
//移动处理
point = null;//处理完之后,将point置为null
}
}
}
}
}

#8


需要看性价比高的键盘的,可以戳 【idzcp.com/?a=index&m=article&id=12】 看看,里边有按预算详细介绍的,整理的不错的,能节省不少挑选时间。  求助,Java如何响应同时按多个键盘按键?