Friday, April 13, 2018

c# - How do I animate pieces between puzzle states?


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?



Answer



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.



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.



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!


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...