preface
I’ve previously created a “Man for 100 seconds” game with Flare, the game engine inside Flutter, here
With the Flare engine, the unique code style of the Flutter application is completely absent. Although more suitable for developers like me with previous game development experience, it is not conducive for us to learn the Flutter framework. That’s why I said at the end of the article that I should rewrite the game with widgets sometime.
The first thing to do is to have a Widget that supports “Sprite maps”. If you’re learning, you can’t develop the Widget by someone else. You have to build the wheel yourself.
What is a Sprite map?
It’s called a spritesheet, which is a way to put multiple shapes on a single chart that only needs to be loaded into memory once. During presentation, only areas of a single figure are shown. Generally, multiple graphics are used to place multiple key frames of continuous animation. In addition to being common in game engines, it is also common in the front-end domain to reduce Web requests.
Principle of dismantling
Load a large image, but only show a specific area of the image at a time
For example, in this Sprite image of an airplane, the size is 330×82 (pixels), and the size of each image is 330/5 = 66. The area we show each time is x=66* screen number, y=0, width=66, height=82.
Horizontal or vertical arrangement can be set
Sprites can be laid out horizontally or vertically, and some game engines have tiles with a maximum size of 4096×4096, so there are some situations where we need to switch lines, but the principle is not that different and I won’t discuss it here.
You can set the playing time interval, automatically switch multiple continuous areas
Most of the time we need sprites to show animations, like this airplane Sprite. The first and second pictures are used to show the animation of the flight state of the aircraft, which needs to be played in a loop.
The third, fourth and fifth frames are used to show the animation of the airplane explosion, which only needs to be played once.
Think about which widgets to build with
Take a look at what widgets we need with an animated demo
- Widgets (Containers) that control the display area
- You need a Widget (Stack+Positioned) that can give you coordinates.
Now that I know how it works and what widgets to use, the rest of the code is easy, right
Turn ideas into code
@override
Widget build(BuildContext context) {
return Container(
width: 66,
height: 82,
child: Stack(
children: [
Positioned(
left: 66*currentIndex,
top: 0,
child: widget.image
)
],
),
);
}
Copy the code
Add a timer and change the currentIndex at a set interval so the image looks like it’s moving.
Timer.periodic(widget.duration, (timer) {
setState(() {
if(currentIndex>=4){
currentIndex=0;
}
elsecurrentIndex++; }); }});Copy the code
Let’s take this one step further and wrap it into our own Widget. Here’s the code for this Widget
import 'dart:async';
import 'package:flutter/widgets.dart';
class AnimatedSpriteImage extends StatefulWidget {
final Image image;
final Size spriteSize;
final int startIndex;
final int endIndex;
final int playTimes;
final Duration duration;
final Axis axis;
AnimatedSpriteImage({
Key? key,
required this.image,
required this.spriteSize,
required this.duration,
this.axis = Axis.horizontal,
this.startIndex = 0.this.endIndex = 0.this.playTimes = 0.//0 = loop
}) : super(key: key);
@override
_AnimatedSpriteImageState createState() => _AnimatedSpriteImageState();
}
class _AnimatedSpriteImageState extends State<AnimatedSpriteImage> {
int currentIndex = 0;
int currentTimes = 0;
@override
void initState() {
currentIndex = widget.startIndex;
Timer.periodic(widget.duration, (timer) {
if(currentTimes<=widget.playTimes){
setState(() {
if(currentIndex>=widget.endIndex){
if(widget.playTimes! =0)currentTimes++;
if(currentTimes<widget.playTimes||widget.playTimes==0)currentIndex=widget.startIndex;
else currentIndex = widget.endIndex;
}
elsecurrentIndex++; }); }});super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
width: widget.spriteSize.width,
height: widget.spriteSize.height,
child: Stack(
children: [
Positioned(
left: widget.axis==Axis.horizontal?-widget.spriteSize.width*currentIndex:0, top: widget.axis==Axis.vertical? -widget.spriteSize.height*currentIndex:0, child: widget.image ) ], ), ); }}Copy the code
Well packaged and especially easy to use.
// Play the animation of aircraft flight status
AnimatedSpriteImage(
duration: Duration(milliseconds: 200),// The interval of the animation
image: Image.asset("assets/images/player.png"),/ / the elves figure
spriteSize: Size(66.82),// Single screen size
startIndex: 0.// Start screen number of animation
endIndex: 1.// Animation end screen number
playTimes: 0.// Number of playback times, 0 is a loop
)
// Play plane explosion animation
AnimatedSpriteImage(
duration: Duration(milliseconds: 200),// The interval of the animation
image: Image.asset("assets/images/player.png"),/ / the elves figure
spriteSize: Size(66.82),// Single screen size
startIndex: 2.// Start screen number of animation
endIndex: 4.// Animation end screen number
playTimes: 1.// Number of playback times, 0 is a loop
)
Copy the code
Pay attention to a guard
An old programmer who loves front-end development and only shares content on three platforms
- The Denver nuggets
- B station: Handsome old ape
- Wechat official account: Da Shuai Lao Ape