2
\$\begingroup\$

I'm developing a simple C# puzzle game as a learning exercise, using OpenTK. It's similar to Puzzles and Dragons' puzzle part: The aim is to match 3 pieces to remove them. Removed pieces are replaced.

I have the puzzle part done such that matches are deleted and more pieces are added from the top. How can I animate tiles dropping from the top after rows/columns have been deleted? (You can see this happening about 4~5 seconds into the video on the website linked above.)

My idea was to create an "imaginary" board above the actual board so when tiles are deleted, I would in essence lower the imaginary board down, moving it further down on each frame. This brute force approach sounds like it could be done more easily with some APIs, but I've not had any luck with this.

Is there a better way to do these animations?

\$\endgroup\$
8
\$\begingroup\$

This is a good use-case for a Model-View-Controller (MVC) architecture as often used in software engineering. Keep your model (board contents) and view (how does it look) as separate parts of your program.

Motivating example

Say you have a board that looks like this:

sample initial board state

You then delete the red pieces and want to animate the replacement pieces falling from above, down into their places:

some frames of a possible animation

Now your board is like this:

final state

The MVC pattern suggests the model should only store board states (tiny board states :)) and not care how they are shown.

That's the view's job. Based on the model and the current point in time, it creates images for a user to see and handles everything else about animations. It does this without changing the model at all, although it might store additional data.

Implementation hints

In your model, you might store a type and unique id for each piece on a grid. Here's a 3x3 grid:

model = [
  [ { type : "blue",  id : 1 }, { type : "red",  id : 2 }, { type : "blue",  id : 3 }, ]
  [ { type : "red",   id : 4 }, { type : "red",  id : 5 }, { type : "blue",  id : 6 }, ]
  [ { type : "green", id : 7 }, { type : "blue", id : 8 }, { type : "green", id : 9 }, ]
]

The notation is pseudocode; {...} are objects containing key : value pairs and [...] are lists.

initial board state, with IDs

It's the same initial board state colours; we've just added numerical ids. To my understanding, you've got this bit working, though maybe without IDs.

The reason for the IDs becomes clear if we consider what happens when the model changes.

Here's a new board state:

model = [
  [ { type : "red",   id : 10 }, { type : "green", id : 11 }, { type : "blue",  id : 3 }, ]
  [ { type : "blue",  id : 1  }, { type : "green", id : 12 }, { type : "blue",  id : 6 }, ]
  [ { type : "green", id : 7  }, { type : "blue",  id : 8  }, { type : "green", id : 9 }, ]
]

This transition happened:

the same transition between board states, just with IDs

Now, a "dumb" view could ignore that anything happened at all and just continue happily drawing the new board state, without any animation.

However, a "clever" view which has been paying attention by storing a copy of the state, has enough information here to animate everything:

annotated state transition

  • The pieces with ids 3, 6, 7, 8 and 9 have stayed where they were. There's no need to animate them.
  • The piece 1 is there, but it's in a different position! We could animate it moving from its old position to the new one.
  • The pieces 2, 4 and 5 aren't there anymore. They could be animated by "shrinking out" or just disappearing.
  • The pieces 10, 11 and 12 are new. We can animate them falling in from off-screen above.

The "clever view" would then track which animations are happening and how far into each animation it is. Every tick, the view would advance all animations until they've all finished. (The details of this are all about interpolation. There are various interpolations you could use, but that's a different question's territory!)


I hope this is helpful. Ask about unclear parts!

\$\endgroup\$
  • \$\begingroup\$ ahh ok. I don't have IDs I just reference them through the row and column indices in a 2d array. But your answer makes sense! I'll try to implement some interpolation algorithm to do the animation. Thanks anko! \$\endgroup\$ – Nagia Feb 2 '14 at 5:46
  • 1
    \$\begingroup\$ Heh heh heh... I've been trying to figure out this type of setup, especially because I'm trying to create an immutable/functional code base (the view is essentially an output stream). The use of ids was the only piece I was missing. So +1. \$\endgroup\$ – Clockwork-Muse Feb 2 '14 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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