中秋快乐!!!
前言:放假期间,小T打算回顾一下经典,想用Flutter做一下小游戏,做什么好呢,从打飞机到坦克大战,最后还是想做一款贪吃蛇,依稀还记得,小时候第一次玩游戏是在父母的小灵通上玩贪吃蛇哈哈,但是光光一个贪吃蛇太单调了,我们就加一个陀螺仪吧~
话不多说,先上效果图,有图有真相!!(陀螺仪好难操控)
开发步骤:
非常简单,就是玩起来有点费手~
源码在最后哦,直接运行即可
1.定义蛇和豆子
2.让蛇动起来
3.使用陀螺仪来控制蛇
4.让蛇吃掉豆子
5.吃掉豆子随机生成一个豆子
1.定义蛇和豆子
///蛇的每一块的大小
const double size = 10;
Offset ball = Offset.zero;//豆子
List<Offset> snakeList = [Offset(50, 0), Offset(60, 0)];//蛇的长度
显示豆子和蛇:
使用Stack是因为豆子在被蛇吃的时候会重叠
使用Positioned来进行定位
body: Stack(
children: snakeList
.map((snake) => Positioned.fromRect(
rect: Rect.fromCenter(
center: adjust(snake), width: size, height: size),
child: Container(margin:const EdgeInsets.all(1),color: Colors.black)))//加个外边距使每一块更清晰
.toList()
..add(Positioned.fromRect(
rect: Rect.fromCenter(
center: adjust(ball), width: size, height: size),
child: Container(color: Colors.orange))),
)
Offset adjust(Offset offset) {
return Offset(offset.dx + size / 2, offset.dy + size / 2); //使每一块更好的展示出来
}
2.让蛇动起来
在这里我们要先给蛇来一个状态定义:
///控制蛇的状态
enum Direction { Up, Down, Left, Right }
因为蛇要一直动,所以给一个周期函数:
1.定义200毫秒动一次
2.处理更新蛇的长度
3.求余的好处在于优化吃豆子,因为随机生成豆子时,可能是个不会被整除的。
Direction direction = Direction.Left; //给蛇设置一个状态,默认向左移动
///周期函数
void didChangeDependencies() {
///两百毫秒的周期函数
var period = Duration(milliseconds: 200);
///对蛇的长度进行优化
double maxWidth = MediaQuery.of(context).size.width;
double widthPad = maxWidth % size;
maxWidth -= widthPad;
double maxHeight = MediaQuery.of(context).size.height;
double heigthPad = maxHeight % size; //这里除于是为了更好的游戏体验
maxHeight -= heigthPad;
///周期调用
///用于贪吃蛇的自己移动,以及碰撞检测
Timer.periodic(period, (timer) {
final snakeHead = snakeList[0];
List<Offset> newSnakeList = List.generate(snakeList.length, (index) {
if (index > 0) {
return snakeList[index - 1];
} else {
///移动处理
switch (direction) {
case Direction.Up:
return Offset(snakeHead.dx,
(snakeHead.dy - size + maxHeight) % maxHeight); //求余是保证不会超标
case Direction.Down:
return Offset(
snakeHead.dx, (snakeHead.dy + size + maxHeight) % maxHeight);
case Direction.Left:
return Offset(
(snakeHead.dx - size + maxWidth) % maxWidth, snakeHead.dy);
case Direction.Right:
return Offset(
(snakeHead.dx + size + maxWidth) % maxWidth, snakeHead.dy);
}
}
});
setState(() {
snakeList = newSnakeList; //更新蛇的状态
});
});
super.didChangeDependencies();
}
3.使用陀螺仪来控制蛇
Flutter使用陀螺仪需要借助一个库:sensors 或者sensors_plus,两者没有太大的区别
这个demo使用:
sensors: any
官方给的例子:
import 'package:sensors/sensors.dart';
accelerometerEvents.listen((AccelerometerEvent event) {
print(event);
});
// [AccelerometerEvent (x: 0.0, y: 9.8, z: 0.0)] 加速度
userAccelerometerEvents.listen((UserAccelerometerEvent event) {
print(event);
});
// [UserAccelerometerEvent (x: 0.0, y: 0.0, z: 0.0)]
gyroscopeEvents.listen((GyroscopeEvent event) {
print(event);
});
// [GyroscopeEvent (x: 0.0, y: 0.0, z: 0.0)] 陀螺仪
我们在initState对陀螺仪进行监听:
这里有x,y,z的三个参数,也可以自己优化调试,5.0是当手机倾斜>=45°
@override
void initState() {
super.initState();
accelerometerEvents.listen((AccelerometerEvent event) {
setState(() {
_accelerometerValues = <double>[event.x, event.y, event.z];
if(_accelerometerValues[0] >= 5.0){
direction = Direction.Left;
}else if(_accelerometerValues[1] >= 5.0){
direction = Direction.Down;
}else if(_accelerometerValues[0] <= -5.0){
direction = Direction.Right;
}else if(_accelerometerValues[1] <= -5.0){
direction = Direction.Up;
}
});
});
}
4.让蛇吃掉豆子
还是在刚刚的周期函数里添加:
当蛇头碰到豆子时,给蛇加一格
if(newSnakeList[0] == ball){
newSnakeList..add(snakeList[snakeList.length - 1]);
setState(() {
ball = randoowPositon(maxWidth, maxHeight); //随机生成一个豆子,randoowPositon方法在后面
});
}
5.吃掉豆子随机生成一个豆子
对豆子的生成也需要优化一下
Offset randoowPositon (double widthRange,double heigthRange){
///随机生成豆子
var rng = Random();
double widthPad = widthRange % size;
widthRange -= widthPad;
double heigthPad = heigthRange % size; //这里除于是为了更好的游戏体验
heigthRange -= heigthPad;
return Offset(rng.nextInt(widthRange.toInt()).toDouble(),rng.nextInt(heigthRange.toInt()).toDouble());
}
ok到这里就完成了,需要源码的,给该文章点个赞,在我的主页有交流群,源码已经上传~
这游戏好玩是好玩,就是费手,哈哈,来个大神优化一下吧
添加我为你的好友,领取源码以及Flutter学习资料~
加入我们吧,一起学习,一起进步~
我是小T,我们下期再见~