文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

利用Flutter制作经典贪吃蛇游戏

2024-04-02 19:55

关注

前言

Flutter (Channel stable, 2.10.3, on Microsoft Windows [Version 10.0.19044.1586], locale zh-CN)

Android toolchain - develop for Android devices (Android SDK version 30.0.3)

Flutter 框架让你可以使用单一代码库为 Android、iOS、Web ,桌面平台构建应用程序。尽管许多大公司都将 Flutter 用于他们蓬勃发展的应用程序,包括 Google Pay 和阿里巴巴闲鱼,但没有多少人正在探索使用 Flutter 进行游戏开发。这就是你将在本教程中所做的。

由于 Flutter 能够以高达 60 FPS 的速度渲染 UI,你将利用该功能在 Flutter 中构建简单的 2D Snake 游戏。

在此过程中,你将学习如何:

启动项目设置了竞争环境。你将在构建游戏时为其添加 UI 元素。入门项目还提供了一些有用的实用方法,因此你可以专注于更大的场景:编写游戏。以下是你可以在项目中找到的预构建函数,以及如何使用它们:

使用 Flutter 作为游戏引擎

游戏引擎是一套工具和服务,可帮助游戏开发者构建游戏。他们处理很多不同的事情,比如图形、声音、人工智能、用户输入、网络等等。Flutter 也可以处理大部分这些事情。作为 Flutter 开发人员,你可以访问整个世界的 Dart 插件。另外,如果不存在,你始终可以自己编写代码。

要从 Flutter 作为游戏开发引擎开始,你将使用框架的渲染功能来为蛇、食物和游戏分数等游戏对象设置动画。在这种情况下,你将使用计时器每秒重新生成 60 次 UI,并在屏幕上显示一条蛇。通过在改变其位置的同时以高达 60 FPS 的速度渲染蛇,你可以获得非常平滑的移动动画效果。

像 Unity 这样的游戏引擎以类似的方式工作。这里的不同之处在于,过多地推动框架的限制可能最终导致需要大量资源的应用程序。然而,在测试这款游戏时,Flutter 的表现惊人地好,根本没有加热设备。

画蛇

你的第一步是创建蛇。你将从启动Piece项目中的小部件开始,它会在屏幕上呈现一个彩色圆圈。使用此小部件,你将逐个绘制蛇以及蛇食。

但是,在绘制蛇之前,有必要花点时间了解使用 Flutter 进行 2D 渲染的基础知识。

2D 渲染的基础

要渲染任何在屏幕上不断改变其位置的东西,你需要使用 和 之类的小Stack部件Positioned。给定 x 和 y 坐标,这些小部件可以将子小部件放置在屏幕上的任何位置。

要记住的最重要的事情是,你正在开发一个移动应用程序,该应用程序需要在具有各种屏幕尺寸和纵横比的设备上运行。这意味着你不能对游戏领域的任何维度进行硬编码。相反,你将使用MediaQuery获取用户屏幕的宽度和高度,然后根据这些值计算位置。

例如,这是一个简单的代码片段,它声明变量,然后将屏幕的宽度和高度分配给它们。

final screenSize = MediaQuery.of(context).size;
final screenWidth = screenSize.width;
final screenHeight = screenSize.height;

在上面的代码片段中,MediaQuery继承的小部件用于获取当前设备屏幕的宽度和高度。这需要传递内容,因此,我们在其内部拥有此代码build()

既然你知道如何在屏幕上放置对象,就该画蛇了。

创建蛇

你将使用它Piece来创建蛇。首先,你将根据蛇在屏幕上的位置进行创建。然后,你会将组成蛇的所有部分的位置存储在被调用的。

首先将getPieces()位于lib/game.dart中的 替换为:

 List<Piece> getPieces() {
    final pieces = <Piece>[];
    draw();
    drawFood();
​
    // 1
    for (var i = 0; i < length; ++i) {
      // 2
      if (i >= positions.length) {
        continue;
      }
​
      // 3
      pieces.add(
        Piece(
          posX: positions[i].dx.toInt(),
          posY: positions[i].dy.toInt(),
          // 4
          size: step,
          color: Colors.red,
        ),
      );
    }
​
    return pieces;
}

这是上面代码中发生的事情:

保存文件并让应用程序热重新加载。到目前为止,什么都没有发生,你也不会注意到 UI 中的任何变化。

填写列表

你需要实施draw()以实际填写positions列表。因此draw(),在同一文件中替换为以下内容:

  void draw() async {
    // 1
    if (positions.length == 0) {
      positions.add(getRandomPositionWithinRange());
    }
​
    // 2
    while (length > positions.length) {
      positions.add(positions[positions.length - 1]);
    }
​
    // 3
    for (var i = positions.length - 1; i > 0; i--) {
      positions[i] = positions[i - 1];
    }
​
    // 4
    positions[0] = await getNextPosition(positions[0]);
  }

以下是上述函数的工作原理:

你在这里需要做的最后一件事是实现 at getNextPosition()

将蛇移动到下一个位置

将以下代码添加到lib/game.dart中的函数中:

  Future<Offset> getNextPosition(Offset position) async {
    Offset nextPosition;
​
    if (direction == Direction.right) {
      nextPosition = Offset(position.dx + step, position.dy);
    } else if (direction == Direction.left) {
      nextPosition = Offset(position.dx - step, position.dy);
    } else if (direction == Direction.up) {
      nextPosition = Offset(position.dx, position.dy - step);
    } else if (direction == Direction.down) {
      nextPosition = Offset(position.dx, position.dy + step);
    }
​
    return nextPosition;
  }

以下是上面代码的作用:

最后,

  return Scaffold(
    body: Container(
      color: Color(0XFFF5BB00),
      child: Stack(
        children: [
          Stack(
            children: getPieces(),
          ),
        ],
      ),
    ),
  );

在上面的代码片段中,我们只是添加了getPieces()将小部件返回到堆栈的方法,因此我们可以在屏幕上看到一些 UI。请注意,如果你不将小部件添加到build(),屏幕上不会发生任何变化。

保存所有内容并重新启动应用程序。你会看到的:

你可以看到一条蛇……它什么也没做。那是因为你没有添加任何东西来重建 UI。但是,一次又一次地保存文件并让热重载完成它的工作,你会看到蛇移动。

添加运动和速度

现在,让蛇移动所需的只是一种重建 UI 的方法。每次build调用,都需要计算新的位置,并在Piece屏幕上渲染新的 s 列表。为此,你将使用Timer.

changeSpeed()在lib/game.dart中添加以下定义:

  void changeSpeed() {
    if (timer != null && timer.isActive) timer.cancel();
​
    timer = Timer.periodic(Duration(milliseconds: 200 ~/ speed), (timer) {
      setState(() {});
    });
  }

上面的代码只是简单地重置了timer一个包含speed. speed每次蛇吃食物时,你控制并增加它。最后,在计时器的每一个滴答声中,你都会调用setState(),它会重建整个 UI。

changeSpeed()接下来,从restart()同一文件中调用:

  void restart() {
    changeSpeed();
  }

timer每次用户重新启动游戏时都会重新初始化。

保存所有文件并重新启动应用程序。现在,每次重新启动应用程序时,蛇都会向随机方向移动。

添加控件

现在你有了一条移动的蛇,你需要添加更多的旋钮和转盘,以便用户可以控制蛇的方向和速度。请记住以下几点:

改变方向

ControlPanel拥有让用户控制蛇的方向所需的一切。它由四个圆形按钮组成,每个按钮都会改变蛇的运动方向。该小部件位于lib/control_panel.dart中。随意挖掘并查看实现。

现在,将以下代码添加到getControls()lib /game.dart 中:

  Widget getControls() {
    return ControlPanel( // 1
      onTapped: (Direction newDirection) { // 2
        direction = newDirection; // 3
      },
    );
  }

在上面的代码片段中:

此外,在文档顶部添加以下导入:

  import 'control_panel.dart';

接下来,添加getControls()为外部Stackin的第二个孩子build()

@override
Widget build(BuildContext context) {
  // ...
  return Scaffold(
    body: Container(
      color: Color(0XFFF5BB00),
      child: Stack(
        children: [
          Stack(
            children: getPieces(),
          ),
          getControls(),
        ],
      ),
    ),
  );
}

上面的代码将 getControls 方法返回的小部件添加到 Stack 内屏幕上的 UI,但位于 UI 的其余部分之上。

保存文件并重新启动应用程序。现在,你将看到一组控制蛇方向的按钮。

点击按钮会改变蛇的方向。到目前为止,游戏在一个简单的级别上运行,但你仍然需要添加玩家应该努力的东西。只是在屏幕上移动一条五颜六色的蛇并不是很有趣,对吧?所以你的下一步是给蛇一些食物来加速它。

吃东西和提高速度

要在屏幕上渲染食物,你将Piece再次使用,但你将更改其颜色。请记住,你不希望食物出现在任意位置。相反,它应该始终在游戏区域内的随机位置渲染,并且它应该始终位于蛇移动的网格上。

现在,你将实现在屏幕上drawFood()呈现食物。Piece将以下代码添加到drawFood()同一文件中:

  void drawFood() {
​
    // 1
    if (foodPosition == null) {
      foodPosition = getRandomPositionWithinRange();
    }
​
    // 2
    food = Piece(
      posX: foodPosition.dx.toInt(),
      posY: foodPosition.dy.toInt(),
      size: step,
      color: Color(0XFF8EA604),
      isAnimated: true,
    );
  }

这是上面发生的事情。

在屏幕上显示食物

接下来,你需要添加foodbuildinsideStack以将其呈现在屏幕上。

@override
Widget build(BuildContext context) {
  //...
  return Scaffold(
    body: Container(
      color: Color(0XFFF5BB00),
      child: Stack(
        children: [
          Stack(
            children: getPieces(),
          ),
          getControls(),
          food,
        ],
      ),
    ),
  );
}

保存所有文件并重新启动应用程序以查看实际更改。应用程序重新启动后,你会在屏幕上看到绿色食物。

然而,如果你试图让蛇找到食物,什么都不会发生——它只会越过食物图标。那是因为你没有做任何事情让蛇吃掉食物。接下来你会解决这个问题。

消耗和再生食物

现在,你需要检查蛇和食物在 2D 空间中是否处于相同坐标。如果是,你将对蛇进行一些更改并在新位置呈现一些新食物。

drawFood()在第一个if块结束后将以下代码添加到:

  void drawFood() {
​
    // ...
​
    if (foodPosition == positions[0]) {
      length++;
      speed = speed + 0.25;
      score = score + 5;
      changeSpeed();
​
      foodPosition = getRandomPositionWithinRange();
    }
​
    // ...
  }

上面的代码只是检查你存储foodPosition的位置和蛇的第一Piece个小部件的位置是否相同。如果它们匹配,你将length增加1speed和。然后调用,它使用新设置重新初始化。0.25``score``5``changeSpeed()``timer

最后,你foodPosition在屏幕上使用新的随机位置进行更新,从而呈现新的食物Piece

保存文件并重新启动应用程序以使更改生效。

蛇现在可以吃食物了。当它这样做时,它的长度会大大增加。

检测碰撞并显示游戏结束对话框

到目前为止,这条蛇可以自由地四处走动——这就造成了一个问题。没有什么可以阻止蛇走出矩形游乐区。你需要限制蛇的移动以保持在你在屏幕上定义的游戏区域内。

首先,使用 渲染该游戏区域getPlayAreaBorder(),这会为游戏区域添加轮廓。只需添加getPlayAreaBorder()到外部Stackin build()

@override
Widget build(BuildContext context) {
  //...
  return Scaffold(
      body: Container(
        color: Color(0XFFF5BB00),
        child: Stack(
          children: [
            getPlayAreaBorder(),
            Stack(
              children: getPieces(),
            ),
            getControls(),
            food,
          ],
        ),
      ),
    );
}

上面的代码将food小部件添加到Stackinbuild()所以现在它将呈现在屏幕上。

接下来,将以下代码添加到detectCollision()

  bool detectCollision(Offset position) {
​
    if (position.dx >= upperBoundX && direction == Direction.right) {
      return true;
    } else if (position.dx <= lowerBoundX && direction == Direction.left) {
      return true;
    } else if (position.dy >= upperBoundY && direction == Direction.down) {
      return true;
    } else if (position.dy <= lowerBoundY && direction == Direction.up) {
      return true;
    }
​
    return false;
  }

上面的函数检查蛇是否到达了四个边界中的任何一个。如果有,则返回true,否则返回false。它使用lowerBoundXupperBoundX和变量lowerBoundYupperBoundY检查蛇是否仍在游戏区域内。

接下来,你需要在每次生成蛇的下一个位置时使用detectCollision()inside来检查碰撞。getNextPosition()将以下代码添加到getNextPosition()的声明之后nextPosition

Future<Offset> getNextPosition(Offset position) async {
  //...
  if (detectCollision(position) == true) {
      if (timer != null && timer.isActive) timer.cancel();
      await Future.delayed(
          Duration(milliseconds: 500), () => showGameOverDialog());
      return position;
    }
  //...
}

上面的代码检查碰撞。如果蛇与边界框发生碰撞,代码会取消计时器并向用户显示Game Over对话框showGameOverDialog()

保存所有文件并热重载应用程序。

这一次,如果蛇接触到周围的边界框,你将立即看到一个对话框,通知用户游戏结束并显示他们的分数。点击对话框中的重新启动按钮以关闭对话框并重新开始游戏。接下来你会这样做。

添加一些收尾工作

比赛开始成形。你接下来的步骤是编写代码以重新启动游戏,然后添加分数以赋予游戏竞争元素。

重启游戏

接下来,你将在用户点击Restart按钮时重新启动游戏。将lib/game.dartrestart中的现有替换为:

  void restart() {
​
    score = 0;
    length = 5;
    positions = [];
    direction = getRandomDirection();
    speed = 1;
​
    changeSpeed();
  }

上面的代码只是将所有内容重置为其初始值。它也会清除positions,因此蛇会失去它length并从头开始重生。

显示分数

接下来,你需要添加代码以在屏幕右上角显示分数。为此,请实施getScore()

  Widget getScore() {
    return Positioned(
      top: 50.0,
      right: 40.0,
      child: Text(
        "Score: " + score.toString(),
        style: TextStyle(fontSize: 24.0),
      ),
    );
  }

添加getScore()build()作为外部的最后一个孩子Stack在. 最后,你应该如下所示:`

@override
Widget build(BuildContext context) {
  //...
  return Scaffold(
    body: Container(
      color: Color(0XFFF5BB00),
      child: Stack(
        children: [
          getPlayAreaBorder(),
          Stack(
            children: getPieces(),
          ),
          getControls(),
          food,
          getScore(),
        ],
      ),
    ),
  );
}

保存所有文件并重新启动应用程序。

现在,你应该会实时看到分数更新。

以上就是利用Flutter制作经典贪吃蛇游戏的详细内容,更多关于Flutter贪吃蛇的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯