mirror of
				https://github.com/flame-engine/flame.git
				synced 2025-10-31 17:06:50 +08:00 
			
		
		
		
	 5b67b8f14a
			
		
	
	5b67b8f14a
	
	
	
		
			
			Removed deprecations for 1.10.0 and fixes some small unreleased regressions found when going through the examples.
		
			
				
	
	
		
			192 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'dart:math';
 | |
| 
 | |
| import 'package:flame/collisions.dart';
 | |
| import 'package:flame/components.dart';
 | |
| import 'package:flame/events.dart';
 | |
| import 'package:flame/game.dart';
 | |
| import 'package:flame/geometry.dart';
 | |
| import 'package:flame/palette.dart';
 | |
| import 'package:flutter/material.dart';
 | |
| 
 | |
| class RaytraceExample extends FlameGame
 | |
|     with
 | |
|         HasCollisionDetection,
 | |
|         TapDetector,
 | |
|         MouseMovementDetector,
 | |
|         TapDetector {
 | |
|   static const description = '''
 | |
| In this example the raytrace functionality is showcased.
 | |
| Click to start sending out a ray which will bounce around to visualize how it
 | |
| works. If you move the mouse around the canvas, rays and their reflections will
 | |
| be moved rendered and if you click again some more objects that the rays can
 | |
| bounce on will appear.
 | |
|   ''';
 | |
| 
 | |
|   final _colorTween = ColorTween(
 | |
|     begin: Colors.amber.withOpacity(1.0),
 | |
|     end: Colors.lightBlueAccent.withOpacity(1.0),
 | |
|   );
 | |
|   final random = Random();
 | |
|   Ray2? ray;
 | |
|   Ray2? reflection;
 | |
|   Vector2? origin;
 | |
|   bool isOriginCasted = false;
 | |
|   Paint rayPaint = Paint();
 | |
|   final boxPaint = BasicPalette.gray.paint()
 | |
|     ..style = PaintingStyle.stroke
 | |
|     ..strokeWidth = 2.0;
 | |
| 
 | |
|   final List<Ray2> rays = [];
 | |
|   final List<RaycastResult<ShapeHitbox>> results = [];
 | |
| 
 | |
|   late Path path;
 | |
|   @override
 | |
|   Future<void> onLoad() async {
 | |
|     addAll([
 | |
|       ScreenHitbox(),
 | |
|       CircleComponent(
 | |
|         radius: min(canvasSize.x, canvasSize.y) / 2,
 | |
|         paint: boxPaint,
 | |
|         children: [CircleHitbox()],
 | |
|       ),
 | |
|     ]);
 | |
|   }
 | |
| 
 | |
|   bool isClicked = false;
 | |
|   final extraChildren = <Component>[];
 | |
|   @override
 | |
|   void onTap() {
 | |
|     if (!isClicked) {
 | |
|       isClicked = true;
 | |
|       return;
 | |
|     }
 | |
|     _timePassed = 0;
 | |
|     if (extraChildren.isEmpty) {
 | |
|       addAll(
 | |
|         extraChildren
 | |
|           ..addAll(
 | |
|             [
 | |
|               CircleComponent(
 | |
|                 position: Vector2(100, 100),
 | |
|                 radius: 50,
 | |
|                 paint: boxPaint,
 | |
|                 children: [CircleHitbox()],
 | |
|               ),
 | |
|               CircleComponent(
 | |
|                 position: Vector2(150, 500),
 | |
|                 radius: 50,
 | |
|                 paint: boxPaint,
 | |
|                 anchor: Anchor.center,
 | |
|                 children: [CircleHitbox()],
 | |
|               ),
 | |
|               CircleComponent(
 | |
|                 position: Vector2(150, 500),
 | |
|                 radius: 150,
 | |
|                 paint: boxPaint,
 | |
|                 anchor: Anchor.center,
 | |
|                 children: [CircleHitbox()],
 | |
|               ),
 | |
|               RectangleComponent(
 | |
|                 position: Vector2.all(300),
 | |
|                 size: Vector2.all(100),
 | |
|                 paint: boxPaint,
 | |
|                 children: [RectangleHitbox()],
 | |
|               ),
 | |
|               RectangleComponent(
 | |
|                 position: Vector2.all(500),
 | |
|                 size: Vector2(100, 200),
 | |
|                 paint: boxPaint,
 | |
|                 children: [RectangleHitbox()],
 | |
|               ),
 | |
|               CircleComponent(
 | |
|                 position: Vector2(650, 275),
 | |
|                 radius: 50,
 | |
|                 paint: boxPaint,
 | |
|                 anchor: Anchor.center,
 | |
|                 children: [CircleHitbox()],
 | |
|               ),
 | |
|               RectangleComponent(
 | |
|                 position: Vector2(550, 200),
 | |
|                 size: Vector2(200, 150),
 | |
|                 paint: boxPaint,
 | |
|                 children: [RectangleHitbox()],
 | |
|               ),
 | |
|               RectangleComponent(
 | |
|                 position: Vector2(350, 30),
 | |
|                 size: Vector2(200, 150),
 | |
|                 paint: boxPaint,
 | |
|                 angle: tau / 10,
 | |
|                 children: [RectangleHitbox()],
 | |
|               ),
 | |
|             ],
 | |
|           ),
 | |
|       );
 | |
|     } else {
 | |
|       removeAll(extraChildren);
 | |
|       extraChildren.clear();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void onMouseMove(PointerHoverInfo info) {
 | |
|     final origin = info.eventPosition.widget;
 | |
|     isOriginCasted = origin == this.origin;
 | |
|     this.origin = origin;
 | |
|   }
 | |
| 
 | |
|   final Ray2 _ray = Ray2.zero();
 | |
|   var _timePassed = 0.0;
 | |
| 
 | |
|   @override
 | |
|   void update(double dt) {
 | |
|     super.update(dt);
 | |
|     if (isClicked) {
 | |
|       _timePassed += dt;
 | |
|     }
 | |
|     rayPaint.color = _colorTween.transform(0.5 + (sin(_timePassed) / 2))!;
 | |
|     if (origin != null) {
 | |
|       _ray.origin.setFrom(origin!);
 | |
|       _ray.direction
 | |
|         ..setValues(1, 1)
 | |
|         ..normalize();
 | |
|       collisionDetection
 | |
|           .raytrace(
 | |
|             _ray,
 | |
|             maxDepth: min((_timePassed * 8).ceil(), 1000),
 | |
|             out: results,
 | |
|           )
 | |
|           .toList();
 | |
|       isOriginCasted = true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void render(Canvas canvas) {
 | |
|     super.render(canvas);
 | |
|     if (origin != null) {
 | |
|       renderResult(canvas, origin!, results, rayPaint);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void renderResult(
 | |
|     Canvas canvas,
 | |
|     Vector2 origin,
 | |
|     List<RaycastResult<ShapeHitbox>> results,
 | |
|     Paint paint,
 | |
|   ) {
 | |
|     var originOffset = origin.toOffset();
 | |
|     for (final result in results) {
 | |
|       if (!result.isActive) {
 | |
|         continue;
 | |
|       }
 | |
|       final intersectionPoint = result.intersectionPoint!.toOffset();
 | |
|       canvas.drawLine(
 | |
|         originOffset,
 | |
|         intersectionPoint,
 | |
|         paint,
 | |
|       );
 | |
|       originOffset = intersectionPoint;
 | |
|     }
 | |
|   }
 | |
| }
 |