Harmony Flutter 跨平台开发实战:鸿蒙与音乐律动艺术、元胞自动机:生命游戏的音频演化逻辑

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net


🧬 一、元胞自动机:简单规则产生复杂行为

📚 1.1 元胞自动机的历史

元胞自动机(Cellular Automaton,简称 CA)是由数学家**约翰·冯·诺依曼(John von Neumann)**在 1940 年代提出的概念,最初用于研究自复制系统。1970 年,**约翰·康威(John Conway)**发明了著名的"生命游戏",使元胞自动机广为人知。

历史里程碑:

年份 人物 贡献
1940 斯坦尼斯瓦夫·乌拉姆 提出网格模型
1948 约翰·冯·诺依曼 自复制自动机
1970 约翰·康威 生命游戏
1983 斯蒂芬·沃尔夫拉姆 一维 CA 分类
2002 斯蒂芬·沃尔夫拉姆 《一种新科学》

📐 1.2 生命游戏的规则

康威生命游戏是最著名的二维元胞自动机,规则极其简单却能产生复杂的行为:

基本规则:

状态 邻居数量 结果
活细胞 < 2 死亡(孤独)
活细胞 2 或 3 存活
活细胞 > 3 死亡(拥挤)
死细胞 = 3 复活(繁殖)
复制代码
生命游戏示意:

初始状态:        下一代:
□ □ □ □ □       □ □ ■ □ □
□ □ ■ □ □  →    □ □ ■ □ □
□ □ ■ □ □       □ □ ■ □ □
□ □ ■ □ □       □ □ □ □ □
□ □ □ □ □       □ □ □ □ □

■ = 活细胞
□ = 死细胞

🔬 1.3 经典图案与行为

生命游戏中存在许多有趣的图案:

图案类型 名称 特点
🔄 振荡器 闪烁器、蟾蜍 周期性变化
🚀 飞船 滑翔机、轻量飞船 持续移动
🔫 枪 滑翔机枪 持续产生飞船
💥 爆发 R-五格骨牌 快速扩张
🏛️ 静止 方块、蜂巢 稳定不变

滑翔机(Glider):

复制代码
□ ■ □
□ □ ■
■ ■ ■

🎯 1.4 元胞自动机的应用

领域 应用 效果
🧬 生物学 生态系统模拟 种群动态
🌊 物理学 流体动力学 格子气模型
🔐 密码学 伪随机数生成 流密码
🎨 艺术 生成艺术 动态图案
🎵 音乐可视化 音频驱动演化 节奏响应

🔧 二、元胞自动机的 Dart 实现

🧮 2.1 基础网格类

dart 复制代码
import 'dart:math';
import 'dart:typed_data';

/// 元胞状态
enum CellState { dead, alive }

/// 二维网格
class Grid2D {
  final int width;
  final int height;
  final List<int> _cells;
  
  Grid2D(this.width, this.height) : _cells = List<int>.filled(width * height, 0);
  
  /// 获取单元格状态
  int get(int x, int y) {
    if (x < 0 || x >= width || y < 0 || y >= height) return 0;
    return _cells[y * width + x];
  }
  
  /// 设置单元格状态
  void set(int x, int y, int value) {
    if (x >= 0 && x < width && y >= 0 && y < height) {
      _cells[y * width + x] = value;
    }
  }
  
  /// 获取邻居数量
  int countNeighbors(int x, int y) {
    int count = 0;
    for (int dy = -1; dy <= 1; dy++) {
      for (int dx = -1; dx <= 1; dx++) {
        if (dx == 0 && dy == 0) continue;
        count += get(x + dx, y + dy);
      }
    }
    return count;
  }
  
  /// 清空网格
  void clear() {
    _cells.fillRange(0, _cells.length, 0);
  }
  
  /// 随机填充
  void randomize(double density, [Random? random]) {
    random ??= Random();
    for (int i = 0; i < _cells.length; i++) {
      _cells[i] = random!.nextDouble() < density ? 1 : 0;
    }
  }
  
  /// 复制网格
  Grid2D copy() {
    final newGrid = Grid2D(width, height);
    for (int i = 0; i < _cells.length; i++) {
      newGrid._cells[i] = _cells[i];
    }
    return newGrid;
  }
  
  /// 获取活细胞数量
  int get aliveCount => _cells.fold(0, (sum, cell) => sum + cell);
  
  /// 获取密度
  double get density => aliveCount / _cells.length;
}

/// 生命游戏规则
class LifeRules {
  final Set<int> birthConditions;
  final Set<int> surviveConditions;
  
  const LifeRules({
    required this.birthConditions,
    required this.surviveConditions,
  });
  
  /// 标准康威生命游戏规则
  static const LifeRules conway = LifeRules(
    birthConditions: {3},
    surviveConditions: {2, 3},
  );
  
  /// HighLife 规则
  static const LifeRules highLife = LifeRules(
    birthConditions: {3, 6},
    surviveConditions: {2, 3},
  );
  
  /// Day & Night 规则
  static const LifeRules dayNight = LifeRules(
    birthConditions: {3, 6, 7, 8},
    surviveConditions: {3, 4, 6, 7, 8},
  );
  
  /// Seeds 规则(爆炸性增长)
  static const LifeRules seeds = LifeRules(
    birthConditions: {2},
    surviveConditions: {},
  );
  
  /// 判断下一个状态
  bool nextState(bool isAlive, int neighbors) {
    if (isAlive) {
      return surviveConditions.contains(neighbors);
    } else {
      return birthConditions.contains(neighbors);
    }
  }
}

⚡ 2.2 生命游戏引擎

dart 复制代码
/// 生命游戏引擎
class LifeEngine {
  Grid2D grid;
  LifeRules rules;
  int generation;
  
  LifeEngine({
    required int width,
    required int height,
    this.rules = LifeRules.conway,
  }) : grid = Grid2D(width, height),
       generation = 0;
  
  /// 演化一代
  void step() {
    final newGrid = Grid2D(grid.width, grid.height);
    
    for (int y = 0; y < grid.height; y++) {
      for (int x = 0; x < grid.width; x++) {
        final isAlive = grid.get(x, y) == 1;
        final neighbors = grid.countNeighbors(x, y);
        
        if (rules.nextState(isAlive, neighbors)) {
          newGrid.set(x, y, 1);
        }
      }
    }
    
    grid = newGrid;
    generation++;
  }
  
  /// 演化多代
  void stepMultiple(int count) {
    for (int i = 0; i < count; i++) {
      step();
    }
  }
  
  /// 重置
  void reset() {
    grid.clear();
    generation = 0;
  }
  
  /// 随机初始化
  void randomize(double density) {
    grid.randomize(density);
    generation = 0;
  }
  
  /// 添加图案
  void addPattern(int x, int y, List<List<int>> pattern) {
    for (int py = 0; py < pattern.length; py++) {
      for (int px = 0; px < pattern[py].length; px++) {
        grid.set(x + px, y + py, pattern[py][px]);
      }
    }
  }
  
  /// 预设图案
  static const List<List<int>> glider = [
    [0, 1, 0],
    [0, 0, 1],
    [1, 1, 1],
  ];
  
  static const List<List<int>> blinker = [
    [1, 1, 1],
  ];
  
  static const List<List<int>> beacon = [
    [1, 1, 0, 0],
    [1, 0, 0, 0],
    [0, 0, 0, 1],
    [0, 0, 1, 1],
  ];
  
  static const List<List<int>> pulsar = [
    [0,0,1,1,1,0,0,0,1,1,1,0,0],
    [0,0,0,0,0,0,0,0,0,0,0,0,0],
    [1,0,0,0,0,1,0,1,0,0,0,0,1],
    [1,0,0,0,0,1,0,1,0,0,0,0,1],
    [1,0,0,0,0,1,0,1,0,0,0,0,1],
    [0,0,1,1,1,0,0,0,1,1,1,0,0],
    [0,0,0,0,0,0,0,0,0,0,0,0,0],
    [0,0,1,1,1,0,0,0,1,1,1,0,0],
    [1,0,0,0,0,1,0,1,0,0,0,0,1],
    [1,0,0,0,0,1,0,1,0,0,0,0,1],
    [1,0,0,0,0,1,0,1,0,0,0,0,1],
    [0,0,0,0,0,0,0,0,0,0,0,0,0],
    [0,0,1,1,1,0,0,0,1,1,1,0,0],
  ];
}

🎨 2.3 音频驱动的元胞自动机

dart 复制代码
import 'package:flutter/material.dart';
import 'package:just_audio_ohos/just_audio_ohos.dart';
import 'package:audio_session/audio_session.dart';

/// 音频驱动的生命游戏控制器
class AudioLifeController extends ChangeNotifier {
  final AudioPlayer _player = AudioPlayer();
  late LifeEngine _engine;
  
  bool _isPlaying = false;
  bool _isRunning = false;
  Duration _position = Duration.zero;
  Duration _duration = Duration.zero;
  
  Float32List _audioData = Float32List(128);
  double _energy = 0;
  double _bass = 0;
  double _mid = 0;
  double _treble = 0;
  
  double _time = 0;
  int _gridWidth = 80;
  int _gridHeight = 80;
  double _stepInterval = 0.1;
  double _accumulatedTime = 0;
  
  bool get isPlaying => _isPlaying;
  bool get isRunning => _isRunning;
  Duration get position => _position;
  Duration get duration => _duration;
  LifeEngine get engine => _engine;
  Float32List get audioData => _audioData;
  double get energy => _energy;
  double get bass => _bass;
  double get mid => _mid;
  double get treble => _treble;
  AudioPlayer get player => _player;
  
  /// 初始化
  Future<void> initialize() async {
    final session = await AudioSession.instance;
    await session.configure(const AudioSessionConfiguration.music());
    
    _engine = LifeEngine(width: _gridWidth, height: _gridHeight);
    _engine.randomize(0.3);
    
    _player.playerStateStream.listen((state) {
      _isPlaying = state.playing;
      notifyListeners();
    });
    
    _player.positionStream.listen((position) {
      _position = position;
      notifyListeners();
    });
    
    _player.durationStream.listen((duration) {
      _duration = duration ?? Duration.zero;
      notifyListeners();
    });
  }
  
  /// 加载网络音频
  Future<void> loadAudio(String url) async {
    try {
      await _player.setUrl(url);
    } catch (e) {
      debugPrint('加载音频失败: $e');
    }
  }
  
  /// 更新
  void update(double dt) {
    _time += dt;
    
    // 更新音频数据
    _updateAudioData();
    
    // 计算音频特征
    _calculateAudioFeatures();
    
    // 更新演化速度
    _updateStepInterval();
    
    // 演化逻辑
    _accumulatedTime += dt;
    if (_isRunning && _accumulatedTime >= _stepInterval) {
      _engine.step();
      _accumulatedTime = 0;
      
      // 音频驱动的细胞注入
      _injectCells();
    }
    
    notifyListeners();
  }
  
  void _updateAudioData() {
    final random = Random();
    
    for (int i = 0; i < 128; i++) {
      if (_isPlaying) {
        final freq = (i / 128) * 8 + 1;
        final wave1 = sin(_time * freq) * 0.4;
        final wave2 = sin(_time * freq * 1.5 + pi / 3) * 0.3;
        final noise = (random.nextDouble() - 0.5) * 0.15;
        final bassBoost = i < 32 ? 0.3 : 0;
        
        _audioData[i] = _audioData[i] * 0.85 + 
            (wave1 + wave2 + noise + bassBoost) * 0.15;
      } else {
        _audioData[i] *= 0.95;
      }
    }
  }
  
  void _calculateAudioFeatures() {
    double totalEnergy = 0;
    double bassEnergy = 0;
    double midEnergy = 0;
    double trebleEnergy = 0;
    
    for (int i = 0; i < 128; i++) {
      final value = _audioData[i].abs();
      totalEnergy += value;
      
      if (i < 32) {
        bassEnergy += value;
      } else if (i < 96) {
        midEnergy += value;
      } else {
        trebleEnergy += value;
      }
    }
    
    _energy = totalEnergy / 128;
    _bass = bassEnergy / 32;
    _mid = midEnergy / 64;
    _treble = trebleEnergy / 32;
  }
  
  void _updateStepInterval() {
    // 能量越高,演化越快
    _stepInterval = 0.2 - _energy * 0.15;
    _stepInterval = _stepInterval.clamp(0.02, 0.2);
  }
  
  void _injectCells() {
    final random = Random();
    
    // 低音脉冲注入细胞
    if (_bass > 0.5) {
      final count = (_bass * 20).toInt();
      for (int i = 0; i < count; i++) {
        final x = random.nextInt(_gridWidth);
        final y = random.nextInt(_gridHeight);
        _engine.grid.set(x, y, 1);
      }
    }
    
    // 高频注入滑翔机
    if (_treble > 0.6 && random.nextDouble() < 0.3) {
      final x = random.nextInt(_gridWidth - 3);
      final y = random.nextInt(_gridHeight - 3);
      _engine.addPattern(x, y, LifeEngine.glider);
    }
  }
  
  /// 开始/暂停演化
  void toggleRunning() {
    _isRunning = !_isRunning;
    notifyListeners();
  }
  
  /// 单步演化
  void stepOnce() {
    _engine.step();
    notifyListeners();
  }
  
  /// 重置
  void reset() {
    _engine.reset();
    _engine.randomize(0.3);
    notifyListeners();
  }
  
  /// 切换单元格
  void toggleCell(int x, int y) {
    final current = _engine.grid.get(x, y);
    _engine.grid.set(x, y, current == 0 ? 1 : 0);
    notifyListeners();
  }
  
  /// 设置规则
  void setRules(LifeRules rules) {
    _engine.rules = rules;
    notifyListeners();
  }
  
  /// 播放/暂停音频
  Future<void> togglePlay() async {
    if (_isPlaying) {
      await _player.pause();
    } else {
      await _player.play();
    }
  }
  
  /// 跳转
  Future<void> seek(Duration position) async {
    await _player.seek(position);
  }
  
  @override
  void dispose() {
    _player.dispose();
    super.dispose();
  }
}

📦 三、完整示例代码

以下是完整的元胞自动机音乐可视化示例代码:

dart 复制代码
import 'package:flutter/material.dart';
import 'package:just_audio_ohos/just_audio_ohos.dart';
import 'package:audio_session/audio_session.dart';
import 'dart:math';
import 'dart:typed_data';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '元胞自动机',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green, brightness: Brightness.dark),
        useMaterial3: true,
      ),
      home: const LifeHomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('🧬 元胞自动机'), backgroundColor: Theme.of(context).colorScheme.inversePrimary),
      body: ListView(padding: const EdgeInsets.all(16), children: [
        _buildCard(context, title: '基础生命游戏', description: '康威生命游戏', icon: Icons.grid_on, color: Colors.green,
            onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const BasicLifeDemo()))),
        _buildCard(context, title: '规则变体', description: '不同规则效果', icon: Icons.settings, color: Colors.teal,
            onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const RulesDemo()))),
        _buildCard(context, title: '图案库', description: '经典图案展示', icon: Icons.category, color: Colors.cyan,
            onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const PatternsDemo()))),
        _buildCard(context, title: '音乐生命', description: '音频驱动演化', icon: Icons.music_note, color: Colors.orange,
            onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const MusicLifeDemo()))),
        _buildCard(context, title: '交互模式', description: '触摸绘制细胞', icon: Icons.touch_app, color: Colors.purple,
            onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const InteractiveLifeDemo()))),
      ]),
    );
  }

  Widget _buildCard(BuildContext context, {required String title, required String description, required IconData icon, 
      required Color color, required VoidCallback onTap}) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(16),
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Row(children: [
            Container(width: 56, height: 56, decoration: BoxDecoration(color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12)),
                child: Icon(icon, color: color, size: 28)),
            const SizedBox(width: 16),
            Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
              Text(title, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              const SizedBox(height: 4),
              Text(description, style: TextStyle(color: Colors.grey[600], fontSize: 14)),
            ])),
            Icon(Icons.chevron_right, color: Colors.grey[400]),
          ]),
        ),
      ),
    );
  }
}

/// 网格类
class Grid {
  final int width, height;
  final List<int> cells;
  Grid(this.width, this.height) : cells = List<int>.filled(width * height, 0);
  
  int get(int x, int y) => (x < 0 || x >= width || y < 0 || y >= height) ? 0 : cells[y * width + x];
  void set(int x, int y, int v) { if (x >= 0 && x < width && y >= 0 && y < height) cells[y * width + x] = v; }
  
  int countNeighbors(int x, int y) {
    int c = 0;
    for (int dy = -1; dy <= 1; dy++) for (int dx = -1; dx <= 1; dx++) 
      if (dx != 0 || dy != 0) c += get(x + dx, y + dy);
    return c;
  }
  
  void randomize(double density) {
    final r = Random();
    for (int i = 0; i < cells.length; i++) cells[i] = r.nextDouble() < density ? 1 : 0;
  }
  
  void clear() => cells.fillRange(0, cells.length, 0);
}

/// 基础生命游戏演示
class BasicLifeDemo extends StatefulWidget {
  const BasicLifeDemo({super.key});
  @override
  State<BasicLifeDemo> createState() => _BasicLifeDemoState();
}

class _BasicLifeDemoState extends State<BasicLifeDemo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Grid _grid;
  bool _running = false;
  int _generation = 0;
  final int _size = 60;

  @override
  void initState() {
    super.initState();
    _grid = Grid(_size, _size);
    _grid.randomize(0.3);
    _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 100))..repeat();
    _controller.addListener(_update);
  }
  
  void _update() {
    if (_running) {
      _step();
      setState(() {});
    }
  }
  
  void _step() {
    final newGrid = Grid(_size, _size);
    for (int y = 0; y < _size; y++) {
      for (int x = 0; x < _size; x++) {
        final alive = _grid.get(x, y) == 1;
        final n = _grid.countNeighbors(x, y);
        newGrid.set(x, y, (alive && (n == 2 || n == 3)) || (!alive && n == 3) ? 1 : 0);
      }
    }
    _grid = newGrid;
    _generation++;
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('基础生命游戏')),
      body: Column(children: [
        Expanded(child: CustomPaint(painter: LifePainter(_grid), size: Size.infinite)),
        _buildControls(),
      ]),
    );
  }

  Widget _buildControls() {
    return Container(
      padding: const EdgeInsets.all(16),
      color: Colors.black12,
      child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
        Text('代数: $_generation', style: const TextStyle(color: Colors.white)),
        IconButton(icon: Icon(_running ? Icons.pause : Icons.play_arrow, color: Colors.green),
            onPressed: () => setState(() => _running = !_running)),
        IconButton(icon: const Icon(Icons.skip_next, color: Colors.white),
            onPressed: () { _step(); setState(() {}); }),
        IconButton(icon: const Icon(Icons.refresh, color: Colors.white),
            onPressed: () { _grid.randomize(0.3); _generation = 0; setState(() {}); }),
      ]),
    );
  }
}

class LifePainter extends CustomPainter {
  final Grid grid;
  LifePainter(this.grid);
  
  @override
  void paint(Canvas canvas, Size size) {
    final cellW = size.width / grid.width;
    final cellH = size.height / grid.height;
    
    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), Paint()..color = const Color(0xFF0a0a15));
    
    for (int y = 0; y < grid.height; y++) {
      for (int x = 0; x < grid.width; x++) {
        if (grid.get(x, y) == 1) {
          final hue = (x + y) * 2 % 360;
          canvas.drawRect(
            Rect.fromLTWH(x * cellW, y * cellH, cellW - 1, cellH - 1),
            Paint()..color = HSVColor.fromAHSV(1, hue.toDouble(), 0.7, 1).toColor(),
          );
        }
      }
    }
  }
  
  @override
  bool shouldRepaint(covariant LifePainter old) => true;
}

/// 规则变体演示
class RulesDemo extends StatefulWidget {
  const RulesDemo({super.key});
  @override
  State<RulesDemo> createState() => _RulesDemoState();
}

class _RulesDemoState extends State<RulesDemo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Grid _grid;
  bool _running = false;
  String _ruleName = 'Conway';
  final int _size = 50;
  
  final Map<String, Set<int>> _birthRules = {
    'Conway': {3},
    'HighLife': {3, 6},
    'Day&Night': {3, 6, 7, 8},
    'Seeds': {2},
  };
  
  final Map<String, Set<int>> _surviveRules = {
    'Conway': {2, 3},
    'HighLife': {2, 3},
    'Day&Night': {3, 4, 6, 7, 8},
    'Seeds': {},
  };

  @override
  void initState() {
    super.initState();
    _grid = Grid(_size, _size);
    _grid.randomize(0.3);
    _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 100))..repeat();
    _controller.addListener(_update);
  }
  
  void _update() {
    if (_running) {
      _step();
      setState(() {});
    }
  }
  
  void _step() {
    final birth = _birthRules[_ruleName]!;
    final survive = _surviveRules[_ruleName]!;
    final newGrid = Grid(_size, _size);
    
    for (int y = 0; y < _size; y++) {
      for (int x = 0; x < _size; x++) {
        final alive = _grid.get(x, y) == 1;
        final n = _grid.countNeighbors(x, y);
        newGrid.set(x, y, (alive && survive.contains(n)) || (!alive && birth.contains(n)) ? 1 : 0);
      }
    }
    _grid = newGrid;
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('规则变体')),
      body: Column(children: [
        Expanded(child: CustomPaint(painter: LifePainter(_grid), size: Size.infinite)),
        _buildControls(),
      ]),
    );
  }

  Widget _buildControls() {
    return Container(
      padding: const EdgeInsets.all(16),
      color: Colors.black12,
      child: Column(children: [
        Wrap(spacing: 8, children: _birthRules.keys.map((name) => 
          ChoiceChip(label: Text(name), selected: _ruleName == name,
              onSelected: (_) => setState(() { _ruleName = name; _grid.randomize(0.3); }))).toList()),
        const SizedBox(height: 8),
        Row(mainAxisAlignment: MainAxisAlignment.center, children: [
          IconButton(icon: Icon(_running ? Icons.pause : Icons.play_arrow, color: Colors.green),
              onPressed: () => setState(() => _running = !_running)),
          IconButton(icon: const Icon(Icons.refresh, color: Colors.white),
              onPressed: () { _grid.randomize(0.3); setState(() {}); }),
        ]),
      ]),
    );
  }
}

/// 图案库演示
class PatternsDemo extends StatefulWidget {
  const PatternsDemo({super.key});
  @override
  State<PatternsDemo> createState() => _PatternsDemoState();
}

class _PatternsDemoState extends State<PatternsDemo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Grid _grid;
  bool _running = false;
  final int _size = 60;
  String _pattern = 'Glider';
  
  final Map<String, List<List<int>>> _patterns = {
    'Glider': [[0,1,0],[0,0,1],[1,1,1]],
    'Blinker': [[1,1,1]],
    'Beacon': [[1,1,0,0],[1,0,0,0],[0,0,0,1],[0,0,1,1]],
    'Toad': [[0,1,1,1],[1,1,1,0]],
    'Pulsar': [
      [0,0,1,1,1,0,0,0,1,1,1,0,0],
      [0,0,0,0,0,0,0,0,0,0,0,0,0],
      [1,0,0,0,0,1,0,1,0,0,0,0,1],
      [1,0,0,0,0,1,0,1,0,0,0,0,1],
      [1,0,0,0,0,1,0,1,0,0,0,0,1],
      [0,0,1,1,1,0,0,0,1,1,1,0,0],
      [0,0,0,0,0,0,0,0,0,0,0,0,0],
      [0,0,1,1,1,0,0,0,1,1,1,0,0],
      [1,0,0,0,0,1,0,1,0,0,0,0,1],
      [1,0,0,0,0,1,0,1,0,0,0,0,1],
      [1,0,0,0,0,1,0,1,0,0,0,0,1],
      [0,0,0,0,0,0,0,0,0,0,0,0,0],
      [0,0,1,1,1,0,0,0,1,1,1,0,0],
    ],
  };

  @override
  void initState() {
    super.initState();
    _grid = Grid(_size, _size);
    _addPattern();
    _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 150))..repeat();
    _controller.addListener(_update);
  }
  
  void _addPattern() {
    _grid.clear();
    final pattern = _patterns[_pattern]!;
    final x = (_size - pattern[0].length) ~/ 2;
    final y = (_size - pattern.length) ~/ 2;
    for (int py = 0; py < pattern.length; py++) {
      for (int px = 0; px < pattern[py].length; px++) {
        _grid.set(x + px, y + py, pattern[py][px]);
      }
    }
  }
  
  void _update() {
    if (_running) {
      _step();
      setState(() {});
    }
  }
  
  void _step() {
    final newGrid = Grid(_size, _size);
    for (int y = 0; y < _size; y++) {
      for (int x = 0; x < _size; x++) {
        final alive = _grid.get(x, y) == 1;
        final n = _grid.countNeighbors(x, y);
        newGrid.set(x, y, (alive && (n == 2 || n == 3)) || (!alive && n == 3) ? 1 : 0);
      }
    }
    _grid = newGrid;
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('图案库')),
      body: Column(children: [
        Expanded(child: CustomPaint(painter: LifePainter(_grid), size: Size.infinite)),
        _buildControls(),
      ]),
    );
  }

  Widget _buildControls() {
    return Container(
      padding: const EdgeInsets.all(16),
      color: Colors.black12,
      child: Column(children: [
        Wrap(spacing: 8, children: _patterns.keys.map((name) => 
          ChoiceChip(label: Text(name), selected: _pattern == name,
              onSelected: (_) => setState(() { _pattern = name; _addPattern(); }))).toList()),
        const SizedBox(height: 8),
        Row(mainAxisAlignment: MainAxisAlignment.center, children: [
          IconButton(icon: Icon(_running ? Icons.pause : Icons.play_arrow, color: Colors.green),
              onPressed: () => setState(() => _running = !_running)),
          IconButton(icon: const Icon(Icons.refresh, color: Colors.white),
              onPressed: () { _addPattern(); setState(() {}); }),
        ]),
      ]),
    );
  }
}

/// 音乐生命演示
class MusicLifeDemo extends StatefulWidget {
  const MusicLifeDemo({super.key});
  @override
  State<MusicLifeDemo> createState() => _MusicLifeDemoState();
}

class _MusicLifeDemoState extends State<MusicLifeDemo> with TickerProviderStateMixin {
  late AnimationController _animController;
  late AudioPlayer _audioPlayer;
  late Grid _grid;
  Float32List _audioData = Float32List(128);
  bool _isPlaying = false;
  bool _running = true;
  Duration _position = Duration.zero;
  Duration _duration = Duration.zero;
  double _energy = 0, _bass = 0;
  double _time = 0, _stepTime = 0;
  final int _size = 50;
  
  static const String _audioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3';

  @override
  void initState() {
    super.initState();
    _grid = Grid(_size, _size);
    _grid.randomize(0.25);
    _initAudio();
    _animController = AnimationController(vsync: this, duration: const Duration(milliseconds: 16))..repeat();
    _animController.addListener(_update);
  }
  
  Future<void> _initAudio() async {
    _audioPlayer = AudioPlayer();
    final session = await AudioSession.instance;
    await session.configure(const AudioSessionConfiguration.music());
    
    _audioPlayer.playerStateStream.listen((s) => setState(() => _isPlaying = s.playing));
    _audioPlayer.positionStream.listen((p) => setState(() => _position = p));
    _audioPlayer.durationStream.listen((d) => setState(() => _duration = d ?? Duration.zero));
    
    try { await _audioPlayer.setUrl(_audioUrl); } catch (e) { debugPrint('加载失败: $e'); }
  }
  
  void _update() {
    _time += 0.016;
    
    for (int i = 0; i < 128; i++) {
      if (_isPlaying) {
        final freq = (i / 128) * 8 + 1;
        final wave = sin(_time * freq) * 0.4 + sin(_time * freq * 1.5) * 0.3;
        final bass = i < 32 ? 0.3 : 0;
        _audioData[i] = _audioData[i] * 0.85 + (wave + bass) * 0.15;
      } else {
        _audioData[i] *= 0.95;
      }
    }
    
    double total = 0, bassE = 0;
    for (int i = 0; i < 128; i++) {
      total += _audioData[i].abs();
      if (i < 32) bassE += _audioData[i].abs();
    }
    _energy = total / 128;
    _bass = bassE / 32;
    
    // 演化
    final stepInterval = (0.15 - _energy * 0.1).clamp(0.03, 0.15);
    _stepTime += 0.016;
    
    if (_running && _stepTime >= stepInterval) {
      _step();
      _injectCells();
      _stepTime = 0;
    }
    
    setState(() {});
  }
  
  void _step() {
    final newGrid = Grid(_size, _size);
    for (int y = 0; y < _size; y++) {
      for (int x = 0; x < _size; x++) {
        final alive = _grid.get(x, y) == 1;
        final n = _grid.countNeighbors(x, y);
        newGrid.set(x, y, (alive && (n == 2 || n == 3)) || (!alive && n == 3) ? 1 : 0);
      }
    }
    _grid = newGrid;
  }
  
  void _injectCells() {
    final r = Random();
    if (_bass > 0.5) {
      for (int i = 0; i < (_bass * 15).toInt(); i++) {
        _grid.set(r.nextInt(_size), r.nextInt(_size), 1);
      }
    }
  }

  @override
  void dispose() {
    _animController.dispose();
    _audioPlayer.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('音乐生命')),
      body: Stack(children: [
        CustomPaint(painter: MusicLifePainter(_grid, _energy), size: Size.infinite),
        Positioned(bottom: 30, left: 20, right: 20, child: _buildControls()),
      ]),
    );
  }
  
  Widget _buildControls() {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(color: Colors.black.withOpacity(0.7), borderRadius: BorderRadius.circular(16)),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          const Text('🎵 SoundHelix - Song 1', style: TextStyle(color: Colors.white, fontSize: 14)),
          const SizedBox(height: 12),
          Slider(value: _duration.inMilliseconds > 0 ? _position.inMilliseconds.toDouble().clamp(0, _duration.inMilliseconds.toDouble()) : 0,
              max: _duration.inMilliseconds > 0 ? _duration.inMilliseconds.toDouble() : 1,
              onChanged: (v) => _audioPlayer.seek(Duration(milliseconds: v.toInt()))),
          Row(mainAxisAlignment: MainAxisAlignment.center, children: [
            IconButton(icon: Icon(_running ? Icons.pause : Icons.play_arrow, color: Colors.green),
                onPressed: () => setState(() => _running = !_running)),
            IconButton(icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow, color: Colors.orange, size: 36),
                onPressed: () => _isPlaying ? _audioPlayer.pause() : _audioPlayer.play()),
            IconButton(icon: const Icon(Icons.refresh, color: Colors.white),
                onPressed: () { _grid.randomize(0.25); setState(() {}); }),
          ]),
        ],
      ),
    );
  }
}

class MusicLifePainter extends CustomPainter {
  final Grid grid;
  final double energy;
  
  MusicLifePainter(this.grid, this.energy);
  
  @override
  void paint(Canvas canvas, Size size) {
    final cellW = size.width / grid.width;
    final cellH = size.height / grid.height;
    
    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height),
        Paint()..color = Color.lerp(const Color(0xFF0a0a15), const Color(0xFF100a20), energy)!);
    
    for (int y = 0; y < grid.height; y++) {
      for (int x = 0; x < grid.width; x++) {
        if (grid.get(x, y) == 1) {
          final hue = (x * 3 + y * 5 + energy * 100) % 360;
          final paint = Paint()..color = HSVColor.fromAHSV(0.8 + energy * 0.2, hue, 0.7, 1).toColor();
          
          if (energy > 0.3) paint.maskFilter = MaskFilter.blur(BlurStyle.normal, 1 + energy * 2);
          
          canvas.drawRect(Rect.fromLTWH(x * cellW, y * cellH, cellW - 1, cellH - 1), paint);
        }
      }
    }
  }
  
  @override
  bool shouldRepaint(covariant MusicLifePainter old) => true;
}

/// 交互模式演示
class InteractiveLifeDemo extends StatefulWidget {
  const InteractiveLifeDemo({super.key});
  @override
  State<InteractiveLifeDemo> createState() => _InteractiveLifeDemoState();
}

class _InteractiveLifeDemoState extends State<InteractiveLifeDemo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Grid _grid;
  bool _running = false;
  final int _size = 40;

  @override
  void initState() {
    super.initState();
    _grid = Grid(_size, _size);
    _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 150))..repeat();
    _controller.addListener(_update);
  }
  
  void _update() {
    if (_running) {
      _step();
      setState(() {});
    }
  }
  
  void _step() {
    final newGrid = Grid(_size, _size);
    for (int y = 0; y < _size; y++) {
      for (int x = 0; x < _size; x++) {
        final alive = _grid.get(x, y) == 1;
        final n = _grid.countNeighbors(x, y);
        newGrid.set(x, y, (alive && (n == 2 || n == 3)) || (!alive && n == 3) ? 1 : 0);
      }
    }
    _grid = newGrid;
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('交互模式')),
      body: GestureDetector(
        onPanStart: (details) => _toggleCell(details.localPosition),
        onPanUpdate: (details) => _toggleCell(details.localPosition),
        child: Stack(children: [
          CustomPaint(painter: LifePainter(_grid), size: Size.infinite),
          Positioned(bottom: 20, left: 20, child: Container(
            padding: const EdgeInsets.all(8),
            decoration: BoxDecoration(color: Colors.black.withOpacity(0.7), borderRadius: BorderRadius.circular(8)),
            child: const Text('触摸绘制细胞', style: TextStyle(color: Colors.white54, fontSize: 12)),
          )),
        ]),
      ),
      floatingActionButton: Row(mainAxisAlignment: MainAxisAlignment.end, children: [
        FloatingActionButton(heroTag: 'play', backgroundColor: _running ? Colors.orange : Colors.green,
            child: Icon(_running ? Icons.pause : Icons.play_arrow),
            onPressed: () => setState(() => _running = !_running)),
        const SizedBox(width: 10),
        FloatingActionButton(heroTag: 'clear', backgroundColor: Colors.red,
            child: const Icon(Icons.clear),
            onPressed: () { _grid.clear(); setState(() {}); }),
      ]),
    );
  }
  
  void _toggleCell(Offset localPosition) {
    final RenderBox box = context.findRenderObject() as RenderBox;
    final size = box.size;
    final cellW = size.width / _size;
    final cellH = size.height / _size;
    final x = (localPosition.dx / cellW).floor();
    final y = (localPosition.dy / cellH).floor();
    
    if (x >= 0 && x < _size && y >= 0 && y < _size) {
      setState(() => _grid.set(x, y, _grid.get(x, y) == 0 ? 1 : 0));
    }
  }
}

📝 四、总结

本篇文章深入探讨了元胞自动机在音乐可视化中的应用,从康威生命游戏到音频驱动的演化规则,构建了具有"生命感"的动态网格动画效果。

✅ 核心知识点回顾

知识点 说明
🧬 元胞自动机 网格、邻居、规则
🎮 生命游戏 康威规则、经典图案
📐 规则变体 HighLife、Day&Night
🎵 音频驱动 能量控制演化速度
🔊 网络音乐 just_audio_ohos 在线播放

⭐ 最佳实践要点

  • ✅ 使用双缓冲避免读写冲突
  • ✅ 低分辨率网格保证性能
  • ✅ 音频特征注入细胞
  • ✅ 支持交互绘制

🚀 进阶方向

  • 🔮 多状态元胞自动机
  • ✨ 3D 元胞自动机
  • 👆 多点触控绘制
  • ⚡ GPU 并行计算

相关推荐
梦想的颜色1 小时前
【编程实战】AI 时代 APP 开发全栈硬核指南:技术选型 + AI 架构 + 模型落地全维度决策
python·flutter·react native·react.js·ai·桌面应用·milvus
yuanlaile20 小时前
2026年全新Flutter 跨平台开发全栈学习资料整理
flutter·getx·鸿蒙 next·flutter开发鸿蒙·flutter入门实战·flutter全栈
恋猫de小郭1 天前
Genkit Dart 1.0 发布,Flutter 原生的 AI Agent 终于完整了
android·前端·flutter
第10086个小白1 天前
flutter桌面端打包方式(Inno Setup Compiler)版本
前端·flutter
陆断枫2 天前
Flutter 3.47 动画引擎盘点:Impeller 全平台,和那些"新特性"
flutter
程序员老刘2 天前
Flet 1.0 思路很好,可惜来晚了
flutter·ai编程·客户端
m0_738185822 天前
Flutter 鸿蒙化实战:qr_code_scanner_plus 适配 OpenHarmony,二维码扫描
flutter·华为·harmonyos·鸿蒙
恋猫de小郭2 天前
Flutter + EmbeddingGemma 2,谷歌发布完全端侧的 AI Edge Foresight
android·前端·flutter
君赏3 天前
基于 FlutterPatch 快速接入 Flutter 热更新
flutter
律宏阔3 天前
Dart FFI 内存管理:用 using + Arena 替代嵌套 try-finally
前端·flutter