flame_2022_visual_novel_tutorial icon indicating copy to clipboard operation
flame_2022_visual_novel_tutorial copied to clipboard

Instance of 'DialogButton' cannot be added to Instance of 'MyGame' because it already has a parent: Instance of 'MyGame'

Open 1gnoramus opened this issue 3 years ago • 6 comments

I tried to add buttons according to the YT video 'Add Tappable Buttons to Flame Flutter Games'. For some reasons i got an exception telling: "Another exception was thrown: Instance of 'DialogButton' cannot be added to Instance of 'MyGame' because it already has a parent: Instance of 'MyGame'" I tried ti find a solution in stackoverflow, but didn't get anything Could you help me please?

1gnoramus avatar Nov 26 '22 16:11 1gnoramus

import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/experimental.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:flame/flame.dart';

void main() {
  print('sad');
  runApp(
    GameWidget(
      game: MyGame(),
    ),
  );
}

class MyGame extends FlameGame with HasTappables {
  SpriteComponent queen = SpriteComponent();
  SpriteComponent knight = SpriteComponent();
  SpriteComponent background = SpriteComponent();
  DialogButton dialogButton = DialogButton();
  Vector2 buttonSize = Vector2(50.0, 50.0);

  final double characterSize = (200);
  bool turnAway = false;
  int dialogLevel = 0;

  TextPaint dialogTextPaint = TextPaint(style: const TextStyle(fontSize: 30));
  @override
  Future<void> onLoad() async {
    super.onLoad();

    final screenWidth = size[0];
    final screenHeight = size[1];
    final textBoxHeight = 100;
    add(
      background
        ..sprite = await loadSprite('background_1.jpg')
        ..size = Vector2(size[0], size[1] - textBoxHeight),
    );
    queen
      ..sprite = await loadSprite('queen.png')
      ..size = Vector2(characterSize, characterSize)
      ..anchor = Anchor.topCenter
      ..y = screenHeight - characterSize - textBoxHeight;

    add(queen);
    knight
      ..sprite = await loadSprite('knight.png')
      ..size = Vector2(characterSize, characterSize)
      ..y = screenHeight - characterSize - textBoxHeight
      ..x = screenWidth
      ..anchor = Anchor.topCenter
      ..flipHorizontally();
    add(knight);

    dialogButton
      ..sprite = await loadSprite('next_button.png')
      ..size = buttonSize
      ..position =
          Vector2(size[0] - buttonSize[0] - 10, size[1] - buttonSize[1] - 10);
  }

  @override
  void update(double dt) {
    super.update(dt);
    if (queen.x < size[0] / 2 - 100) {
      queen.x += 30 * dt;
      if (queen.x > 50 && dialogLevel == 0) {
        dialogLevel++;
      }
      if (queen.x > 150 && dialogLevel == 1) {
        dialogLevel++;
      }
    } else if (turnAway == false) {
      knight.flipHorizontally();
      turnAway = true;
      if (dialogLevel == 2) {
        dialogLevel++;
      }
    }
    if (knight.x > size[0] / 2 - 50) {
      knight.x -= 60 * dt;
    }
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);
    switch (dialogLevel) {
      case 1:
        dialogTextPaint.render(
            canvas, 'NOCHEAS: Hey! How are you?', Vector2(10, size[1] - 100));
        break;
      case 2:
        dialogTextPaint.render(canvas, 'MENOS: Yo. Couldn\'t be better. You?',
            Vector2(10, size[1] - 100));
        break;
      case 3:
        dialogTextPaint.render(
            canvas, 'NOCHEAS: Wo ye hao!', Vector2(10, size[1] - 100));
        add(dialogButton);
        break;
    }
    ;
  }
}

class DialogButton extends SpriteComponent with Tappable {
  @override
  bool onTapDown(TapDownInfo event) {
    try {
      print('next screen');
      return true;
    } catch (e) {
      print(e);
      return false;
    }
  }
}

1gnoramus avatar Nov 26 '22 16:11 1gnoramus

this is not a major issue though. The code still works. But i want to understand why this exception was thrown

1gnoramus avatar Nov 26 '22 16:11 1gnoramus

There's likely a bug in my code where the render method is adding multiple buttons to the game. The render method will loop through the code and attempt to add the button in through each iteration.

a better strategy is to add a new scene in with a button press and then delete the old scene with remove(). I'm working on another video series with a new strategy. This is another example. https://github.com/codetricity/galatrix_tutorial

codetricity avatar Dec 02 '22 04:12 codetricity

@1gnoramus you can add a check if the button is already mounted, before adding the dialog button to eliminate the assertion error

if (!dialogButton.isMounted) {
  add(dialogButton);
}

anidotnet avatar Dec 04 '22 11:12 anidotnet

There's likely a bug in my code where the render method is adding multiple buttons to the game. The render method will loop through the code and attempt to add the button in through each iteration.

a better strategy is to add a new scene in with a button press and then delete the old scene with remove(). I'm working on another video series with a new strategy. This is another example. https://github.com/codetricity/galatrix_tutorial

Thanks a lot for your help. I really appreciate your courses, and looking forward for the new ones. im watching videos in codeBakers rn and will try to help new people with such issues below in the comments. Some of the problems i've already solved

1gnoramus avatar Dec 05 '22 16:12 1gnoramus

@anidotnet nice idea about

if (!dialogButton.isMounted) {
  add(dialogButton);
}

I'll try that. Have a nice day!

codetricity avatar Dec 06 '22 21:12 codetricity