如何使用Flutter构建2D游戏(分步指南)

如何使用Flutter构建2D游戏(分步指南)

文章图片
Flutter构建2D游戏实例
Flutter 的出现和成长利用了跨平台游戏设计的发展;Flutter 游戏只需几行代码即可创建设计和逻辑,同时保持出色的 UI/UX。
Flutter 能够以高达 60FPS 的速度渲染。你可以利用该功能构建简单的 2D 甚至 3D 游戏。请记住,在 Flutter 中开发更复杂的游戏并不是一个好主意,因为大多数开发人员会倾向于为复杂的应用程序进行原生开发。
如何使用Flutter构建2D游戏?在本教程中,我们将重新创建有史以来最早的电脑游戏之一:Pong,Pong是一个简单的游戏,所以它是一个很好的起点。本文分为两个主要部分:游戏逻辑和用户界面,通过分别关注重要部分,使构建更加清晰。
在我们进入构建之前,让我们回顾一下先决条件和设置。
Flutter 2D游戏构建教程预先准备要理解本课程并编写代码,你将需要以下内容:
  • Flutter安装在你的机器上
  • Dart 和 Flutter 的工作知识
  • 一个文本编辑器
Flutter构建2D游戏实例入门在这篇文章中,我们将用作屏幕 X 轴和 Y 轴位置的表示,这将有助于开发游戏的物理特性。我们还将为我们的一些变量创建无状态小部件,并在文件中声明它们,以使代码体积更小且易于理解。Alignment(x,y)Vector(x,y)homepage.dart
首先,创建一个 Flutter 项目。清除文件中的默认代码,并导入用于在应用程序中包含Material 小部件的包。main.dartmaterial.dart
接下来,创建一个名为并返回的类,然后创建一个并将其传递给如下所示的参数:MyApp()MaterialApp()statefulWidget  HomePage()homeMaterialApp()
import 'package:flutter/material.dart'; import 'package:pong/homePage.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner:false, home: HomePage(), ); } }

游戏逻辑如何使用Flutter构建2D游戏?在HomePage()中,我们需要编写一些函数和方法来处理数学和物理相关的操作。这些包括处理碰撞、加速或减速以及游戏中的导航。
但首先,我们需要声明一些参数,这些参数将代表球、球员的位置对齐以及双方球员的初始得分。参数的代码应该放在 下_HomePageState,我们将在后面的帖子中引用:
//player variations double playerX = -0.2; double brickWidth = 0.4; int playerScore = 0; // enemy variable double enemyX = -0.2; int enemyScore = 0; //ball double ballx = 0; double bally = 0; var ballYDirection = direction.DOWN; var ballXDirection = direction.RIGHT; bool gameStarted = false; ...

然后,我们提供球和砖块运动方向的枚举:
enum direction { UP, DOWN, LEFT, RIGHT } ...

为了让这个游戏工作,我们需要创建人工重力,这样当球碰到顶部砖块 (0.9) 或底部砖块 (-0.9) 时,它会朝着相反的方向前进。否则,如果它没有击中任何一块砖块,而是进入了比赛场地的顶部 (1) 或底部 (-1),则将其记录为玩家的损失。
当球撞到左边 (1) 或右边 (-1) 的墙壁时,它会朝着相反的方向前进:
void startGame() { gameStarted = true; Timer.periodic(Duration(milliseconds: 1), (timer) { updatedDirection(); moveBall(); moveEnemy(); if (isPlayerDead()) { enemyScore++; timer.cancel(); _showDialog(false); // resetGame(); } if (isEnemyDead()) { playerScore++; timer.cancel(); _showDialog(true); // resetGame(); } }); } ...

在上面的代码,我们开始与函数从而改变了布尔来,之后我们称之为以一秒的持续时间。startGame()gameStartedtrueTimer()
在计时器内,函数如、和与检查任一玩家是否失败的语句一起传递。如果是,则累积分数,取消计时器,并显示一个对话框。updatedDirection()moveBall()moveEnemy()if
Flutter构建2D游戏实例:以下函数确保球不会超出0.9对齐,并且球在与砖块接触时只会向相反的方向移动:
void updatedDirection() { setState(() { //update vertical dirction if (bally >= 0.9 & & playerX + brickWidth>= ballx & & playerX < = ballx) { ballYDirection = direction.UP; } else if (bally < = -0.9) { ballYDirection = direction.DOWN; } // update horizontal directions if (ballx >= 1) { ballXDirection = direction.LEFT; } else if (ballx < = -1) { ballXDirection = direction.RIGHT; } }); } void moveBall() { //vertical movement setState(() { if (ballYDirection == direction.DOWN) { bally += 0.01; } else if (ballYDirection == direction.UP) { bally -= 0.01; } }); //horizontal movement setState(() { if (ballXDirection == direction.LEFT) { ballx -= 0.01; } else if (ballXDirection == direction.RIGHT) { ballx += 0.01; } }); } ...

此外,如果球击中场地的左侧或右侧,则它会朝着相反的方向前进:
void moveLeft() { setState(() { if (!(playerX - 0.1 < = -1)) { playerX -= 0.1; } }); } void moveRight() { if (!(playerX + brickWidth >= 1)) { playerX += 0.1; } } ...

该和功能有助于控制我们的砖块运动使用键盘上的箭头从左向右。这些与声明一起使用,以确保积木不会超出场地两个轴的宽度。moveLeft()moveRight()if
该函数将球员和球返回到他们的默认位置:resetGame()
void resetGame() { Navigator.pop(context); setState(() { gameStarted = false; ballx = 0; bally = 0; playerX = -0.2; enemyX =- 0.2; }); } ...

接下来,我们创建两个函数和,它们返回一个布尔值。他们检查是否有任何一个球员输了(如果球已经击中了砖块后面的垂直部分):isEnemyDead()isPlayerDead()
bool isEnemyDead(){ if (bally < = -1) { return true; } return false; } bool isPlayerDead() { if (bally >= 1) { return true; } return false; } ...

Flutter 2D游戏构建教程:最后,_showDialog当任一玩家获胜时,该函数会显示一个对话框。它传递一个布尔值 ,enemyDied来区分玩家何时输球。然后,它宣布非失败玩家赢得了这一轮,并使用获胜玩家的颜色显示文本“再玩一次:”
void _showDialog(bool enemyDied) { showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { // return object of type Dialog return AlertDialog( elevation: 0.0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0)), backgroundColor: Colors.purple, title: Center( child: Text( enemyDied?"Pink Wins": "Purple Wins", style: TextStyle(color: Colors.white), ), ), actions: [ GestureDetector( onTap: resetGame, child: ClipRRect( borderRadius: BorderRadius.circular(5), child: Container( padding: EdgeInsets.all(7), color: Colors.purple[ 100], child: Text( "Play Again", style: TextStyle(color:enemyDied?Colors.pink[ 300]: Colors.purple[ 000]), )), ), ) ], ); }); }

用户界面如何使用Flutter构建2D游戏?现在,我们将开始开发用户界面。
【如何使用Flutter构建2D游戏(分步指南)】在文件的小部件build内,添加以下代码:homePage.dart
return RawKeyboardListener( focusNode: FocusNode(), autofocus: false, onKey: (event) { if (event.isKeyPressed(LogicalKeyboardKey.arrowLeft)) { moveLeft(); } else if (event.isKeyPressed(LogicalKeyboardKey.arrowRight)) { moveRight(); } }, child: GestureDetector( onTap: startGame, child: Scaffold( backgroundColor: Colors.grey[ 900], body: Center( child: Stack( children: [ Welcome(gameStarted), //top brick Brick(enemyX, -0.9, brickWidth, true), //scoreboard Score(gameStarted,enemyScore,playerScore), // ball Ball(ballx, bally), // //bottom brick Brick(enemyX, 0.9, brickWidth, false) ], ))), ), );

在代码中,我们返回,它将在我们在网络上构建时提供从左到右的移动。这也可以为触摸屏设备复制。RawKeyboardListener()
小部件提供用于调用上面在逻辑中编写的函数的功能。还编写了一个子项来指定应用程序的背景颜色和正文。GestureDetector()onTapstartGameScaffold()
接下来,创建一个名为的类Welcome并传入一个布尔值来检查游戏是否已经开始。如果游戏还没有开始,“tap to play”的文字会变成可见的:
class Welcome extends StatelessWidget { final bool gameStarted; Welcome(this.gameStarted); @override Widget build(BuildContext context) { return Container( alignment: Alignment(0, -0.2), child: Text( gameStarted ? "": "T A P T O P L A Y", style: TextStyle(color: Colors.white), )); } }

现在我们可以创建另一个类 ,使用Ball来处理球设计及其在场地中每个点的位置。我们通过构造函数传递这些参数以实现移动性,如下所示:Alignment(x,y)
class Ball extends StatelessWidget { final x; final y; Ball(this.x, this.y); @override Widget build(BuildContext context) { return Container( alignment: Alignment(x, y), child: Container( decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.white), width: 20, height: 20, ), ); } }

现在让我们设计Brick类来处理砖块设计、颜色、位置和玩家类型。
Flutter构建2D游戏实例:在这里,我们使用数学方程 ( ) 来传递 x 和 y 轴的位置:Alignment((2* x +brickWidth)/(2-brickWidth), y)
class Brick extends StatelessWidget { final x; final y; final brickWidth; final isEnemy; Brick( this.x, this.y, this.brickWidth, this.isEnemy); @override Widget build(BuildContext context) { return Container( alignment: Alignment((2* x +brickWidth)/(2-brickWidth), y), child: ClipRRect( borderRadius: BorderRadius.circular(10), child: Container( alignment: Alignment(0, 0), color: isEnemy?Colors.purple[ 500]: Colors.pink[ 300], height: 20, width:MediaQuery.of(context).size.width * brickWidth/ 2, ), )); } }

最后,Score该类应直接放置build在文件中的小部件下方;它显示每个玩家的分数。homepage.dart
为变量创建一个构造函数enemyScoreplayerScore处理每个玩家的分数,并gameStarted检查游戏是否已经开始。这将显示, 或空的内容:Stack()Container()
class Score extends StatelessWidget { final gameStarted; final enemyScore; final playerScore; Score(this.gameStarted, this.enemyScore,this.playerScore, ); @override Widget build(BuildContext context) { return gameStarted? Stack(children: [ Container( alignment: Alignment(0, 0), child: Container( height: 1, width: MediaQuery.of(context).size.width / 3, color: Colors.grey[ 800], )), Container( alignment: Alignment(0, -0.3), child: Text( enemyScore.toString(), style: TextStyle(color: Colors.grey[ 800], fontSize: 100), )), Container( alignment: Alignment(0, 0.3), child: Text( playerScore.toString(), style: TextStyle(color: Colors.grey[ 800], fontSize: 100), )), ]): Container(); } }

下面的 gif 显示了游戏的测试:
如何使用Flutter构建2D游戏(分步指南)

文章图片
Flutter构建2D游戏实例
Flutter 2D游戏构建教程结论如何使用Flutter构建2D游戏?在这篇文章中,我们介绍了alignmentRawKeyboardListener、小部件、布尔值、容器的 ClipRect 以及我们代码中的数学函数,所有这些都用于重新创建 Pong 游戏。游戏还可以通过增加球数或减少砖块长度来改进,使其更加复杂。
我希望这篇文章像构建和记录它一样有用和有趣。随意使用文章中的原理重新创建其他经典游戏,或发明一个新游戏。你可以在 GitHub 上找到这篇文章中的代码链接。

    推荐阅读