Flutter开发游戏初体验,喜大普奔

今天来给大家带来一个更劲爆的知识点——Flutter开发游戏。是的,没错,Flutter也可以用来开发游戏了。有人会问不懂Unity或者Cocos2d也能用Flutter开发游戏吗???是的,你没看错,Flutter就是这么666。

我在pub.dev上面找到了一些有关游戏的第三方开源库,使用它们你就可以轻而易举的实现你的游戏梦(你要说开发王者荣耀、吃鸡那种大型游戏的话就当我前面的话没说)。下面开始今天的干货分享。

添加依赖包

首先在pubspec.yaml 里面添加依赖包,如下所示:

dependencies:
  flutter:
    sdk: flutter

  flame: ^0.17.2
  box2d_flame: ^0.4.4
  sensors: ^0.4.1+1

在main.dart中添加相关设置要素

接下来看看 main.dart 里面的代码,如下所示:

 1   import 'dart:async';
 2   import 'package:flame/util.dart';
 3   import 'package:flutter/material.dart';
 4   import 'package:flutter/services.dart';
 5   import 'game.dart';
 6
 7   void main() async {
 8     // 启动游戏前要先设置flame的相关属性
 9     await setupFlame();
10     var game = new FlutterGame();
11     runApp(game.widget);
12   }
13
14   /// 构建Flame所需要的属性设置
15   Future setupFlame() async {
16     // 创建 Util对象
17     var flameUtil = Util();
18    // 设置全屏
19  await flameUtil.fullScreen();
20  // 固定为纵向位置,不允许旋转
21  await flameUtil.setOrientation(DeviceOrientation.portraitUp);
22}

首先解释一下每个包的作用:

// MD组件
import 'package:flutter/material.dart';

// 我们需要Flame构建游戏
import 'package:flame/util.dart';

// setupFlame() 方法中需要用到
import 'package:flutter/services.dart';

// 异步支持
import 'dart:async';

// 具体的游戏界面
import 'FlutterGame.dart';

main()函数用了一个async表示异步,因为这涉及到里面的“setupFlame()”函数。setupFlame()函数是一个异步的,它里面主要是构建Flame所需要的属性设置,我们在启动游戏前要先设置flame的相关属性。

setupFlame() 函数里面做了3件事:

● 创建 Util对象

● 设置全屏

● 固定为纵向位置,不允许旋转

游戏部分的代码

接下来看看 game.dart 里面的代码,如下所示:

 1   import 'dart:ui';
 2
 3   import 'package:box2d_flame/box2d.dart';
 4   import 'package:flame/flame.dart';
 5   import 'package:flame/game.dart';
 6
 7   class FlutterGame extends Game {
 8     static const int WORLD_POOL_SIZE = 100;
 9     static const int WORLD_POOL_CONTAINER_SIZE = 10;
10
11     World world;
12
13     final Vector2 _gravity = Vector2.zero();
14
15     FlutterGame() {
16       world = new World.withPool(
17         _gravity,
18         DefaultWorldPool(WORLD_POOL_SIZE, WORLD_POOL_CONTAINER_SIZE),
19       );
20       initialize();
21     }
22
23     Future initialize() async {
24        resize(await Flame.util.initialDimensions());
25     }
26
27     void resize(Size size) {
28       super.resize(size);
29     }
30
31      @override
32     void render(Canvas canvas) {
33    }
34
35     @override
36     void update(double t) {
37     }
38   }

解释一下上面的代码的意思:

FlutterGame类是具体游戏功能的实现,继承了Flame提供的Game类,所以可以放心大胆的写我们自己的功能,比如游戏循环或者调整大小事件等。Box2D将负责我们所有与物理相关的操作,这包括处理碰撞,加速/减速物体/质量以及模拟我们游戏中的不同形状/材料。

World是主要物理对象。

gravity 设置向量为0 表示无重力(gravity),Vector2你可以把它看做是平面二维坐标系统内的一个点,每个Vector2都有一个X和一个Y值。我们的gravity向量坐标值为(0,0)手机坐标系统左上角为(0,0),上部水平向右x轴正方向,左侧垂直向下位y轴正方向重力设置位(0,1)表示元素从屏幕顶部掉落到底部。

Box2D 需要用到 这两个常量值,这里面定义了两个,分别是:WORLD_POOL_SIZE和WORLD_POOL_CONTAINER_SIZE。

然后使用World.withPool创建World对象。

接下来调用initialize()方法,初始化我们所有需要的东西,包括:需要调整大小和不需要调整大小的东西。然后它的返回值调用Flame的初始化的方法,一旦Flutter准备就绪,立即调用resize()方法检查显示尺寸。

接下来看看几个函数的说明:

● render:在画布上绘制元素。

● update: 目标是60fps的速度进行,这意味着在一秒内将调用该函数60次。由于并不一直是60fps的速度,time参数会告诉你自上次调用以来经过了多少时间。

开启引擎,绘制元素

如果你按照以上步骤都都设置好了,这时候运行程序到你的设备,你会发现是一片黑色或空白的,因为我们还没有绘制任何元素在我们的界面上面。

接下来可以试着画一点东西上去。

新增代码如下所示:

Paint paint;
Size screenSize;
Rect _screenRect;
final int scale = 5;

void resize(Size size) {
  paint = Paint();
  paint.color = Color(0xffffffff);
  screenSize = size;
  _screenRect = Rect.fromLTWH(0, 0, screenSize.width, screenSize.height);
  super.resize(size);
 }

void render(Canvas canvas) {
  if (screenSize == null) {
    return;
  }
  canvas.save();
  canvas.scale(screenSize.width / scale);
  canvas.translate(_screenRect.width/2, _screenRect.height/2);
  canvas.drawCircle(Offset(0, 0), .1, paint);
  canvas.restore();
  }
}

这里发生的事情如下:

首先声明一个Paint对象,它是画笔,需要它来画一些东西。

screenSize和screenRect分别用于保存屏幕大小和相关的矩形以供以后使用。在resize()方法中,通过调用Flame的相关API,获得了size和Rect,然后再分别赋值给全局变量screenSize和screenRect。

定义一个比例因子(scale)这个变量来增加我们的应用程序中的元素。后面我们在物理交互中需要用到它。

render()函数内部主要是绘制的过程:

设置screenSize属性,确保我们准备好绘制了。然后保存画布。

调用scale()方法,设置缩放。使用屏幕的宽度除以比例因子,screenSize.width / scale,然后作为参数传入scale()方法。

使用translate()方法将画布的(0,0)点移动到屏幕中心位置。

使用drawCircle()方法,我们使用画图对象在(0,0)处绘制半径为0.1的圆

调用restore()方法将完成我们的渲染循环,仅显示一帧。

立即启动应用程序,应在屏幕中心附近绘制一个小圆圈,如下图所示:

最后我们把绘制部分的代码修改一下,加上重力传感器的代码,最终效果是这样的(具体的请进入Github查看源码),如下图所示:

源码及总结

本文的源码来自于GitHub:

https://github.com/Dev-Owl/Mazeball

来一点我的一些个人总结和说明: 当然前面这些看似比较基础,但是只要你用心学习,多看看相关API介绍,也可以用它做其它的复杂的的游戏或其他功能,比如:连连看、俄罗斯方块、是男人就下100层、超级玛丽、愤怒的小鸟、接方块、摩拜单车APP的贴纸功能等。当然具体的业务逻辑需要你自己的思考,所有的具体业务功能点都是在核心API的基础之上不断完善的,这里只是给出一些可以研究的相关的方向,感兴趣的朋友们可以试着做一下,这里就不逐个列举了。

最后给大家送一点福利,感谢大家一直以来的支持和鼓励。具体内容大家可以看看这里 ↓

在这里我分享一份私货,自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习

如果你有需要的话,可以点赞+评论关注我,然后点这里领取 Android学习PDF+架构视频+面试文档+源码笔记

发布了182 篇原创文章 · 获赞 70 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_45258969/article/details/103532869