用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编程助手有什么看法?欢迎分享你的体验!

相关推荐
帅次31 分钟前
Flutter 边框按钮:OutlinedButton 完全手册与设计最佳实践
android·flutter·macos·ios·kotlin·android studio
sunly_2 小时前
Flutter:签名板封装
开发语言·javascript·flutter
Loadings2 小时前
AI Agent主流框架对比
langchain·aigc·ai 编程
Loadings2 小时前
MCP从理解到实现
前端·cursor·ai 编程
Phodal3 小时前
可编排 AI 编程助手 Shire 1.0 发布:一键连接工具生态,重塑软件开发流程
人工智能·ai 编程
Judy16234 小时前
巧用 VSCode 与 AI 编码提升 Vue 前端开发效率
前端·javascript·ai 编程