【问题标题】:Trying to move object with KeyListener in simple game尝试在简单游戏中使用 KeyListener 移动对象
【发布时间】:2014-07-29 09:19:41
【问题描述】:

我正在尝试创建一个类似于打砖块的简单游戏。我能够弄清楚游戏的一些基本概念(移动球,碰撞检测等)

我正在尝试使用左右箭头键在 x 方向上移动平台对象。在使用一些 println 语句进行测试后,keyPressed 方法的 if 条件有效,但我无法使用 keyListener 移动平台对象。 Is 与 Platform 类中的 moveLeft 、 moveRight 方法有关,因为我尝试 d 来更改 dx 的值,所以我可能会看到平台中的一些运动。

这里有 3 个类。

import java.applet.*; 
import java.awt.*; 
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;

public class tennisGame extends Applet implements Runnable, KeyListener{ 

Ball b;
Platform p;

public void init() { 

    setSize(640, 480);
    addKeyListener(this);
} 

public void start () { 
    b= new Ball();
    p= new Platform();
    Thread thread = new Thread (this); 
    thread.start (); 
}

public void paint(Graphics g) { 
    b.paint(g);
    p.paint(g);

}
public void run(){
    while (true){
        b.update(this);
        p.update(this,b);
        repaint();
        try {
            Thread.sleep(20);
        }
        catch (InterruptedException e){
            //e.printStackTrace();
        }
    }
}
@Override
public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == e.VK_RIGHT){
        System.out.println("Pressed RIGHT");
        p.moveRight();
    }
    if(e.getKeyCode() == e.VK_LEFT){
        System.out.println("Pressed LEFT");
        p.moveLeft(); 
    }
}
@Override
public void keyReleased(KeyEvent e) {

}
@Override
public void keyTyped(KeyEvent e) {

}
}


import java.awt.*; 

public class Ball{ 
private int x=0;
private int y=0; 
private double dx=10;
private double dy=10;
private int width=20;
private int height=20;
private int radius=10;

public Ball() {

}

public void update(tennisGame tg){

    if ( x + dx > tg.getWidth()-radius-1){
        x = tg.getWidth()-radius-1;
        dx= -dx;
    }
    else if ( x + dx < 0 + radius ){
        x= 0 + radius;
        dx= -dx;
    }
    else{
        x+=dx;
    }

    if ( y + dy> tg.getHeight()-radius-1){
        y = tg.getHeight()-radius-1;
        dy= -dy;
    }
    else if ( y + dy < 0 + radius ){
        y= 0 + radius;
        dy= -dy;
    }
    else{
        y+=dy;
    }
}

public int getX() {
    return x;
}
public void setX(int x) {
    this.x = x;
}
public int getY() {
    return y;
}
public void setY(int y) {
    this.y = y;
}
public double getDx() {
    return dx;
}
public void setDx(int dx) {
    this.dx = dx;
}
public void setDy(double dy) {
    this.dy = dy;
}
public double getDy() {
    return dy;
}
public int getRadius() {
    return radius;
}

public void paint(Graphics g) { 
    g.setColor(new Color(0,0,250,250));
    g.fillOval(x-radius,y-radius,width, height);
}
}


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

public class Platform {

private int x=275;
private int y=400;
int dx=0;
private int width=120;
private int height=20;


public void update(tennisGame tg,Ball b) {
    checkForCollosion(b);
}

private void checkForCollosion(Ball b) {

    int ballX= b.getX();
    int ballY= b.getY();
    int radius= b.getRadius();

    if (ballY + radius > y && ballY + radius < y + height){
        if (ballX > x && ballX < x + width){
            double newDy= b.getDy()* -1 ;
            b.setDy(newDy);
        }
    }
}

public void moveRight() {
    if ( dx + 1 < 20){
        dx+=1;
    }
}
public void moveLeft() {
    if ( dx -1 > -20){
        dx-=1;
    }
}
public void paint(Graphics g){
    g.setColor(Color.red);
    g.fillRect(x , y, width, height);
}

}

【问题讨论】:

  • 那么,您的关键听众有什么问题?它在做什么?它应该做什么?只是转储你的代码并说“我被卡住了,为我写它”不会给你一个有用的答案。
  • 我有另一段左右的信息描述了我的问题,哈哈,可能会意外删除它。但我正在尝试使用左右箭头键在 x 方向上移动平台,但对象不会移动。
  • 您应该编辑您的问题以重新添加该段落。
  • 已添加!提前致谢

标签: java applet awt keylistener


【解决方案1】:

您的第一个问题是,在您的 moveRight()moveLeft() 方法中,您正在检查和更新 dx 的值,而在您的代码中关于平台绘制的任何地方都没有使用它。

例如

public void moveRight() {
    if (dx + 1 < 20) {
        dx += 1; // updating dx, but x is used to paint
    }
}
public void moveLeft() {
    if (dx - 1 > -20) {
        dx -= 1; // updating dx, but x is used to paint
    }
}

即使我们将您的方法更改为使用x 而不是dx,您的第二个问题是增加或减少一个像素不会移动太多。但是,如果您按住左箭头键的时间足够长,平台就会慢慢爬行。由于您的第三个问题:边界检查,当您按下正确的数组时(一开始)什么都不会发生。

移动方法中的边界检查基于 20 的 x 值,但 x 的初始值为 275

public void moveRight() {
    if (x + 1 < 20) { // can't move very far from the left side of the screen
        x += 1;
    }
}
public void moveLeft() {
    if (x - 1 > -20) { // goes left only a little bit off the screen
        x -= 1;
    }
}

您需要使用反映小程序大小的值。此代码有效,但由于时间原因,我刚刚硬编码了边界值。你真的应该根据tennisGame的大小来计算它们:

public void moveRight() {
    if (x < 520) {     // enable moving to the edge of the screen
        x += 10;   // move a little faster
    }
}
public void moveLeft() {
    if (x > 0) {       // enable moving to the edge of the screen
        x -= 10;   // move a little faster
    }
}

【讨论】:

    【解决方案2】:
    1. 致电super.paint 或为更多怪事做好准备
    2. KeyListener 只会在它注册到的组件是可聚焦的并且有焦点时响应关键事件
    3. 考虑使用 Swing API 而不是 AWT。 AWT 组件不是双缓冲的,更新时会闪烁。相反,从JPanel 之类的内容开始,然后将其添加到您想要的任何内容中

    您可以致电 setFocusable(true)requestFocusInWindow(),但不能保证它会在 100% 的时间内正常工作或继续工作。

    相反,更新代码以使用 Swing 并利用 key bindings API,它使您能够控制触发关键事件所需的焦点级别

    更新...

    例如,您也没有更新Platformx 位置...

    public void update(Tennis tg, Ball b) {
        x += dx;
        checkForCollosion(b);
    }
    

    现在这将要求您对 Platform 执行范围检查,以查看是否超出视图的可见范围,如果您对此类事情...

    我最后还添加了一个MouseListener,每次点击它时都会调用requestFocusInWindow,例如...

    addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            requestFocusInWindow();
        }
    });
    

    这就是为什么我不喜欢 applet 或 KeyListener 的原因

    【讨论】:

    • 我在tennisGame类的paint方法中尝试了super.paint(g),还是不行。我把它放在正确的位置了吗?
    • 它应该是您在 paint 方法中进行的第一次调用。
    • 哪一部分?如果是关于键盘命令的,请参见 cmets 的请求
    • 我有 super.paint(g) 作为tennisGame类中paint方法的第一行。
    • super.paint 是为了尊重绘制链并确保 UI 已正确更新,它不会解决您当前的问题,但有助于防止未来的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多