LCOV - code coverage report
Current view: top level - lib/src/components - base_component.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 56 77 72.7 %
Date: 2021-08-10 15:50:53 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:ui';
       2             : 
       3             : import 'package:meta/meta.dart';
       4             : 
       5             : import '../../game.dart';
       6             : import '../../input.dart';
       7             : import '../effects/effects.dart';
       8             : import '../effects/effects_handler.dart';
       9             : import '../extensions/vector2.dart';
      10             : import '../text.dart';
      11             : import 'component.dart';
      12             : import 'component_set.dart';
      13             : import 'mixins/has_game_ref.dart';
      14             : 
      15             : /// This can be extended to represent a basic Component for your game.
      16             : ///
      17             : /// The difference between this and [Component] is that the [BaseComponent] can
      18             : /// have children, handle effects and can be used to see whether a position on
      19             : /// the screen is on your component, which is useful for handling gestures.
      20             : abstract class BaseComponent extends Component {
      21             :   final EffectsHandler _effectsHandler = EffectsHandler();
      22             : 
      23          48 :   late final ComponentSet children = createComponentSet();
      24             : 
      25             :   /// If the component has a parent it will be set here
      26             :   BaseComponent? _parent;
      27             : 
      28           7 :   @override
      29           7 :   BaseComponent? get parent => _parent;
      30             : 
      31             :   /// This is set by the BaseGame to tell this component to render additional
      32             :   /// debug information, like borders, coordinates, etc.
      33             :   /// This is very helpful while debugging. Set your BaseGame debugMode to true.
      34             :   /// You can also manually override this for certain components in order to
      35             :   /// identify issues.
      36             :   bool debugMode = false;
      37             : 
      38             :   Color debugColor = const Color(0xFFFF00FF);
      39             : 
      40           0 :   Paint get debugPaint => Paint()
      41           0 :     ..color = debugColor
      42           0 :     ..strokeWidth = 1
      43           0 :     ..style = PaintingStyle.stroke;
      44             : 
      45           0 :   TextPaint get debugTextPaint => TextPaint(
      46           0 :         config: TextPaintConfig(
      47           0 :           color: debugColor,
      48             :           fontSize: 12,
      49             :         ),
      50             :       );
      51             : 
      52          56 :   BaseComponent({int? priority}) : super(priority: priority);
      53             : 
      54             :   /// This method is called periodically by the game engine to request that your
      55             :   /// component updates itself.
      56             :   ///
      57             :   /// The time [dt] in seconds (with microseconds precision provided by Flutter)
      58             :   /// since the last update cycle.
      59             :   /// This time can vary according to hardware capacity, so make sure to update
      60             :   /// your state considering this.
      61             :   /// All components on [BaseGame] are always updated by the same amount. The
      62             :   /// time each one takes to update adds up to the next update cycle.
      63          20 :   @mustCallSuper
      64             :   @override
      65             :   void update(double dt) {
      66          40 :     children.updateComponentList();
      67          40 :     _effectsHandler.update(dt);
      68          44 :     children.forEach((c) => c.update(dt));
      69             :   }
      70             : 
      71           3 :   @mustCallSuper
      72             :   @override
      73             :   void render(Canvas canvas) {
      74           3 :     preRender(canvas);
      75             :   }
      76             : 
      77           3 :   @mustCallSuper
      78             :   @override
      79             :   void renderTree(Canvas canvas) {
      80           3 :     render(canvas);
      81           3 :     postRender(canvas);
      82           7 :     children.forEach((c) {
      83           1 :       canvas.save();
      84           1 :       c.renderTree(canvas);
      85           1 :       canvas.restore();
      86             :     });
      87             : 
      88             :     // Any debug rendering should be rendered on top of everything
      89           3 :     if (debugMode) {
      90           0 :       renderDebugMode(canvas);
      91             :     }
      92             :   }
      93             : 
      94             :   /// A render cycle callback that runs before the component and its children
      95             :   /// has been rendered.
      96           0 :   @protected
      97             :   void preRender(Canvas canvas) {}
      98             : 
      99             :   /// A render cycle callback that runs after the component has been
     100             :   /// rendered, but before any children has been rendered.
     101           3 :   void postRender(Canvas canvas) {}
     102             : 
     103           0 :   void renderDebugMode(Canvas canvas) {}
     104             : 
     105          23 :   @mustCallSuper
     106             :   @override
     107             :   void onGameResize(Vector2 gameSize) {
     108          23 :     super.onGameResize(gameSize);
     109          46 :     children.forEach((child) => child.onGameResize(gameSize));
     110             :   }
     111             : 
     112          20 :   @mustCallSuper
     113             :   @override
     114             :   void onMount() {
     115          20 :     super.onMount();
     116          40 :     children.forEach((child) => child.onMount());
     117             :   }
     118             : 
     119           5 :   @mustCallSuper
     120             :   @override
     121             :   void onRemove() {
     122           5 :     super.onRemove();
     123          10 :     children.forEach((child) => child.onRemove());
     124             :   }
     125             : 
     126             :   /// Called to check whether the point is to be counted as within the component
     127             :   /// It needs to be overridden to have any effect, like it is in
     128             :   /// PositionComponent.
     129           0 :   bool containsPoint(Vector2 point) => false;
     130             : 
     131             :   /// Add an effect to the component
     132           7 :   void addEffect(ComponentEffect effect) {
     133          14 :     _effectsHandler.add(effect, this);
     134             :   }
     135             : 
     136             :   /// Mark an effect for removal on the component
     137           0 :   void removeEffect(ComponentEffect effect) {
     138           0 :     _effectsHandler.removeEffect(effect);
     139             :   }
     140             : 
     141             :   /// Remove all effects
     142           0 :   void clearEffects() {
     143           0 :     _effectsHandler.clearEffects();
     144             :   }
     145             : 
     146             :   /// Get a list of non removed effects
     147          18 :   List<ComponentEffect> get effects => _effectsHandler.effects;
     148             : 
     149           4 :   void prepare(Component child, {Game? gameRef}) {
     150           4 :     if (this is HasGameRef) {
     151             :       final c = this as HasGameRef;
     152           4 :       gameRef ??= c.hasGameRef ? c.gameRef : null;
     153             :     } else if (gameRef == null) {
     154             :       assert(
     155           3 :         !isMounted,
     156             :         'Parent was already added to Game and has no HasGameRef; in this case, gameRef is mandatory.',
     157             :       );
     158             :     }
     159           4 :     if (gameRef is BaseGame) {
     160           3 :       gameRef.prepare(child);
     161             :     }
     162             : 
     163           4 :     if (child is BaseComponent) {
     164           4 :       child._parent = this;
     165           8 :       child.debugMode = debugMode;
     166             :     }
     167             :   }
     168             : 
     169             :   /// Uses the game passed in, or uses the game from [HasGameRef] otherwise,
     170             :   /// to prepare the child component before it is added to the list of children.
     171             :   /// Note that this component needs to be added to the game first if
     172             :   /// [this.gameRef] should be used to prepare the child.
     173             :   /// For children that don't need preparation from the game instance can
     174             :   /// disregard both the options given above.
     175           4 :   Future<void> addChild(Component child, {BaseGame? gameRef}) {
     176           8 :     return children.addChild(child, gameRef: gameRef);
     177             :   }
     178             : 
     179             :   /// Adds mutiple children.
     180             :   ///
     181             :   /// See [addChild] for details (or `children.addChildren()`).
     182           0 :   Future<void> addChildren(List<Component> cs, {BaseGame? gameRef}) {
     183           0 :     return children.addChildren(cs, gameRef: gameRef);
     184             :   }
     185             : 
     186             :   /// Removes a component from the component list, calling onRemove for it and
     187             :   /// its children.
     188           0 :   void removeChild(Component c) {
     189           0 :     children.remove(c);
     190             :   }
     191             : 
     192             :   /// Removes all the children in the list and calls onRemove for all of them
     193             :   /// and their children.
     194           0 :   void removeChildren(Iterable<Component> cs) {
     195           0 :     children.removeAll(cs);
     196             :   }
     197             : 
     198             :   /// Whether the children list contains the given component.
     199             :   ///
     200             :   /// This method uses reference equality.
     201           3 :   bool containsChild(Component c) => children.contains(c);
     202             : 
     203             :   /// Call this if any of this component's children priorities have changed
     204             :   /// at runtime.
     205             :   ///
     206             :   /// This will call `rebalanceAll` on the [children] ordered set.
     207           3 :   void reorderChildren() => children.rebalanceAll();
     208             : 
     209             :   /// This method first calls the passed handler on the leaves in the tree,
     210             :   /// the children without any children of their own.
     211             :   /// Then it continues through all other children. The propagation continues
     212             :   /// until the handler returns false, which means "do not continue", or when
     213             :   /// the handler has been called with all children
     214             :   ///
     215             :   /// This method is important to be used by the engine to propagate actions
     216             :   /// like rendering, taps, etc, but you can call it yourself if you need to
     217             :   /// apply an action to the whole component chain.
     218             :   /// It will only consider components of type T in the hierarchy,
     219             :   /// so use T = Component to target everything.
     220           4 :   bool propagateToChildren<T extends Component>(
     221             :     bool Function(T) handler,
     222             :   ) {
     223             :     var shouldContinue = true;
     224           5 :     for (final child in children) {
     225           1 :       if (child is BaseComponent) {
     226           1 :         shouldContinue = child.propagateToChildren(handler);
     227             :       }
     228           1 :       if (shouldContinue && child is T) {
     229           1 :         shouldContinue = handler(child);
     230             :       }
     231             :       if (!shouldContinue) {
     232             :         break;
     233             :       }
     234             :     }
     235             :     return shouldContinue;
     236             :   }
     237             : 
     238           4 :   @protected
     239             :   Vector2 eventPosition(PositionInfo info) {
     240          12 :     return isHud ? info.eventPosition.widget : info.eventPosition.game;
     241             :   }
     242             : 
     243          24 :   ComponentSet createComponentSet() {
     244          48 :     final components = ComponentSet.createDefault(prepare);
     245          24 :     if (this is HasGameRef) {
     246           5 :       components.register<HasGameRef>();
     247             :     }
     248             :     return components;
     249             :   }
     250             : }

Generated by: LCOV version 1.15