键盘输入驱动的Updater方法调用Player类绘图无响应问题求助
我帮你梳理下代码里的几个核心问题,这些就是导致调用Player绘图方法没反应的关键原因:
1. Player构造函数的变量覆盖陷阱
你的Player构造函数里犯了一个常见的新手错误:
public Player(int xPos, int yPos) { int x = xPos; int y = yPos; }
这里的int x和int y是局部变量,完全覆盖了类成员的x和y,导致成员变量一直是默认值0,根本没被初始化!改成用this指代成员变量就好了:
public Player(int xPos, int yPos) { this.x = xPos; this.y = yPos; }
2. Player的Graphics对象是空的
Player类里的Graphics g一直是null,调用drawPlayer()的时候肯定会抛出空指针异常(你可以看看控制台有没有报错)。正确的做法是把绘图需要的Graphics对象作为参数传给drawPlayer方法,而不是让Player自己持有一个g:
修改Player的drawPlayer方法:
public void drawPlayer(Graphics g) { g.setColor(Color.BLACK); g.fillRect(40*x, 40*y, 40, 40); }
之后在Game里调用时,把当前的Graphics传进去就行:p.drawPlayer(g);
3. 游戏线程根本没跑起来
你的Game类线程实现有问题:
if (loopThread == null) { loopThread = new Thread(); loopThread.start(); }
创建Thread时没有传入Runnable对象,这个线程的run方法是空的,不会执行你写的while循环!首先要让Game实现Runnable接口:
public class Game extends Applet implements Runnable { // ... 原有代码 }
然后创建线程时把this传进去:
loopThread = new Thread(this);
这样线程才会调用Game的run方法,循环才能正常执行。
4. 坐标系逻辑搞反了
AWT的坐标系里,左上角是(0,0),y轴是向下增长的,所以:
- 向上移动应该是
y--(y坐标减小) - 向下移动应该是
y++(y坐标增大)
但你的Player类里完全搞反了,修正一下:
public void goU() { y--; } public void goD() { y++; }
5. 绘图逻辑的正确姿势
AWT里的update方法默认会清屏然后调用paint,你应该把绘图逻辑放在paint方法里,每次绘图前先清掉之前的图像,不然会留下轨迹。修改Game的update和paint方法:
public void update(Graphics g) { // 先更新玩家位置 if(left) { p.goL(); left = false; } else if(right) { p.goR(); right = false; } else if(up) { p.goU(); up = false; } else if(down) { p.goD(); down = false; } // 调用paint绘图 paint(g); } public void paint(Graphics g) { // 清屏,用背景色填充整个区域 g.setColor(Color.WHITE); g.fillRect(0, 0, getWidth(), getHeight()); // 绘制玩家 p.drawPlayer(g); }
另外,Game里的Graphics g成员变量完全没必要,直接用方法参数里的g就行。
6. 初始状态的小调整
你把down初始设为true,会导致程序启动就自动向下移动,如果你不需要这个初始行为,改成boolean down = false;
修复后的完整代码示例
Game类
import java.applet.Applet; import java.awt.Color; import java.awt.Event; import java.awt.Graphics; public class Game extends Applet implements Runnable { Thread loopThread; boolean left = false; boolean right = false; boolean up = false; boolean down = false; // 修正初始值 Player p = new Player(0, 0); @Override public void start() { if (loopThread == null) { loopThread = new Thread(this); loopThread.start(); } } @Override public void run() { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); while (Thread.currentThread() == loopThread) { try { // 控制帧率,约每秒60帧 Thread.sleep(16); } catch (InterruptedException e) { e.printStackTrace(); } repaint(); // 触发update和paint } } @Override public void update(Graphics g) { // 更新玩家位置 if (left) { p.goL(); left = false; } else if (right) { p.goR(); right = false; } else if (up) { p.goU(); up = false; } else if (down) { p.goD(); down = false; } paint(g); } @Override public void paint(Graphics g) { // 清屏 g.setColor(Color.WHITE); g.fillRect(0, 0, getWidth(), getHeight()); // 绘制玩家 p.drawPlayer(g); } @Override public boolean keyDown(Event e, int key) { if (key == Event.LEFT) { left = true; } if (key == Event.RIGHT) { right = true; } if (key == Event.UP) { up = true; } if (key == Event.DOWN) { down = true; } return true; } }
Player类
import java.awt.Color; import java.awt.Graphics; public class Player { private int x; private int y; public Player(int xPos, int yPos) { this.x = xPos; this.y = yPos; } public void drawPlayer(Graphics g) { g.setColor(Color.BLACK); g.fillRect(40 * x, 40 * y, 40, 40); } public int getX() { return x; } public int getY() { return y; } public void goL() { x--; } public void goR() { x++; } public void goU() { y--; } public void goD() { y++; } }
这样修改后,你的盒子应该就能通过方向键正常移动了。虽然Applet是比较老旧的技术,但既然你偏好使用它,这些修改应该能解决你的问题。
内容的提问来源于stack exchange,提问作者Socks

