2

我的最后一个项目(也是最大的:))是乒乓球比赛。我正在尝试实现“AI”,但我不能这样做,因为

Exception in thread "Timer-0" java.lang.NullPointerException
    at main.Ball$1.run(Ball.java:25)
    at java.util.TimerThread.mainLoop(Unknown Source)
    at java.util.TimerThread.run(Unknown Source)

我想我已经把整个代码写得很好,但肯定有问题。

Main.java - http://pastebin.com/nvHwQAFD

Ball.java - http://pastebin.com/cgE5r5eW

Player.java - pastebin.com/7QeiNciz

ai.java - pastebin.com/xsGhJ7Zb(只有两个超链接,防止垃圾邮件)

代码写得不好,我希望你不会去(得到?)盲目 :)

问候,阿德里安

4

3 回答 3

8

你有一个比赛条件。

当您调用Ball构造函数时,它会立即调用movement()调度有问题的代码(诚然在不同的线程中)。所有这一切都发生在Main构造函数的中间,然后 Main.player才被赋值。所以在movement()这里:

if(main.player.intersects(main.ball) && hitP == false){

...main.player如果计时器线程启动得足够快,则仍然为 null,因此main.player.intersects调用会引发异常。(main.ball也是空的,但这实际上并不会导致您看到的问题。但它仍然是一个问题。)

需要学习的几个教训:

  • 不要在构造函数中做太多
  • 理想情况下,尽量避免创建这种循环引用,或者如果您必须拥有一个,请确保在开始实际工作之前一切都已初始化
  • 让你的类名更有意义:作为一个程序的入口点Main很好,但是创建一个类型的对象Main对我来说听起来很可疑。什么Main? _ 你会如何描述它?
  • 不要滥用继承 - 没有理由Ball应该扩展Thread(你说implements Runnable但你自己没有提供run()方法Ball
  • 避免与trueor比较false- writeif (foo)而不是if (foo == true)andif (!foo)而不是if (foo == false)
  • 让你的变量名有意义——根据我之前的评论,在你有一个变量调用的同一个类中调用一个Rectangle变量是自找麻烦playerPlayerp
  • 将所有变量设为私有,如果需要,可以通过属性公开它们。(除非你真的需要,否则不要暴露它们)
  • 缩进很重要——正确缩进你的代码会更容易阅读
  • 在您真正熟悉该语言的基础知识之前,请避免使用线程——这很难,并且会引入各种微妙的问题
于 2012-07-07T15:49:56.410 回答
2

在您的代码中,您ball.movement()在第 17 行调用,然后在第 18 行分配main一个非空值。

于 2012-07-07T15:49:55.597 回答
0

此行:player = new Rectangle(p.getX(), p.getY(), 10, 50);在 Main line 18 必须b = new Ball(this);在 Main line 15 之前。否则当你调用移动时 player 为 null。

于 2012-07-07T15:52:52.077 回答