用Cursor开发Flutter游戏:AI编辑器让编程更高效

用Cursor开发Flutter游戏:AI编辑器提升编程效率

最近体验了Cursor这款编辑器,用它实现了一个"汉斯打怪兽"的Flutter小游戏。整个开发过程比较顺畅,今天分享一下使用心得,以及与团队去年引入的Copilot相比的一些体验差异。

Cursor是什么

Cursor是一个集成了AI功能的代码编辑器。它基于VS Code,内置了AI助手,可以帮你写代码、解决问题、回答问题。与普通编辑器的主要区别是,你可以用自然语言与它对话,不需要记一堆命令。

Flutter游戏开发体验

从零创建项目结构

开始新Flutter项目时,通常需要花时间思考项目结构,然后一个个手动创建文件夹和文件。这个过程不仅繁琐,还容易遗漏重要的模块。

用Cursor时,我只需要输入:

"帮我创建一个Flutter飞机射击游戏的项目结构"

它会给出一个目录结构建议,我最终实现的项目结构如下:

css 复制代码
lib/
├── main.dart
├── screens/
│   ├── home_page.dart
│   ├── game_screen.dart
│   └── splash_screen.dart
└── game/
    ├── models/
    │   ├── player.dart
    │   └── monster.dart
    ├── utils/
    │   └── collision_detector.dart
    └── widgets/
        ├── starry_background.dart
        └── game_controls.dart
assets/
└── images/
    ├── app_logo.svg
    ├── player_ship.svg
    └── monster.svg

这个结构分离了UI、游戏逻辑和资源。点击确认后,Cursor会创建这些文件和文件夹,省去了手动操作的时间。将游戏相关的代码放在单独的game目录下,使项目结构更清晰,便于维护。

项目架构设计

在开发过程中,Cursor帮助我设计了游戏的架构。下面是项目架构图:

graph TD A[main.dart] --> B[MyApp 根Widget] B --> C[SplashScreen 启动页] C --> D[HomePage 主页面] D --> E[游戏设置] D --> F[开始游戏按钮] D --> G[GameScreen 游戏界面] G --> H[StarryBackground 星空背景] G --> I[游戏主循环逻辑] G --> J[GameControls 游戏控制] I --> K[玩家飞船] I --> L[怪兽] K --> M[碰撞检测 & 计分] L --> M

这个架构图展示了游戏的组件层次和数据流向。从主应用入口到各个屏幕,再到游戏核心逻辑,每个部分都有明确的职责和关系。

文件结构也可以用Mermaid图表展示:

graph LR A[lib] --> B[main.dart] A --> C[screens] A --> D[game] C --> C1[home_page.dart] C --> C2[game_screen.dart] C --> C3[splash_screen.dart] D --> D1[models] D --> D2[utils] D --> D3[widgets] D1 --> D1A[player.dart] D1 --> D1B[monster.dart] D2 --> D2A[collision_detector.dart] D3 --> D3A[starry_background.dart] D3 --> D3B[game_controls.dart] E[assets] --> F[images] F --> F1[app_logo.svg] F --> F2[player_ship.svg] F --> F3[monster.svg]

根据描述生成SVG图标

Flutter游戏开发中,素材往往是个问题。要么去网上找现成的(可能有版权问题),要么需要设计工具自己画(需要设计技能)。

用Cursor时,我可以描述需要的图标:

"帮我创建一个太空飞船的SVG图标,简洁风格,有点未来感"

它会生成SVG代码:

xml 复制代码
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <path d="M50 20C35 20 25 35 25 50C25 65 35 75 50 75C65 75 75 65 75 50C75 35 65 20 50 20Z" fill="#3498db"/>
  <path d="M50 30C40 30 35 40 35 50C35 60 40 65 50 65C60 65 65 60 65 50C65 40 60 30 50 30Z" fill="#2980b9"/>
  <rect x="45" y="10" width="10" height="15" rx="2" fill="#95a5a6"/>
  <rect x="35" y="75" width="10" height="15" rx="2" fill="#e74c3c"/>
  <rect x="55" y="75" width="10" height="15" rx="2" fill="#e74c3c"/>
</svg>

保存为.svg文件后就能在Flutter中使用。这比在网上搜索素材或自己设计要快一些,且可以根据需求调整。

核心组件实现

在Cursor的帮助下,我实现了游戏的核心组件。下面是一些实际代码片段:

1. 主应用入口 (main.dart)
dart 复制代码
import 'package:flutter/material.dart';
import 'screens/splash_screen.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '汉斯打怪兽',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
        fontFamily: 'Microsoft YaHei', // 使用微软雅黑字体
      ),
      home: const SplashScreen(), // 使用启动页面作为首页
      debugShowCheckedModeBanner: false, // 移除调试标签
    );
  }
}

这段代码是应用入口,设置了应用主题、字体和初始页面。我描述"我想要一个中文游戏,使用微软雅黑字体,并且有启动页面",Cursor就生成了这样的代码。

2. 星空背景组件 (starry_background.dart)
dart 复制代码
import 'dart:math';
import 'package:flutter/material.dart';

class Star {
  final double x;
  final double y;
  final double size;
  final double opacity;
  
  Star({required this.x, required this.y, required this.size, required this.opacity});
  
  static Star random() {
    final random = Random();
    return Star(
      x: random.nextDouble() * 400,
      y: random.nextDouble() * 800,
      size: 1 + random.nextDouble() * 2,
      opacity: 0.3 + random.nextDouble() * 0.7,
    );
  }
}

class StarryBackground extends StatefulWidget {
  const StarryBackground({Key? key}) : super(key: key);

  @override
  _StarryBackgroundState createState() => _StarryBackgroundState();
}

class _StarryBackgroundState extends State<StarryBackground> with TickerProviderStateMixin {
  late List<Star> stars;
  late AnimationController _controller;
  
  @override
  void initState() {
    super.initState();
    // 生成随机星星
    stars = List.generate(100, (_) => Star.random());
    // 设置动画控制器
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 5000),
    )..repeat();
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return CustomPaint(
          painter: StarPainter(stars, _controller.value),
          child: child,
        );
      },
      child: Container(),
    );
  }
}

class StarPainter extends CustomPainter {
  final List<Star> stars;
  final double animationValue;
  
  StarPainter(this.stars, this.animationValue);
  
  @override
  void paint(Canvas canvas, Size size) {
    for (var star in stars) {
      // 计算闪烁效果
      final flicker = sin((animationValue * 10) + (star.x + star.y)) * 0.3 + 0.7;
      final paint = Paint()
        ..color = Colors.white.withOpacity(star.opacity * flicker);
      
      canvas.drawCircle(
        Offset(star.x % size.width, star.y % size.height),
        star.size,
        paint,
      );
    }
  }
  
  @override
  bool shouldRepaint(StarPainter oldDelegate) => true;
}

这段代码实现了一个动态的星空背景,包含随机生成的星星和闪烁效果。当我向Cursor描述"我想要一个有星星闪烁的太空背景"时,它生成了基本的Widget结构,并考虑了性能优化和动画效果。

3. 玩家飞船模型 (player.dart)
dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class Player {
  Rect rect;
  double speed;
  int lives;
  List<Rect> bullets;
  DateTime lastShootTime;
  
  Player({
    required this.rect,
    this.speed = 5.0,
    this.lives = 3,
  }) : 
    bullets = [],
    lastShootTime = DateTime.now();
  
  void move(double dx) {
    rect = rect.translate(dx * speed, 0);
  }
  
  void shoot() {
    final now = DateTime.now();
    // 限制射击频率
    if (now.difference(lastShootTime).inMilliseconds > 300) {
      bullets.add(
        Rect.fromCenter(
          center: Offset(rect.center.dx, rect.top),
          width: 5,
          height: 10,
        ),
      );
      lastShootTime = now;
      // 添加振动反馈
      HapticFeedback.lightImpact();
    }
  }
  
  void updateBullets() {
    // 移动子弹
    for (int i = bullets.length - 1; i >= 0; i--) {
      bullets[i] = bullets[i].translate(0, -10);
      
      // 移除超出屏幕的子弹
      if (bullets[i].bottom < 0) {
        bullets.removeAt(i);
      }
    }
  }
  
  void render(Canvas canvas) {
    // 绘制飞船
    final paint = Paint()
      ..color = Colors.blue;
    canvas.drawRect(rect, paint);
    
    // 绘制子弹
    final bulletPaint = Paint()
      ..color = Colors.red;
    for (var bullet in bullets) {
      canvas.drawRect(bullet, bulletPaint);
    }
  }
}

这段代码定义了玩家飞船的数据模型,包含位置、移动、射击和渲染逻辑。Cursor还添加了振动反馈功能,这是我在描述需求时提到的增强游戏体验的细节。

4. 碰撞检测工具 (collision_detector.dart)
dart 复制代码
import 'dart:math';
import 'package:flutter/material.dart';
import '../models/player.dart';
import '../models/monster.dart';

class CollisionDetector {
  static bool checkCollision(Rect rect1, Rect rect2) {
    return rect1.overlaps(rect2);
  }
  
  static void detectCollisions(Player player, List<Monster> monsters, Function(int) onScoreChanged) {
    int score = 0;
    
    // 检测子弹与怪兽的碰撞
    for (int i = player.bullets.length - 1; i >= 0; i--) {
      for (int j = monsters.length - 1; j >= 0; j--) {
        if (checkCollision(player.bullets[i], monsters[j].rect)) {
          // 处理碰撞逻辑
          player.bullets.removeAt(i);
          monsters[j].health--;
          
          if (monsters[j].health <= 0) {
            monsters.removeAt(j);
            score += 10;
            // 提供振动反馈
            HapticFeedback.mediumImpact();
          }
          
          // 更新分数
          onScoreChanged(score);
          break;
        }
      }
    }
    
    // 检测玩家与怪兽的碰撞
    for (int i = monsters.length - 1; i >= 0; i--) {
      if (checkCollision(player.rect, monsters[i].rect)) {
        player.lives--;
        monsters.removeAt(i);
        // 提供强烈振动反馈
        HapticFeedback.heavyImpact();
        break;
      }
    }
  }
}

这段代码实现了游戏中的碰撞检测逻辑,包括子弹与怪兽的碰撞和玩家与怪兽的碰撞。Cursor实现了基本的碰撞检测算法,并添加了不同强度的振动反馈,以区分不同类型的碰撞。

5. 游戏控制组件 (game_controls.dart)
dart 复制代码
import 'package:flutter/material.dart';

class GameControls extends StatelessWidget {
  final Function(double) onMove;
  final VoidCallback onShoot;
  
  const GameControls({
    Key? key,
    required this.onMove,
    required this.onShoot,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        // 左右移动控制区
        Positioned.fill(
          child: GestureDetector(
            onPanUpdate: (details) {
              onMove(details.delta.dx);
            },
          ),
        ),
        
        // 射击按钮
        Positioned(
          right: 20,
          bottom: 20,
          child: GestureDetector(
            onTap: onShoot,
            child: Container(
              width: 60,
              height: 60,
              decoration: BoxDecoration(
                color: Colors.red.withOpacity(0.5),
                shape: BoxShape.circle,
              ),
              child: const Icon(
                Icons.flash_on,
                color: Colors.white,
                size: 30,
              ),
            ),
          ),
        ),
      ],
    );
  }
}

这段代码实现了游戏的控制界面,包括左右移动和射击按钮。Cursor考虑到了移动设备的触摸特性,使用GestureDetector来捕获用户的滑动和点击操作。

数据流向

游戏的数据流向如下:

flowchart LR A[用户输入] --> B[GameControls] B --> C[Player模型] C --> D[游戏状态更新] D --> E[碰撞检测] E --> F[游戏逻辑] F --> G[Monster模型] G --> H[渲染更新] H --> I[屏幕显示]

这种数据流向在代码中的体现是:

dart 复制代码
// GameScreen中的一部分代码
void _updateGame() {
  // 更新玩家状态
  _player.updateBullets();
  
  // 更新怪兽状态
  for (var monster in _monsters) {
    monster.update();
  }
  
  // 检测碰撞
  CollisionDetector.detectCollisions(
    _player, 
    _monsters, 
    (score) {
      setState(() {
        _score += score;
      });
    }
  );
  
  // 生成新怪兽
  _generateMonsters();
  
  // 检查游戏结束条件
  if (_player.lives <= 0) {
    _gameOver();
  }
  
  // 触发重绘
  setState(() {});
}

用户输入通过GameControls传递给Player模型,触发游戏状态更新,然后通过碰撞检测影响Monster模型,最终通过setState触发重绘,反映到屏幕显示上。

最终实现效果

Cursor与Copilot的对比

去年团队引入了GitHub Copilot,它提高了编码效率,但Cursor在某些方面提供了不同的体验:

交互方式

Copilot:主要是行内代码补全和注释驱动的代码生成。你写一个Widget名或注释,它会尝试补全剩余代码。

Cursor:提供对话界面,可以进行多轮交流。你可以描述一个Flutter UI需求,它会生成解决方案,然后你可以继续提问或要求修改。

项目理解能力

Copilot:擅长理解当前文件和上下文,对整个项目结构的理解有限。

Cursor:可以理解项目结构,处理多个文件,帮助创建项目框架。

代码生成范围

Copilot:通常一次生成几行到几十行代码,适合单个Widget实现。

Cursor:可以生成完整的类或文件,包括相关的辅助类和控制器。

Flutter开发技巧

1. 描述UI需求

不需要特定格式,直接描述:"我想实现一个Flutter计分板,可以记录玩家得分"。

2. 遇到报错直接粘贴

编译报错时,把错误信息粘贴给Cursor,它通常能理解问题并给出解决方案。

3. Widget重构

当Widget变得复杂时,可以让Cursor帮忙重构:"这个StatefulWidget太长了,能帮我拆分成更小的组件吗?"

4. 学习Flutter特性

想了解Flutter中某个widget怎么用?直接问Cursor:"如何使用AnimatedBuilder实现动画?",它会给出示例代码和解释。

优缺点

Cursor在Flutter开发中的优点

  1. 项目结构建议:可以提供Flutter项目结构建议,减少手动创建的工作
  2. 从UI设计到代码的转化:描述UI需求可以得到Flutter代码实现
  3. 素材生成:能根据描述生成SVG图标,减少对设计工具的依赖
  4. 跨平台问题解决:帮助处理Flutter在不同平台上的兼容性问题

Cursor在Flutter开发中的缺点

  1. 有时会生成错误代码:特别是复杂Widget,需要自己验证
  2. 依赖网络:断网就变成普通编辑器
  3. 对大型项目理解有限:随着项目变大,可能需要多次解释上下文
  4. 编辑器功能:某些Flutter特定功能不如Flutter专用插件成熟

总结

Cursor和Copilot在Flutter开发中各有优势。Copilot像是一个随时准备补全代码的助手,而Cursor更像是一个可以讨论项目的合作伙伴。

对于"汉斯打怪兽"这样的新Flutter项目,Cursor帮助我搭建了项目结构,生成了游戏素材,实现了核心功能。在日常维护和小Widget开发中,Copilot的即时补全可能更方便。

理想的Flutter开发工作流可能是结合两者:用Cursor进行项目规划和复杂UI实现,用Copilot处理日常编码和小改动。


你用过Cursor或Copilot开发Flutter应用吗?对这两种AI编程助手有什么看法?欢迎分享你的体验!

相关推荐
爱意随风起风止意难平17 分钟前
003 flutter初始文件讲解(2)
学习·flutter
每次的天空2 小时前
Android第十一次面试flutter篇
android·flutter·面试
getapi7 小时前
为什么 uni-app 开发的 App 没有明显出现屏幕适配问题Flutter 开发的 App 出现了屏幕适配问题
flutter·uni-app
getapi7 小时前
使用 Flutter 开发 App 时,想要根据 Figma 设计稿开发出响应式 UI 界面
flutter·ui·figma
只可远观7 小时前
Flutter GridView网格组件
flutter
jianleepb9 小时前
2025Flutter(安卓)面试题详解
flutter
90后的晨仔12 小时前
Flutter 中常见的几种页面跳转方式
前端·flutter
90后的晨仔12 小时前
Flutter滚动组件全面解析
前端·flutter
张风捷特烈14 小时前
每日一题 Flutter#2 | 如何理解 Widget 的不可变性
android·flutter·面试
李新_1 天前
我们使用了哪些Flutter 三方库(二)
android·flutter·ios