news 2026/2/5 22:12:52

Flutter游戏开发与图形渲染实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter游戏开发与图形渲染实战

🔗实战项目:openharmonycrossplatform.csdn.net/content

📖 目录

  • 🎮 游戏引擎基础

  • 🎨 图形渲染

  • ⚡ 物理引擎

  • 📱 触摸交互

🎮 一、游戏引擎基础

1.1 游戏循环实现

dart

// lib/game/game_loop.dart import 'dart:async'; import 'dart:math'; class GameLoop { late Timer _timer; bool _isRunning = false; int _lastTime = 0; double _deltaTime = 0; final void Function(double deltaTime) onUpdate; final void Function(Canvas canvas) onRender; GameLoop({ required this.onUpdate, required this.onRender, }); void start() { if (_isRunning) return; _isRunning = true; _lastTime = DateTime.now().millisecondsSinceEpoch; _timer = Timer.periodic(const Duration(milliseconds: 16), (_) { _tick(); }); } void stop() { _isRunning = false; _timer.cancel(); } void _tick() { final currentTime = DateTime.now().millisecondsSinceEpoch; _deltaTime = (currentTime - _lastTime) / 1000.0; _lastTime = currentTime; // 限制最大deltaTime,避免卡顿导致的问题 _deltaTime = min(_deltaTime, 0.1); onUpdate(_deltaTime); } double get deltaTime => _deltaTime; bool get isRunning => _isRunning; }

1.2 游戏对象管理

dart

// lib/game/game_object.dart import 'package:flutter/material.dart'; abstract class GameObject { Offset position = Offset.zero; double rotation = 0; double scale = 1.0; void update(double deltaTime); void render(Canvas canvas); void translate(double dx, double dy) { position = Offset( position.dx + dx, position.dy + dy, ); } void rotate(double angle) { rotation += angle; } } class Sprite extends GameObject { final Image image; final Size size; Sprite({ required this.image, required this.size, }); @override void update(double deltaTime) { // 精灵更新逻辑 } @override void render(Canvas canvas) { canvas.save(); // 应用变换 canvas.translate(position.dx, position.dy); canvas.rotate(rotation); canvas.scale(scale); // 绘制精灵 paintImage( canvas: canvas, rect: Rect.fromCenter( center: Offset.zero, width: size.width, height: size.height, ), image: image, fit: BoxFit.contain, ); canvas.restore(); } } class GameWorld { final List<GameObject> _objects = []; final List<GameObject> _toAdd = []; final List<GameObject> _toRemove = []; void addObject(GameObject object) { _toAdd.add(object); } void removeObject(GameObject object) { _toRemove.add(object); } void update(double deltaTime) { // 添加新对象 _objects.addAll(_toAdd); _toAdd.clear(); // 更新所有对象 for (final object in _objects) { object.update(deltaTime); } // 移除标记的对象 _objects.removeWhere((obj) => _toRemove.contains(obj)); _toRemove.clear(); } void render(Canvas canvas) { for (final object in _objects) { object.render(canvas); } } List<GameObject> findObjectsNear(Offset position, double radius) { return _objects.where((obj) { final distance = (obj.position - position).distance; return distance <= radius; }).toList(); } }

🎨 二、图形渲染系统

2.1 粒子系统

dart

// lib/graphics/particle_system.dart import 'dart:math'; import 'package:flutter/material.dart'; class Particle { Offset position; Offset velocity; double size; Color color; double life; double maxLife; Particle({ required this.position, required this.velocity, required this.size, required this.color, required this.maxLife, }) : life = maxLife; void update(double deltaTime) { position += velocity * deltaTime; life -= deltaTime; // 重力效果 velocity += const Offset(0, 98) * deltaTime; } void render(Canvas canvas) { final alpha = (life / maxLife).clamp(0.0, 1.0); final paint = Paint() ..color = color.withOpacity(alpha) ..style = PaintingStyle.fill; canvas.drawCircle(position, size * alpha, paint); } bool get isDead => life <= 0; } class ParticleSystem extends GameObject { final List<Particle> _particles = []; final Random _random = Random(); Offset _emitterPosition = Offset.zero; bool _isEmitting = false; @override void update(double deltaTime) { // 发射新粒子 if (_isEmitting) { _emitParticles(deltaTime); } // 更新现有粒子 _particles.removeWhere((particle) { particle.update(deltaTime); return particle.isDead; }); } @override void render(Canvas canvas) { for (final particle in _particles) { particle.render(canvas); } } void startEmission() { _isEmitting = true; } void stopEmission() { _isEmitting = false; } void _emitParticles(double deltaTime) { final count = (deltaTime * 100).toInt(); // 每秒100个粒子 for (int i = 0; i < count; i++) { _particles.add(Particle( position: _emitterPosition, velocity: Offset( (_random.nextDouble() - 0.5) * 100, -_random.nextDouble() * 200, ), size: _random.nextDouble() * 5 + 2, color: Color.fromARGB( 255, _random.nextInt(255), _random.nextInt(255), _random.nextInt(255), ), maxLife: _random.nextDouble() * 2 + 1, )); } } void setEmitterPosition(Offset position) { _emitterPosition = position; } }

2.2 着色器效果

dart

// lib/graphics/shaders.dart import 'dart:ui'; import 'package:flutter/material.dart'; class ShaderEffects { static Future<FragmentProgram> loadShader(String assetPath) async { return await FragmentProgram.fromAsset(assetPath); } // 波浪效果 static Shader waveShader(Size size, double time) { return const LinearGradient( colors: [Colors.blue, Colors.purple], stops: [0.0, 1.0], ).createShader(Rect.fromLTWH(0, 0, size.width, size.height)); } // 模糊效果 static ImageFilter blurFilter(double radius) { return ImageFilter.blur(sigmaX: radius, sigmaY: radius); } } class AnimatedBackground extends StatelessWidget { final double animationValue; const AnimatedBackground({ super.key, required this.animationValue, }); @override Widget build(BuildContext context) { return CustomPaint( painter: _BackgroundPainter(animationValue), size: Size.infinite, ); } } class _BackgroundPainter extends CustomPainter { final double animationValue; _BackgroundPainter(this.animationValue); @override void paint(Canvas canvas, Size size) { // 创建渐变背景 final gradient = LinearGradient( colors: [ Colors.blue.withOpacity(0.3), Colors.purple.withOpacity(0.3), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ); final paint = Paint() ..shader = gradient.createShader( Rect.fromLTWH(0, 0, size.width, size.height), ); canvas.drawRect( Rect.fromLTWH(0, 0, size.width, size.height), paint, ); // 绘制动画波浪 final wavePaint = Paint() ..color = Colors.white.withOpacity(0.1) ..style = PaintingStyle.fill; final path = Path(); path.moveTo(0, size.height * 0.7); for (double x = 0; x <= size.width; x += 5) { final y = size.height * 0.7 + sin(x * 0.01 + animationValue * 2 * pi) * 20; path.lineTo(x, y); } path.lineTo(size.width, size.height); path.lineTo(0, size.height); path.close(); canvas.drawPath(path, wavePaint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => true; }

⚡ 三、物理引擎集成

3.1 基础物理模拟

dart

// lib/physics/physics_engine.dart import 'dart:math'; class PhysicsBody { Vector2 position = Vector2.zero(); Vector2 velocity = Vector2.zero(); Vector2 acceleration = Vector2.zero(); double mass = 1.0; double friction = 0.98; bool isStatic = false; void applyForce(Vector2 force) { if (!isStatic) { acceleration += force / mass; } } void update(double deltaTime) { if (isStatic) return; velocity += acceleration * deltaTime; velocity *= friction; // 应用摩擦力 position += velocity * deltaTime; // 重置加速度 acceleration = Vector2.zero(); } void checkBoundary(Rect bounds) { // 边界碰撞检测 if (position.x < bounds.left) { position.x = bounds.left; velocity.x = -velocity.x * 0.8; } if (position.x > bounds.right) { position.x = bounds.right; velocity.x = -velocity.x * 0.8; } if (position.y < bounds.top) { position.y = bounds.top; velocity.y = -velocity.y * 0.8; } if (position.y > bounds.bottom) { position.y = bounds.bottom; velocity.y = -velocity.y * 0.8; } } } class Vector2 { double x; double y; Vector2(this.x, this.y); factory Vector2.zero() => Vector2(0, 0); Vector2 operator +(Vector2 other) => Vector2(x + other.x, y + other.y); Vector2 operator -(Vector2 other) => Vector2(x - other.x, y - other.y); Vector2 operator *(double scalar) => Vector2(x * scalar, y * scalar); Vector2 operator /(double scalar) => Vector2(x / scalar, y / scalar); double get magnitude => sqrt(x * x + y * y); Vector2 get normalized => this / magnitude; double dot(Vector2 other) => x * other.x + y * other.y; } class PhysicsWorld { final List<PhysicsBody> _bodies = []; final Vector2 gravity = Vector2(0, 98); void addBody(PhysicsBody body) { _bodies.add(body); } void update(double deltaTime) { // 应用重力 for (final body in _bodies) { if (!body.isStatic) { body.applyForce(gravity * body.mass); } } // 更新所有物体 for (final body in _bodies) { body.update(deltaTime); } // 碰撞检测 _checkCollisions(); } void _checkCollisions() { for (int i = 0; i < _bodies.length; i++) { for (int j = i + 1; j < _bodies.length; j++) { final bodyA = _bodies[i]; final bodyB = _bodies[j]; if (bodyA.isStatic && bodyB.isStatic) continue; final distance = (bodyA.position - bodyB.position).magnitude; const minDistance = 30.0; // 假设半径为15 if (distance < minDistance) { _resolveCollision(bodyA, bodyB); } } } } void _resolveCollision(PhysicsBody a, PhysicsBody b) { // 简单的碰撞响应 final normal = (a.position - b.position).normalized; // 相对速度 final relativeVelocity = a.velocity - b.velocity; final velocityAlongNormal = relativeVelocity.dot(normal); // 确保物体在分离 if (velocityAlongNormal > 0) return; // 恢复系数 const restitution = 0.8; var impulseScalar = -(1 + restitution) * velocityAlongNormal; impulseScalar /= 1 / a.mass + 1 / b.mass; final impulse = normal * impulseScalar; if (!a.isStatic) { a.velocity += impulse / a.mass; } if (!b.isStatic) { b.velocity -= impulse / b.mass; } } }

3.2 刚体物理

dart

// lib/physics/rigid_body.dart class RigidBody extends PhysicsBody { double rotation = 0; double angularVelocity = 0; double angularAcceleration = 0; double momentOfInertia = 1.0; List<Vector2> vertices = []; Vector2 center = Vector2.zero(); @override void update(double deltaTime) { super.update(deltaTime); // 更新旋转 angularVelocity += angularAcceleration * deltaTime; rotation += angularVelocity * deltaTime; // 重置角加速度 angularAcceleration = 0; } void applyTorque(double torque) { angularAcceleration += torque / momentOfInertia; } void applyForceAtPoint(Vector2 force, Vector2 point) { applyForce(force); // 计算力矩 final r = point - center; final torque = r.x * force.y - r.y * force.x; applyTorque(torque); } List<Vector2> getTransformedVertices() { final transformed = <Vector2>[]; for (final vertex in vertices) { // 旋转 final cosTheta = cos(rotation); final sinTheta = sin(rotation); final x = vertex.x * cosTheta - vertex.y * sinTheta; final y = vertex.x * sinTheta + vertex.y * cosTheta; // 平移 transformed.add(Vector2(x + position.x, y + position.y)); } return transformed; } }

📱 四、触摸交互游戏

4.1 简单游戏示例:弹跳球

dart

// lib/games/bouncing_ball.dart import 'package:flutter/material.dart'; class BouncingBallGame extends StatefulWidget { const BouncingBallGame({super.key}); @override State<BouncingBallGame> createState() => _BouncingBallGameState(); } class _BouncingBallGameState extends State<BouncingBallGame> with SingleTickerProviderStateMixin { late GameLoop _gameLoop; late GameWorld _world; Offset _ballPosition = const Offset(100, 100); Offset _ballVelocity = const Offset(200, 300); final double _ballRadius = 30; @override void initState() { super.initState(); _world = GameWorld(); _setupGame(); _gameLoop = GameLoop( onUpdate: _update, onRender: (canvas) { _render(canvas, Size.infinite); }, ); _gameLoop.start(); } void _setupGame() { // 创建游戏对象 _world.addObject(_createBall()); _world.addObject(_createPlatforms()); } GameObject _createBall() { return _Ball( position: _ballPosition, velocity: _ballVelocity, radius: _ballRadius, ); } GameObject _createPlatforms() { return _Platforms(); } void _update(double deltaTime) { _world.update(deltaTime); // 边界检查 final screenWidth = 400.0; final screenHeight = 800.0; if (_ballPosition.dx < _ballRadius || _ballPosition.dx > screenWidth - _ballRadius) { _ballVelocity = Offset(-_ballVelocity.dx, _ballVelocity.dy); } if (_ballPosition.dy < _ballRadius || _ballPosition.dy > screenHeight - _ballRadius) { _ballVelocity = Offset(_ballVelocity.dx, -_ballVelocity.dy); } // 更新位置 _ballPosition += _ballVelocity * deltaTime; setState(() {}); } void _render(Canvas canvas, Size size) { _world.render(canvas); } @override Widget build(BuildContext context) { return GestureDetector( onTapDown: (details) { // 点击时给球一个力 final tapPosition = details.localPosition; final direction = (tapPosition - _ballPosition).normalized(); _ballVelocity += direction * 100; }, child: CustomPaint( painter: _GamePainter( ballPosition: _ballPosition, ballRadius: _ballRadius, ), size: const Size(400, 800), ), ); } @override void dispose() { _gameLoop.stop(); super.dispose(); } } class _Ball extends GameObject { Offset velocity; double radius; _Ball({ required super.position, required this.velocity, required this.radius, }); @override void update(double deltaTime) { // 简单物理模拟 position += velocity * deltaTime; // 重力 velocity = Offset(velocity.dx, velocity.dy + 98 * deltaTime); // 摩擦力 velocity = Offset(velocity.dx * 0.99, velocity.dy); } @override void render(Canvas canvas) { final paint = Paint() ..color = Colors.blue ..style = PaintingStyle.fill; canvas.drawCircle(position, radius, paint); // 添加高光 final highlightPaint = Paint() ..color = Colors.white.withOpacity(0.3) ..style = PaintingStyle.fill; canvas.drawCircle( position - Offset(radius * 0.3, radius * 0.3), radius * 0.4, highlightPaint, ); } } class _Platforms extends GameObject { final List<Rect> platforms = [ const Rect.fromLTWH(50, 600, 300, 20), const Rect.fromLTWH(100, 400, 200, 20), const Rect.fromLTWH(150, 200, 100, 20), ]; @override void update(double deltaTime) {} @override void render(Canvas canvas) { final paint = Paint() ..color = Colors.green ..style = PaintingStyle.fill; for (final platform in platforms) { canvas.drawRect(platform, paint); // 添加纹理 final texturePaint = Paint() ..color = Colors.green.shade700 ..style = PaintingStyle.stroke ..strokeWidth = 2; for (double x = platform.left; x < platform.right; x += 10) { canvas.drawLine( Offset(x, platform.top), Offset(x, platform.bottom), texturePaint, ); } } } } class _GamePainter extends CustomPainter { final Offset ballPosition; final double ballRadius; const _GamePainter({ required this.ballPosition, required this.ballRadius, }); @override void paint(Canvas canvas, Size size) { // 绘制背景 final backgroundPaint = Paint() ..color = Colors.black ..style = PaintingStyle.fill; canvas.drawRect(Offset.zero & size, backgroundPaint); // 绘制网格 final gridPaint = Paint() ..color = Colors.grey.shade800 ..style = PaintingStyle.stroke ..strokeWidth = 1; for (double x = 0; x < size.width; x += 50) { canvas.drawLine(Offset(x, 0), Offset(x, size.height), gridPaint); } for (double y = 0; y < size.height; y += 50) { canvas.drawLine(Offset(0, y), Offset(size.width, y), gridPaint); } // 绘制球 final ballPaint = Paint() ..color = Colors.blue ..style = PaintingStyle.fill; canvas.drawCircle(ballPosition, ballRadius, ballPaint); // 绘制影子 final shadowPaint = Paint() ..color = Colors.blue.shade900.withOpacity(0.3) ..style = PaintingStyle.fill; canvas.drawOval( Rect.fromCenter( center: Offset(ballPosition.dx, ballPosition.dy + ballRadius * 0.5), width: ballRadius * 1.5, height: ballRadius * 0.5, ), shadowPaint, ); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => true; }

4.2 触摸控制示例

dart

// lib/games/touch_control_game.dart class TouchControlGame extends StatefulWidget { const TouchControlGame({super.key}); @override State<TouchControlGame> createState() => _TouchControlGameState(); } class _TouchControlGameState extends State<TouchControlGame> { final List<Offset> _touches = []; Offset _playerPosition = const Offset(200, 400); double _playerSpeed = 200; @override Widget build(BuildContext context) { return GestureDetector( onTapDown: (details) { setState(() { _touches.add(details.localPosition); }); }, onPanStart: (details) { setState(() { _touches.add(details.localPosition); }); }, onPanUpdate: (details) { setState(() { _touches.add(details.localPosition); }); }, onPanEnd: (details) { setState(() { _touches.clear(); }); }, child: CustomPaint( painter: _TouchGamePainter( touches: _touches, playerPosition: _playerPosition, ), size: MediaQuery.of(context).size, ), ); } } class _TouchGamePainter extends CustomPainter { final List<Offset> touches; final Offset playerPosition; const _TouchGamePainter({ required this.touches, required this.playerPosition, }); @override void paint(Canvas canvas, Size size) { // 绘制背景 final backgroundPaint = Paint() ..color = Colors.grey.shade900 ..style = PaintingStyle.fill; canvas.drawRect(Offset.zero & size, backgroundPaint); // 绘制触摸点 for (final touch in touches) { final touchPaint = Paint() ..color = Colors.blue.withOpacity(0.3) ..style = PaintingStyle.fill; canvas.drawCircle(touch, 20, touchPaint); final ringPaint = Paint() ..color = Colors.blue ..style = PaintingStyle.stroke ..strokeWidth = 2; canvas.drawCircle(touch, 25, ringPaint); } // 绘制玩家 final playerPaint = Paint() ..color = Colors.green ..style = PaintingStyle.fill; canvas.drawCircle(playerPosition, 30, playerPaint); // 绘制玩家方向 if (touches.isNotEmpty) { final lastTouch = touches.last; final directionPaint = Paint() ..color = Colors.yellow ..style = PaintingStyle.stroke ..strokeWidth = 3; canvas.drawLine(playerPosition, lastTouch, directionPaint); } } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => true; }

📊 总结

游戏开发要点:

  1. 游戏循环:帧率控制、时间管理

  2. 图形渲染:粒子系统、着色器、性能优化

  3. 物理引擎:碰撞检测、刚体物理、力模拟

  4. 触摸交互:手势识别、多点触控、游戏控制

性能优化技巧:

dart

// 游戏性能优化 class GameOptimizations { // 1. 对象池重用 static final List<Particle> _particlePool = []; static Particle getParticle() { if (_particlePool.isNotEmpty) { return _particlePool.removeLast()..life = 1.0; } return Particle(); // 创建新粒子 } static void recycleParticle(Particle particle) { _particlePool.add(particle); } // 2. 批量绘制 static void batchRender(List<Sprite> sprites, Canvas canvas) { for (final sprite in sprites) { // 使用相同材质的精灵可以批量绘制 sprite.render(canvas); } } // 3. 视锥体裁剪 static List<GameObject> frustumCulling( List<GameObject> objects, Rect viewport, ) { return objects.where((obj) { // 简单矩形相交测试 final objectBounds = Rect.fromCircle( center: obj.position, radius: 50, // 假设对象半径 ); return viewport.overlaps(objectBounds); }).toList(); } }

推荐库:

yaml

# pubspec.yaml dependencies: flame: ^1.10.0 # 2D游戏引擎 forge2d: ^0.10.0 # 物理引擎 vector_math: ^2.1.4 # 数学库

💡 提示:移动设备性能有限,注意控制粒子数量、纹理大小和物理计算复杂度。

欢迎大家加入[开源鸿蒙跨平台开发者社区](https://openharmonycrossplatform.csdn.net),一起共建开源鸿蒙跨平台生态。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/4 6:57:21

【Java毕设源码分享】基于springboot+vue的甘肃“印象”网站设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/2/4 8:50:34

【Java毕设源码分享】基于springboot+vue的高校“智慧党建”管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/2/3 0:14:04

57、Ubuntu开发工具与平台全解析

Ubuntu开发工具与平台全解析 1. Launchpad平台介绍 Launchpad是一个旨在简化软件开发过程中的沟通、协作和流程的基础设施,由支持Ubuntu社区的Canonical公司开发和维护。不过,它被众多软件项目所使用,其中不乏一些与Ubuntu社区无关的项目。这里是Ubuntu开发的核心场所。 …

作者头像 李华
网站建设 2026/2/3 1:07:41

OpenFeign 与 Spring Cloud LoadBalancer 源码深度解剖与实战全景

OpenFeign 与 Spring Cloud LoadBalancer 源码深度解剖与实战全景 在微服务架构中,服务调用是最核心的能力之一。Spring Cloud 体系里,OpenFeign 提供了声明式 HTTP 客户端,Spring Cloud LoadBalancer 提供了客户端负载均衡,它们协同工作,实现了 优雅、健壮、可扩展 的服…

作者头像 李华