我在java中制作乒乓球
如果球越界,pause
设置为true
:
if (ball.getX() <= 0) {
score2++;
pause = true;
}
if (ball.getX() >= this.getWidth()-ballWidth) {
score1++;
pause = true;
}
应该睡觉计时器......在线程休眠1000ms后,暂停将被设置为false并且球应该继续移动(ball.autoMove()
):
public void timer() {
int initialDelay = 1000;
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (pause) {
try {
ball.reset(width/2, height/2);
Thread.sleep(1000);
pause = false;
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
ball.autoMove(velocityX, velocityY);
collisionCheck();
}
}, initialDelay, 100);
}
Ball Class AutoMove()函数:
public void autoMove(double velX, double velY) {
xLoc = this.getX()+velX;
yLoc = this.getY()+velY;
}
它完成了所有这些...它睡眠,暂停设置为假等等......但是当球暂停1秒钟后重置球时(在屏幕中间重置...)跳到游戏面板的远端,告诉我当线程“正在睡觉”时,ball.autoMove(velocityX, velocityY);
仍在更新坐标。
为什么会这样?不应该不运行吗?
谢谢!
答案 0 :(得分:6)
指令
timer.scheduleAtFixedRate(new TimerTask() {...}, initial, 100 );
在1秒的睡眠期间,将10次出现的autoMove添加到计时器队列中。
以固定费率进行的安排是正确的,但您无需代替睡觉。
将计数器设置为10并在每次调用方法时将其递减,当它达到零时,继续按正常方式行进(与“暂停”方式相反)。
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if( pauseCount == 10 ) {
ball.reset(width/2, height/2);
}
if( pauseCount > 0 ) {
--pauseCount;
}
else {
ball.autoMove( velocityX, velocityY );
collisionCheck();
}
}
}, initialDelay, 100 );
在睡眠时按照执行日志。
首先是程序:
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
public class SO {
static boolean isTrue = true;
public static void main( String[] args ) {
new Timer().scheduleAtFixedRate( new TimerTask() {
@Override public void run() {
System.out.println(
System.currentTimeMillis() + ": " + Thread.currentThread());
try{
if( isTrue ) {
TimeUnit.SECONDS.sleep( 1 );
isTrue = false;
}
}
catch( InterruptedException e ){
e.printStackTrace();
}
}
}, 0, 100 );
}
}
记录日志,观察时间:
1369769673294: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main] <-- #1 at 308
1369769674308: Thread[Timer-0,5,main] <-- #2 at 308
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main]
1369769674308: Thread[Timer-0,5,main] <-- #10 at 308, queued during the sleep
1369769674402: Thread[Timer-0,5,main]
1369769674496: Thread[Timer-0,5,main]
1369769674605: Thread[Timer-0,5,main]
1369769674699: Thread[Timer-0,5,main]
1369769674808: Thread[Timer-0,5,main]
1369769674901: Thread[Timer-0,5,main]
1369769674995: Thread[Timer-0,5,main]
我们观察到激活就像排队一样,但事实上,类Timer只有一个线程。 这是模拟事件队列的逻辑,java.util.Timer的文档很清楚:
在固定费率执行中,每次执行都是相对于 初始执行的预定执行时间。如果执行是 因任何原因而延迟(例如垃圾收集或其他背景 活动),两个或多个执行将快速连续发生 “跟上来。”从长远来看,执行的频率将是 恰好是指定时期的倒数(假设系统 基础Object.wait(long)的时钟是准确的)。因此 以上,如果预定的第一次是过去,那么任何 “错过”的处决将被安排立即“追赶” 执行。
答案 1 :(得分:2)
当此线程处于休眠状态时,保证不会调用autoMove
。但是,在没有查看代码的情况下,我敢打赌,autoMove正在根据实时变化来移动球。一旦暂停结束,这将使球看起来跳跃,你再次调用autoMove。
您需要根据相对时间更改autoMove,否则您需要更改其使用的时间变量并减去暂停时间。
答案 2 :(得分:0)
很高兴看到改变暂停的完整代码。
你怎么知道它在睡觉时发生了什么?你可以添加带有时间戳的记录器吗?但我会采取刺。
如果在另一个线程中设置暂停,则需要对其进行同步,如果您将其声明为volatile,那么这是一个好主意。在这种方法中同步,并且正在设置暂停的地方。
private volatile Boolean pause = false;
//...
//make a setter and getter for pause
synchronized ( pause ){
return pause ;
}
synchronized ( pause ){
return pause = newPauseValue;
}