import 'dart:math'; import 'package:flame/components.dart'; import 'package:flame/events.dart'; import 'package:flame/extensions.dart'; import 'package:flame/game.dart'; import 'package:flame/palette.dart'; import 'package:flame/sprite.dart'; import 'package:flutter/material.dart'; class LookAtExample extends FlameGame { static const description = 'This example demonstrates how a component can be ' 'made to look at a specific target using the lookAt method. Tap anywhere ' 'to change the target point for both the choppers. ' 'It also shows how nativeAngle can be used to make the component ' 'oriented in the desired direction if the image is not facing the ' 'correct direction.'; LookAtExample() : super(world: _TapWorld()); late SpriteAnimationComponent _chopper1; late SpriteAnimationComponent _chopper2; @override Color backgroundColor() => const Color.fromARGB(255, 96, 145, 112); @override Future onLoad() async { final spriteSheet = SpriteSheet( image: await images.load('animations/chopper.png'), srcSize: Vector2.all(48), ); _spawnChoppers(spriteSheet); _spawnInfoText(); } void _spawnChoppers(SpriteSheet spriteSheet) { // Notice now the nativeAngle is set to pi because the chopper // is facing in down/south direction in the original image. world.add( _chopper1 = SpriteAnimationComponent( nativeAngle: pi, size: Vector2.all(128), anchor: Anchor.center, animation: spriteSheet.createAnimation(row: 0, stepTime: 0.05), ), ); // This chopper does not use correct nativeAngle, hence using // lookAt on it results in the sprite pointing in incorrect // direction visually. world.add( _chopper2 = SpriteAnimationComponent( size: Vector2.all(128), anchor: Anchor.center, animation: spriteSheet.createAnimation(row: 0, stepTime: 0.05), position: Vector2(0, 160), ), ); } // Just displays some information. No functional contribution to the example. void _spawnInfoText() { final shaded = TextPaint( style: TextStyle( color: BasicPalette.white.color, fontSize: 30.0, shadows: const [ Shadow(offset: Offset(1, 1), blurRadius: 1), ], ), ); world.add( TextComponent( text: 'nativeAngle = pi', textRenderer: shaded, anchor: Anchor.center, position: _chopper1.absolutePosition + Vector2(0, -70), ), ); world.add( TextComponent( text: 'nativeAngle = 0', textRenderer: shaded, anchor: Anchor.center, position: _chopper2.absolutePosition + Vector2(0, -70), ), ); } } class _TapWorld extends World with TapCallbacks { final CircleComponent _targetComponent = CircleComponent( radius: 5, anchor: Anchor.center, paint: BasicPalette.black.paint(), ); @override void onTapDown(TapDownEvent event) { if (!_targetComponent.isMounted) { add(_targetComponent); } _targetComponent.position = event.localPosition; final choppers = children.query(); for (final chopper in choppers) { chopper.lookAt(event.localPosition); } } }