使用Flutter撸一个极简的吃月饼小游戏
先看效果
游戏规则很简单,在月饼投掷出去之后能够砸中月亮即记1分,否则该轮游戏结束,连续击中的次数则为本轮分数。
编码实现
代码上其实没有太多复杂度,大体逻辑如下:
1 月亮的移动动画,使用Tween实现一个补间动画,使用TweenSequence指定动画序列,监听动画的完成重复动画,从而实现月亮左右不间断移动的效果。
_animationController =
AnimationController(duration: Duration(milliseconds: 600), vsync: this);
_animationControllerCake =
AnimationController(duration: Duration(milliseconds: 900), vsync: this);
TweenSequenceItem<double> downMarginItem = TweenSequenceItem<double>(
tween: Tween(begin: 1.0, end: 50.0),
weight: 50,
);
TweenSequenceItem<double> upMarginItem = TweenSequenceItem<double>(
tween: Tween(begin: 50.0, end: 300.0),
weight: 100,
);
TweenSequence<double> tweenSequence = TweenSequence<double>([
downMarginItem,
upMarginItem,
]);
_animation = tweenSequence.animate(_animationController);
_animation.addListener(() {
if (_animation.isCompleted) {
_animationController.reverse();
}
if (_animation.isDismissed) {
_animationController.forward();
}
setState(() {});
});
2 月饼的投掷位移效果,使用StreamBuilder控件,配合Timer倒计时,在1秒内不断地Stream发送当前位置数据,从而不断的改变月饼距离底部的距离,看上去就像也是一个位移动画效果,而实际上是不断改变距离形成的视觉效果。
_countdownTimer = new Timer.periodic(new Duration(milliseconds: 1), (timer) {
if (_milliSecond > 0) {
_milliSecond = _milliSecond - 5;
} else {
_countdownTimer.cancel();
}
_cakeStreamController.sink.add(_milliSecond < 0 ? 0 : _milliSecond);
});
Container(
margin: EdgeInsets.only(bottom: distance),
child: Image.asset(
"assets/images/cake.png",
width: 60,
height: 60,
),
)
3 比较关键的一点就是,如何判断月饼投掷出去之后会和月亮发生碰撞,也就是“吃到月饼”。实现方案是:月亮的高度是已知的(屏幕高度 - 状态栏高度 - 月亮距上方距离),月饼的横坐标是固定的(屏幕宽度的一半)。在StreamBuilder中监听:当月饼高度达到月亮的高度时,判断月亮的横坐标是否和月饼一致即可,如果一致则月饼与月亮重合,记为一次有效分数。而这里为了增加游戏的可玩性,并不是很严格的判断坐标完全重合,如图所示,月饼到达月亮高度时,月亮如果在红色区域内都记为有效分数。
判断逻辑:
// 当月饼高度达到月球所处的高度时,判断月球的位置是否处于中间
if (distance < (_screenHeight - 120) &&
distance > (_screenHeight - 170 - MediaQuery.of(context).padding.top)) {
print(_animation.value);
if (_animation.value < (_screenWidth / 2 + 10) && _animation.value > (_screenWidth / 2 - 90)) {
_hintStreamController.add("太棒了");
print("撞到了");
_score++;
} else {
_hintStreamController.add("MISS");
print("MISS");
}
_milliSecond = 1000;
_cakeStreamController.sink.add(_milliSecond);
_countdownTimer.cancel();
}
引入分数排行榜
为了增加游戏的趣味性,在游戏里面增加了联机的分数排行榜机制,游戏中会将玩家的最高分数上传至服务器,在主界面的右上角可以查看自己在排行榜的位置。
这里云端服务器存储功能使用的是第三方平台LeanCloud,这个平台是支持Flutter的,而且在8月份刚好增加了对空安全的迭代。
扫码下载链接
目前支持安卓版本的下载,还在等什么,赶快下载登上排行榜吧~
代码地址
由于云端服务器使用了LeanCloud,下载的老铁需要去LeanCloud平台申请AppKey填写在项目中的main.dart中的初始化位置即可。
LeanCloud.initialize(
"", "",
server: "https://zsyju4p5.lc-cn-n1-shared.com", // to use your own custom domain
queryCache: new LCQueryCache() // optinoal, enable cache
)
作者:单总不会亏待你
链接:https://juejin.cn/post/7005585014767222798
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。