我正在尝试开发一种名为Shaking的Cookie Clicker应用程序。
如果您不知道Cookie Clicker是什么:
Cookie Clicker是一款游戏,你点击一个cookie来“烘焙”一个cookie。您尝试获得尽可能多的cookie,您可以使用cookie来购买可以帮助您烘焙饼干的东西。例如,您可以使用50个cookie来购买光标,该光标每10秒自动为您的cookie计数添加一个。您可以购买的每件商品都有Cps金额(每秒Cookie)。所以光标是0.1 Cps。
在我的游戏版本中,您摇动手机而不是点击Cookie。所以Cps变成了赫兹!
现在我想做的是不是每秒都增加抖动次数,而是每隔一段时间增加抖动次数。我真的没有解释清楚,是吗?例如,如果玩家拥有100Hz的东西,我不想每秒将抖动数增加100,我想每0.01秒增加1!我已经使用Android的Handler
类编写了一个计时器类,但这没有关联。
以下是我的尝试:
我创建了一个TimerTuple
类来存储一个计时器间隔,并且每隔一个间隔就会增加一次抖动量。所以在上面的例子中,定时器间隔为10毫秒,增加的数量为1.顺便说一下,我使用BigDecimal
作为Hz,因为它可能会变得非常大。
这是班级,没什么特别的:
// This is an inner class. Don't tell me that I cannot use static in a class definition!
private static class TimerTuple {
private BigDecimal shakeIncrement;
private int timerInterval;
public TimerTuple(BigDecimal shakeIncrement, int timerInterval) {
this.shakeIncrement = shakeIncrement;
this.timerInterval = timerInterval;
}
}
我编写了一个名为getTimerTuple
的方法,它返回一个TimerTuple
,这样我就可以使用这些信息来设置计时器的间隔,并添加正确的抖动数量。
private TimerTuple getTimerTuple () {
int timerInterval = 1000;
BigDecimal shakeIncrement = new BigDecimal(getCurrentHz ());
if (shakeIncrement.toBigInteger ().compareTo (BigInteger.ZERO) == 0) {
return new TimerTuple (BigDecimal.ZERO, 1);
}
if (shakeIncrement.compareTo (new BigDecimal (Integer.toString (timerInterval))) < 0) {
timerInterval = timerInterval / shakeIncrement.intValue ();
shakeIncrement = new BigDecimal ("1");
return new TimerTuple (shakeIncrement, timerInterval);
} else {
shakeIncrement = shakeIncrement.divide (new BigDecimal (Integer.toString (timerInterval)), 8, RoundingMode.DOWN);
timerInterval = 1;
return new TimerTuple (shakeIncrement, timerInterval);
}
}
我认为我在这里所做的是正确的,但实际上,我不确定。
每次计时器滴答时,我都这样做:
TimerTuple tuple = getTimerTuple ();
if (tuple.timerInterval != timer.getInterval())
timer.setInterval (tuple.timerInterval);
currentShakes = currentShakes.add(tuple.shakeIncrement);
// Code to display the shake amount goes here...
我不知道你是否能理解我所做的所有这些混乱。
我不确定这是否有效,所以我将上述所有内容移到普通的Java应用程序中进行测试,因为它更容易实现。我将计时器更改为javax.swing.Timer
。然后我创建了一个JFrame
并在其中添加了JLabel
。我用这个标签来显示抖动计数。我将Hz设置为1000只是为了发生什么。我的预期结果是摇动计数每秒增加1000.但当然,它没有用。抖动计数非常慢,大致(我没有使用真正的计时器来测量!)每2秒钟震动1000次!
我不知道如何解决它。这是否超过刷新屏幕的最大限制?或者它是计时器的问题?或者我的计算错了?
编辑:
我使用调试器逐步完成代码,发现我的数学是正确的。我尝试将当前Hz设置为20000并运行getTimerTuple
,我得到了正确的结果。即定时器间隔为1ms,抖动增量为20。
对于那些不了解TimerTuple
做什么的人,它基本上说“每timerInterval
毫秒,震动计数应增加shakeIncrement
”。然后,我可以使用此信息将timer
的间隔设置为tuple.timerInterval
。
所以我仍然想知道如何让标签每秒显示正确的抖动计数。
编辑:
这次只是一些额外的信息。
我成功计算了震动增加的速度。当currentHz = 1000时,实际Hz为497.然后我尝试将currentHz设置为500并看到实际Hz为325.我得出结论,当前Hz与实际Hz的比率并不总是2:1!
然后我测试了一些其他值,并绘制了一个图表,显示预期的Hz(电流Hz)如何随实际Hz增加:
我绘制了另一张显示比例如何变化的图表
我认为这些表明比率和预期比率实际上是随机的。这让我更加困惑!
答案 0 :(得分:2)
所以我知道你已经确定你的数学是正确的。但是,我建议您尝试使用BigDecimal
个对象来简化代码(正如您将看到我已经完成了您的代码)。
关于显示它,我实现了一个简单的ActionListener
,附加到javax.swing.Timer
,并让它更新一个非常基本的Swing窗口。
package test;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.math.RoundingMode;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class TickerTest {
private static final BigDecimal ONE_THOUSAND = BigDecimal.TEN.pow(3);
private static final BigDecimal CURR_HZ = BigDecimal.TEN.pow(4).multiply(new BigDecimal(2));
private static final JLabel label = new JLabel("<not running>");
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TimerTuple timerTuple = getTimerTuple();
BigDecimal ratio = timerTuple.getTimerInterval().divide(timerTuple.getShakeIncrement(), 8, RoundingMode.DOWN);
label.setText(ratio.toString());
}
};
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
Timer timer = new Timer(1000, listener);
timer.start();
}
private static TimerTuple getTimerTuple () {
BigDecimal timerInterval = ONE_THOUSAND;
BigDecimal shakeIncrement = getCurrentHz();
if (shakeIncrement.equals(BigDecimal.ZERO)) {
return new TimerTuple(BigDecimal.ZERO, BigDecimal.ONE);
}
if (shakeIncrement.compareTo(timerInterval) < 0) {
timerInterval = timerInterval.divide(shakeIncrement);
return new TimerTuple(BigDecimal.ONE, timerInterval);
}
else {
shakeIncrement = shakeIncrement.divide(timerInterval, 8, RoundingMode.DOWN);
return new TimerTuple (shakeIncrement, BigDecimal.ONE);
}
}
private static BigDecimal getCurrentHz() {
return CURR_HZ;
}
}
package test;
import java.math.BigDecimal;
public class TimerTuple {
private BigDecimal shakeIncrement;
private BigDecimal timerInterval;
public TimerTuple(BigDecimal shakeIncrement, BigDecimal timerInterval) {
this.shakeIncrement = shakeIncrement;
this.timerInterval = timerInterval;
}
public BigDecimal getShakeIncrement() {
return shakeIncrement;
}
public BigDecimal getTimerInterval() {
return timerInterval;
}
}