Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I want to make infinite 2D terrain based on my algorithm.Then I want to move it along Y axis (to the left) This is how I did it :

public class Terrain {  
Queue<Integer> _bottom; 

Paint _paint; 

Bitmap _texture;

Point _screen;

int _numberOfColumns = 100;
int _columnWidth = 20;

public Terrain(int screenWidth, int screenHeight, Bitmap texture)
{
    _bottom = new LinkedList<Integer>();

    _screen = new Point(screenWidth, screenHeight);

    _numberOfColumns = screenWidth / 6;
    _columnWidth = screenWidth / _numberOfColumns;      

    for(int i=0;i<=_numberOfColumns;i++)
    {
        // Generate terrain point and put it into _bottom queue
    }

    _paint = new Paint();
    _paint.setStyle(Paint.Style.FILL);
    _paint.setShader(new BitmapShader(texture, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
}

public void update()
{
    _bottom.remove();
    // Algorithm calculates next point 
    _bottom.add(nextPoint);
}

public void draw(Canvas canvas)
{
    Iterator<Integer> i = _bottom.iterator();
    int counter = 0;
    Path path = new Path();
    path.moveTo(0, _screen.y);
    while (i.hasNext())
    {
        path.lineTo(counter, _screen.y-i.next());
        counter += _columnWidth;
    }
    path.lineTo(_screen.x, _screen.y);
    path.lineTo(0, _screen.y);
    canvas.drawPath(path2, _paint);
}

}

The problem is that the game is too 'fast', so I tried with pausing thread with

Thread.sleep(50);

in run() method of my game thread but then it looks too torn.

Well, is there any way to slow down drawing of my terrain ?

share|improve this question
    
Unrelated comment to your main question: Don't use a linked list; use an array. Yes, yes, the computer science academics will tell you that removing from a list is O(1) and removing from an array is O(n). In real-world code like this, where your N is very small, the cost of removing a node from an array is tiny compared to the general overhead of a linked list (memory allocations, memory address indirections during iteration, cache unfriendliness of non-contiguous memory, etc). Especially once you start using that terrain for more than just drawing and need random-access lookup. –  Sean Middleditch Oct 15 '12 at 1:31
    
Well, I will check terrain tiles for collision with player and I will need random access to elements.Maybe it's better to use array. Thank You! –  Nikola Ninkovic Oct 15 '12 at 19:18
add comment

2 Answers

up vote 3 down vote accepted

The problem is that your drawing is tightly tied to your updates, and vice versa. If the game is drawing at 1000 frames per second, then update() is called 1000 times per second, and your terrain is going to scroll by at 1000 tiles per second.

The solution to that problem is to use a timestep to increment your simulation. In this case, say you want your terrain to scroll by at 60 tiles per second. That means you must call update() once every 1/60th of a second, and no more.

You can achieve this by using a timer and a time accumulator. Every time through your main loop, check how long has elapsed since the last time the loop ran. Add that value (generally represented as a floating point number in units of one second) to the accumulator. If the accumulator is greater than or equal to 1/60, subtract 1/60 from the accumulator and call update().

I'm not familiar with the Android timer APIs, but the general pseudocode looks something like:

// initialize time
last_time = GetCurrentTime();
accumulator = 0;
update_speed = 1/60;

while (!quit) {
  // calculate elapsed time since last frame
  current_time = GetCurrentTime();
  elapsed = ConvertToSeconds(current_time - last_time);

  // store current time for the next frame
  last_time = current_time;

  // if the accumulator is full enough, update game and "drain" accumulator
  accumulator += elapsed;
  if (accumulator >= update_speed) {
    update();
    accumulator -= elapsed;
  }

  draw();
}

Of course, this is a very rough and basic way to go about this. Going forward, you'll want to separate the speed the terrain scrolls by from your update time. You might have a character you need to update at 60 frames per second to feel "smooth" while the terrain is moving by at 20 tiles/second still. You can do this by using a "speed" multiplier for your world scrolling, giving it a separate timer/offset/accumulator from the one in your main game loop.

So far as the choppiness you encounter when you slow the game down, that is because you are moving the world one whole tile at a time. You should smoothly scroll the world, which is going to happen at the pixel level (or possible sub-pixel level, depending on what look/feel you're going for).

You'll want to store an offset in your tile data structure. As the update() function runs, simply increase this offset by your desired speed. (e.g. you want the terrain to move at 20 tiles/second, but you want to keep update() running as 60 calls/second for physics and such, so you increment the offset by 20 * update_speed).

You will need to generate one "extra" tile, because as the world moves to the left, you'll see a part of the left-most tile and a part of the right-most tile just coming into the screen.

When the offset reaches or exceeds 1.0, that is when you remove the old tile on the left, generate yet another new tile on the right, and decrement the offset. Something like:

offset += scroll_speed * update_speed;
if (offset >= 1.0) {
  offset -= 1.0;
  RemoveLeftTile();
  AddRightTile();
}

Going down the road, there's a lot more to do and learn with how to get nice smooth animations, accurate timing and timesteps, and so on, but this should be a good start given your current game development skill level. When you're ready to deal with more advanced problems in the world of game timers and updates, there are already many great articles here on GDSE to help you out. :)

share|improve this answer
add comment

You need to split the update and draw loop into 2 separate threads with timers, this way you can draw your terrain as fast as possible (like 60fps) and slow down the update loop to match your requirements.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.