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:
You then delete the red pieces and want to animate the replacement pieces falling from above, down into their places:
Now your board is like this:
The MVC pattern suggests the model should only store 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.
It's the same initial board state colours; we've just added numerical id
s. 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:
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:
- The pieces with
id
s3
,6
,7
,8
and9
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
and5
aren't there anymore. They could be animated by "shrinking out" or just disappearing. - The pieces
10
,11
and12
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