【Flutter】ゲーム画面の端との衝突

import 'package:flutter/material.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/services.dart';
import 'package:flame/components.dart';
import 'package:flame/collisions.dart';
import 'dart:math';

void main() async {
  runApp(new MyApp());
}
class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Generated App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: const Color(0xFF2196f3),
        canvasColor: const Color(0xFFfafafa),
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
      ),
        body: GameWidget(game: SampleGame())
    );
  }
}

class SampleGame extends FlameGame with HasCollisionDetection, HasKeyboardHandlerComponents, HasTappableComponents {

  late final List<MySprite> _splayers;

  @override
  Color backgroundColor() => const Color(0xffCCCCFF);

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    add(ScreenHitbox());

    _splayers = <MySprite>[];
    for(var i = 0; i < 10; i++) {
      await add(MySprite());
    }
  }
}

class MySprite extends CircleComponent with CollisionCallbacks, HasGameRef<SampleGame> {
  var _size = 50.0;
  late Vector2 _delta;
  late Color _color;

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    final _rnd = Random();
    _color = Color.fromARGB(255,
      _rnd.nextInt(256),
      _rnd.nextInt(256),
      _rnd.nextInt(256));
    size = Vector2(_size, _size);
    final _loc = Vector2.random();
    _loc.x *= gameRef.canvasSize.x;
    _loc.y *= gameRef.canvasSize.y;
    position = _loc;
    _delta = Vector2.random() * 3.0;
    setColor(_color);
    CircleHitbox hitbox = CircleHitbox();
    add(hitbox);
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);
  }

  @override
  void update(double delta){
    super.update(delta);
    position += _delta * delta * 100;
  }

  @override
  void onCollision(Set<Vector2> points, PositionComponent other){
    if(other is ScreenHitbox) {
      if (position.x <= 0) {
        _delta.x = _delta.x.abs();
      } if (position.x >= other.width - _size) {
        _delta.x = -_delta.abs();
      }
      if (position.y <= 0) {
        _delta.y = _delta.y.abs();
      } if (position.y >= other.height - _size) {
        _delta.y = -_delta.y.abs();
      }
    } else {
      setColor(Colors.yellow);
    }
  }

  @override
  void onCollisionEnd(PositionComponent other) {
    setColor(_color);
  }
}
import 'package:flame/collisions.dart';
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/experimental.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  runApp(new MyApp());
}
class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Generated App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: const Color(0xFF2196f3),
        canvasColor: const Color(0xFFfafafa),
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
      ),
        body: GameWidget(game: SampleGame())
    );
  }
}

class SampleGame extends FlameGame with HasCollisionDetection, HasKeyboardHandlerComponents {

  late final List<BlockSprite> _blocks;
  bool _flag = true;
  final List<Color> colors = [
    Colors.red,
    Colors.orange,
    Colors.yellow,
    Colors.green,
    Colors.cyan,
    Colors.blue,
    Colors.purple,
  ];

  @override
  Color backgroundColor() => const Color(0xffCCCCFF);

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    add(ScreenHitbox());
    final _size = Vector2((size.x - 10) / 5 - 10, 25);
    _blocks = <BlockSprite>[];
    for(var i = 0; i < 7; i++){
      for(var j = 0; j < 5; j++){
        var sp = await BlockSprite(_size,
          Vector2(j * (_size.x + 10) + 10, 30 * i + 50),
          colors[i]);
        _blocks.add(sp);
        add(sp);
      }
    }
    await(await BallSprite());
    await add(BarSprite());
  }

  void gameOver(){
    _flag = false;
    add(TextSprite("FINISHED."));
  }
}

class BallSprite extends CircleComponent with CollisionCallbacks, HasGameRef<SampleGame> {
  var _size = 25.0;
  late Vector2 _delta;

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    size = Vector2(_size, _size);
    final _loc = Vector2(
      gameRef.canvasSize.x / 2 - 12,
      gameRef.canvasSize.y - 100);
    position = _loc;
    _delta = Vector2(1, -1);
    setColor(Colors.white);
    add(CircleHitbox());
  }

  @override
  void update(double delta) {
    if (!gameRef._flag) {return;}
    super.update(delta);
    position += _delta * delta * 100;
  }

  @override
  void onCollision(Set<Vector2> points,
      PositionComponent other) {
    if (!gameRef._flag) { return; }
    if (other is ScreenHitbox) {
      if(position.x <= 0) {
        _delta.x = _delta.x.abs();
      } if (position.x > other.width - _size) {
        _delta.x = -_delta.x.abs();
      }
      if(position.y <= 0) {
        _delta.y = _delta.y.abs();
      } if (position.y >= other.height - _size) {
        _delta.y = -_delta.y.abs();
        gameRef.gameOver();
      }
    }
    if(other is BlockSprite) {
      if (position.x + size.x / 2 < other.position.x) {
        _delta.x = _delta.x.abs();
      } if (position.x + size.x / 2 > other.position.x + other.width) {
        _delta.x = _delta.x.abs();
      }
      if (position.y + size.y / 2  < other.position.y) {
        _delta.y = -_delta.y.abs();
      }
      if(position.y + size.y / 2 > other.position.y + other.height) {
        _delta.y = _delta.y.abs();
      }
    }
    if (other is BarSprite) {
      if (position.x + size.x / 2 < other.position.x) {
        _delta.x = _delta.x.abs();
      } if (position.x + size.x / 2 > other.position.x + other.width) {
        _delta.x = _delta.x.abs();
      }
      if (position.y + size.y / 2 < other.position.y) {
        _delta.y = -_delta.y.abs();
        final d = ((other.position.x + other.width / 2) - (position.x + size.x / 2));
        final p = (other.width / 5).floor();
        _delta.x -= (d/p);
        _delta.x = _delta.x > 3 ? 3 : _delta.x;
        _delta.y = -(5/ (gameRef._blocks.length/5).ceil() + 1);
      }
      if (position.y + size.y / 2 > other.position.y + other.height) {
        _delta.y = _delta.y.abs();
    }
    }
  }
}

class BlockSprite extends PositionComponent with CollisionCallbacks, HasGameRef<SampleGame> {
  late Vector2 _position;
  late Vector2 _size;
  late Paint _paint;
  late Color _color;

  BlockSprite(this._size, this._position, this._color): super();

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    position = _position;
    size = _size;
    _paint = Paint()
      ..style = PaintingStyle.fill
      ..color = _color;
    add(RectangleHitbox());
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);
    final r = Rect.fromLTWH(0, 0, _size.x, _size.y);
    canvas.drawRect(r, _paint);
  }

  @override
  void onCollisionEnd(PositionComponent other) {
    if(!gameRef._flag) { return ; }
    gameRef.remove(this);
    gameRef._blocks.remove(this);
    if (gameRef._blocks.length == 0) {
      gameRef.gameOver();
    }
  }
}

class BarSprite extends PositionComponent with CollisionCallbacks, KeyboardHandler, HasGameRef<SampleGame> {
  Vector2 _delta = Vector2.zero();
  late Paint _paint;

  BarSprite(): super();

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    size = Vector2(100, 25);
    position = Vector2(gameRef.canvasSize.x / 2 - 50, gameRef.canvasSize.y - 50);
    _paint = Paint()
      ..style = PaintingStyle.fill
      ..color = Colors.white;
    add(RectangleHitbox());
  }

  @override
  void update(double delta) {
    if (!gameRef._flag) { return; }
    position += _delta * delta * 100;
    super.update(delta);
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);
    final r = Rect.fromLTWH(0, 0, 100, 25);
    canvas.drawRect(r, _paint);
  }

  @override
  bool onKeyEvent(
      RawKeyEvent event,
      Set<LogicalKeyboardKey> keysPressed,
      ) {
    if(!gameRef._flag) { return false; }
    if (event is RawKeyUpEvent) {
      _delta = Vector2.zero();
    }
    if (event.character == 'j') {
      _delta.x = -3;
    }
    if (event.character == 'l') {
      _delta.x = 3;
    }
    return true;
  }
}

class TextSprite extends TextComponent with HasGameRef<SampleGame> {
  late String _message;

  TextSprite(this._message): super();

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    anchor = Anchor.center;
    position = Vector2(gameRef.canvasSize.x / 2,
     gameRef.canvasSize.y / 2);
    text = _message;
    textRenderer = TextPaint(
      style: TextStyle(
        fontSize: 60.0,
        fontWeight: FontWeight.w300,
        color: Colors.red,
      ),
    );
  }
}