不要将游戏的逻辑(对象移动等)更新速率建立在帧速率上。换句话说,将您的绘图和逻辑更新代码放在两个单独的组件/线程中。这样你的游戏逻辑就完全独立于你的帧率。
逻辑更新应该基于自上次更新以来已经过去了多少时间(我们称之为delta
)。因此,如果您有一个对象以 1px/毫秒的速度移动,那么在每次更新期间,您的对象应该执行以下操作:
public void update(int delta) {
this.x += this.speed * delta;
}
所以现在即使你的 FPS 滞后,它也不会影响你的对象的移动速度,因为增量会更大,使对象移动得更远以进行补偿(在某些情况下会出现并发症,但这就是要点)。
这是在逻辑更新对象中计算增量的一种方法(在某个线程循环中运行):
private long lastUpdateTime;
private long currentTime;
public void update() {
currentTime = System.currentTimeMillis();
int delta = (int) (currentTime - lastUpdateTime);
lastUpdateTime = currentTime;
myGameObject.update(delta); // This would call something like the update method above.
}
希望有帮助!请询问您是否有任何其他问题;我一直在自己制作安卓游戏。:)
示例代码:
复制这两个片段(1 个活动和 1 个视图)并运行代码。无论您的 FPS 是什么,结果都应该是一个白点从屏幕上顺利落下。代码看起来有点复杂和冗长,但实际上非常简单;评论应该解释一切。
这个活动课不是很重要。您可以忽略其中的大部分代码。
public class TestActivity extends Activity {
private TestView view;
public void onCreate(Bundle savedInstanceState) {
// These lines just add the view we're using.
super.onCreate(savedInstanceState);
setContentView(R.layout.randomimage);
RelativeLayout rl = (RelativeLayout) findViewById(R.id.relative_layout);
view = new TestView(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
10000, 10000);
rl.addView(view, params);
// This starts our view's logic thread
view.startMyLogicThread();
}
public void onPause() {
super.onPause();
// When our activity pauses, we want our view to stop updating its logic.
// This prevents your application from running in the background, which eats up the battery.
view.setActive(false);
}
}
这堂课是令人兴奋的地方!
public class TestView extends View {
// Of course, this stuff should be in its own object, but just for this example..
private float position; // Where our dot is
private float velocity; // How fast the dot's moving
private Paint p; // Used during onDraw()
private boolean active; // If our logic is still active
public TestView(Context context) {
super(context);
// Set some initial arbitrary values
position = 10f;
velocity = .05f;
p = new Paint();
p.setColor(Color.WHITE);
active = true;
}
// We draw everything here. This is by default in its own thread (the UI thread).
// Let's just call this thread THREAD_A.
public void onDraw(Canvas c) {
c.drawCircle(150, position, 1, p);
}
// This just updates our position based on a delta that's given.
public void update(int delta) {
position += delta * velocity;
postInvalidate(); // Tells our view to redraw itself, since our position changed.
}
// The important part!
// This starts another thread (let's call this THREAD_B). THREAD_B will run completely
// independent from THREAD_A (above); therefore, FPS changes will not affect how
// our velocity increases our position.
public void startMyLogicThread() {
new Thread() {
public void run() {
// Store the current time values.
long time1 = System.currentTimeMillis();
long time2;
// Once active is false, this loop (and thread) terminates.
while (active) {
try {
// This is your target delta. 25ms = 40fps
Thread.sleep(25);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
time2 = System.currentTimeMillis(); // Get current time
int delta = (int) (time2 - time1); // Calculate how long it's been since last update
update(delta); // Call update with our delta
time1 = time2; // Update our time variables.
}
}
}.start(); // Start THREAD_B
}
// Method that's called by the activity
public void setActive(boolean active) {
this.active = active;
}
}