Do not base the refresh rate of game logic (moving an object, etc.) on the frame rate. In other words, enter the drawing and logical update code into two separate components / threads. Thus, your game logic is completely independent of your frame rate.
A logical update should be based on how much time has passed since the last update (call delta on it). Therefore, if you have an object moving at a speed of 1px / millisecond, then during each update your object should do something like this:
public void update(int delta) { this.x += this.speed * delta; }
So now, even if your FPS is lagging behind, it will not affect the speed of your object, since the delta will simply be larger, forcing the object to move further to compensate (in some cases there are complications, but thatβs the point).
And this is one way to calculate the delta in your logic update object (performed in a certain sequence of threads):
private long lastUpdateTime; private long currentTime; public void update() { currentTime = System.currentTimeMillis(); int delta = (int) (currentTime - lastUpdateTime); lastUpdateTime = currentTime; myGameObject.update(delta);
Hope this helps! Ask if you have any other questions; I myself made Android games. :)
Code example:
Copy these two snippets (1 activity and 1 view) and run the code. The result should be a white dot smoothly falling on your screen, regardless of your FPS. The code looks rather complicated and long, but actually it is quite simple; comments should explain everything.
This class of activity is not very important. You can ignore most of the code.
public class TestActivity extends Activity { private TestView view; public void onCreate(Bundle savedInstanceState) {
This class is interesting stuff!
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 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 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 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 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 been since last update update(delta); // Call update with our delta time1 = time2; // Update our time variables. } } }.start(); // Start THREAD_B } // Method that called by the activity public void setActive(boolean active) { this.active = active; } }