使用Flutter Widget开发游戏”是男人就坚持100秒“,一套代码横跨6端~

简介: 在文章里我说要用Widget再来做一次。现在兑现我的承诺,并且上周日在B站直播了整个开发过程

在Flutter里展示Sprite动画


请看这篇文章《手写一个在Flutter里展示”精灵图“的Widget》


飞机的移动


首先将飞机放置在画面正中,由于Widget的原点统一为左上角,所以要减去飞机图像宽和高的一半。


//获得画布的宽高
Size screenSize = window.physicalSize/window.devicePixelRatio;
//将飞机的x,y坐标设定为画面中心
playerLeft = screenSize.width/2-66/2;
playerTop = screenSize.height/2-82/2;


飞机我们需要捕获到用户的手势事件,使用GestureDetector这个Widget来拖动飞机。


GestureDetector( 
  onPanUpdate: (DragUpdateDetails details) {
    setState(() {
      playerLeft += details.delta.dx;
      playerTop += details.delta.dy;
    });
  },
  child://飞机的Widget
}


image.png


设定FPS


由于没有使用游戏引擎,所以只好自己通过定时器来实现。比如我们要实现60FPS的刷新率,可以将定时器设置为17毫秒,这样的话刷新率约等于59fps。当然可以更精确一些,但没有那个必要。


Timer.periodic(Duration(milliseconds: 17), (timer) {
  gameloop();
});
gameloop(){
    setState(() {
        //触发build方法
    });
}


不过我这里建议设置为每20毫秒刷新一次,原因在后面会讲。


添加子弹


我们建立一个子弹管理数组,将所有子弹的数据都放在数组中


List bulletsData = [];
addBullet(){
    double bulletX;
    double bulletY;
    if (Random().nextBool()) {
      bulletX = Random().nextDouble() * (screenSize.width + bulletSize.width) -
          bulletSize.width;
      bulletY = Random().nextBool() ? -bulletSize.height : screenSize.height;
    } else {
      bulletX = Random().nextBool() ? -bulletSize.width : screenSize.width;
      bulletY = Random().nextDouble() * (screenSize.height + bulletSize.height) -
          bulletSize.height;
    }
    bulletsData.add({
      "x":bulletX,
      "y":bulletY,
      "speed": (1+gameTime/10) + Random().nextDouble()*3,
      "angle": atan2(((bulletY + bulletSize.height/2) - (playerTop + playerHeight / 2)),
          ((bulletX + bulletSize.width) - (playerLeft + playerWidth / 2)))
    });
}


子弹移动


gameloop中遍历数组对子弹进行移动。


for (int i = bulletsData.length - 1; i >= 0; i--) {
      var bulletItem = bulletsData[i];
      double angle = bulletItem["angle"];
      double speed = bulletItem["speed"];
      bulletItem["x"] -= cos(angle) * speed;
      bulletItem["y"] -= sin(angle) * speed;
      if (isHitPlayer(bulletItem["x"], bulletItem["y"])) {
        print("gameOver");
        gameOver();
      }
      if (isNotInScreen(bulletItem["x"], bulletItem["y"])) {
        print("bullet removed");
        bulletsData.removeAt(i);
        continue;
      }
    }
}


子弹展示


上述代码完成后,我们的子弹在数据中就存在了。但是你看不见它们,因为他们没有被绘制到画面中。我们需要利用StackPositioned控件来展示它们。


Stack(
  children: getBulletsWidget(),
)
getBulletsWidget(){
    List<Positioned> bullets = [];
    for(int i = 0;i<bulletsData.length;i++){
      var bulletItem = bulletsData[i];
      // print(bulletItem);
      var bulletWidget = Positioned(
        left: bulletItem["x"],
        top: bulletItem["y"],
        child: bulletImage
      );
      bullets.add(bulletWidget);
    }
    return bullets;
}


image.png


按秒计时


既然游戏标题叫“是男人就坚持100秒”,那游戏中肯定需要一个按秒的计时器。还记得前面为什么我建议将计时器的刷新频率设置为20毫秒吗?这样的话,我们每刷新50次是不是就是1秒钟呢?


Timer.periodic(Duration(milliseconds: 20), (timer) {
  if(timer.tick%50==0){
    gameSeconds+=1;
    //seconds
  }
  loop();
});


在Flutter里我们可以这样做,timer里的tick是一个计时器的执行计数,会不断累计,所以我们只需要对50取余,每次整除50的时候就是1秒钟啦~


跨端


借助Flutter强大的跨端能力,这个游戏我们可以...


运行在Mac桌面


flutter run -d macOS


image.png


运行在浏览器


flutter run -d Chrome


image.png


运行在iOS


flutter run -d 模拟器ID


image.png


还有Linux,Windows,Android我就不一一给大家截图了

项目已开源,请自行运行吧!


相关文章
|
7天前
|
传感器 前端开发 Android开发
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求。本文深入探讨了插件开发的基本概念、流程、集成方法、常见类型及开发实例,如相机插件的开发步骤,同时强调了版本兼容性、性能优化等注意事项,并展望了插件开发的未来趋势。
21 2
|
27天前
深入理解Flutter鸿蒙next版本 中的Widget继承:使用extends获取数据与父类约束
本文详细介绍了Flutter中如何通过继承其他Widget来创建自定义组件。首先解释了Widget继承的基本概念,包括StatelessWidget和StatefulWidget的区别。接着通过具体示例展示了如何继承StatelessWidget和StatefulWidget,并在子类中访问父类的build方法和状态。最后,结合多个自定义Widget展示了如何在实际应用中灵活使用继承和组合来构建复杂的UI。
73 8
|
25天前
|
容器
flutter&鸿蒙next 使用 InheritedWidget 实现跨 Widget 传递状态
在 Flutter 中,状态管理至关重要。本文详细介绍了如何使用 InheritedWidget 实现跨 Widget 的状态传递。InheritedWidget 允许数据在 Widget 树中向下传递,适用于多层嵌套的场景。通过一个简单的计数器示例,展示了如何创建和使用 InheritedWidget,包括其基础概念、工作原理及代码实现。虽然 InheritedWidget 较底层,但它是许多高级状态管理解决方案的基础。
95 2
|
2月前
|
开发者
鸿蒙Flutter实战:07-混合开发
鸿蒙Flutter混合开发支持两种模式:1) 基于har包,便于主项目开发者无需关心Flutter细节,但不支持热重载;2) 基于源码依赖,利于代码维护与热重载,需配置Flutter环境。项目结构包括AppScope、flutter_module等目录,适用于不同开发需求。
79 3
|
25天前
|
传感器 开发框架 物联网
鸿蒙next选择 Flutter 开发跨平台应用的原因
鸿蒙(HarmonyOS)是华为推出的一款旨在实现多设备无缝连接的操作系统。为了实现这一目标,鸿蒙选择了 Flutter 作为主要的跨平台应用开发框架。Flutter 的跨平台能力、高性能、丰富的生态支持和与鸿蒙系统的良好兼容性,使其成为理想的选择。通过 Flutter,开发者可以高效地构建和部署多平台应用,推动鸿蒙生态的快速发展。
166 0
|
25天前
|
Dart JavaScript 前端开发
Flutter 的 Widget 概述与常用 Widgets 与鸿蒙 Next 的对比
Flutter 是 Google 开发的开源 UI 框架,用于快速构建高性能的移动、Web 和桌面应用。Flutter 通过 Widget 构建 UI,每个 UI 元素都是 Widget,包括文本、按钮、图片等。Widget 不仅描述外观,还描述行为,是不可变的。常见的 Widget 包括结构型(Container、Column、Row)、呈现型(Text、Image)、交互型(ElevatedButton)和状态管理型(StatefulWidget)。Flutter 与鸿蒙 Next 在组件化架构、开发语言、布局系统、性能和跨平台支持方面各有优势
69 0
|
27天前
|
Dart 安全 UED
Flutter&鸿蒙next中的表单封装:提升开发效率与用户体验
在移动应用开发中,表单是用户与应用交互的重要界面。本文介绍了如何在Flutter中封装表单,以提升开发效率和用户体验。通过代码复用、集中管理和一致性的优势,封装表单组件可以简化开发流程。文章详细讲解了Flutter表单的基础、封装方法和表单验证技巧,帮助开发者构建健壮且用户友好的应用。
63 0
|
2月前
|
IDE 调度 开发工具
鸿蒙Flutter实战:08-如何调试代码
本文介绍了鸿蒙Flutter项目的开发环境搭建、配置、日志查看及调试方法。首先按照指南搭建开发环境,安装IDE插件;接着配置vscode的launch.json文件;通过IDE调试控制台或命令行查看日志;提供两种调试Flutter的方式,包括IDE直接运行和使用DevEco;最后介绍ArkTs和Webview的调试方法。
54 0
|
2月前
|
编解码 Dart API
鸿蒙Flutter实战:06-使用ArkTs开发Flutter鸿蒙插件
本文介绍了如何开发一个 Flutter 鸿蒙插件,实现 Flutter 与鸿蒙的混合开发及双端消息通信。通过定义 `MethodChannel` 实现 Flutter 侧的 token 存取方法,并在鸿蒙侧编写 `EntryAbility` 和 `ForestPlugin`,使用鸿蒙的首选项 API 完成数据的读写操作。文章还提供了注意事项和参考资料,帮助开发者更好地理解和实现这一过程。
73 0
|
2月前
|
Dart Android开发
鸿蒙Flutter实战:03-鸿蒙Flutter开发中集成Webview
本文介绍了在OpenHarmony平台上集成WebView的两种方法:一是使用第三方库`flutter_inappwebview`,通过配置pubspec.lock文件实现;二是编写原生ArkTS代码,自定义PlatformView,涉及创建入口能力、注册视图工厂、处理方法调用及页面构建等步骤。
61 0
下一篇
无影云桌面