import 'dart:async'; import 'dart:math'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:pong/pong_menu.dart'; void main() { runApp(const PongGame()); } class PongGame extends StatelessWidget { const PongGame({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Pong Game', theme: ThemeData(scaffoldBackgroundColor: Color.fromARGB(255, 41, 38, 38)), home: const StartScreen(), ); } } class StartScreen extends StatelessWidget { const StartScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: GestureDetector( onTap: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) { return const GameScreen(); }, )); }, child: const Center( child: Text( 'Berühren um zu beginnen!', style: TextStyle( fontSize: 30, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), ); } } class GameScreen extends StatefulWidget { const GameScreen({super.key}); @override State createState() => _GameScreenState(); } @visibleForTesting class _GameScreenState extends State { final ballSize = 20.0; final racketWidth = 240.0; final racketHeight = 25.0; final racketBottomOffset = 100.0; final initialBallSpeed = 2.0; double ballX = 0; double ballY = 0; double ballSpeedX = 0; double ballSpeedY = 0; double racketX = 20; int score = 0; late Ticker ticker; final double ballSpeedMultiplier = 2; @override void initState() { super.initState(); startGame(); } @override void dispose() { super.dispose(); stopGame(); } void startGame() { final random = Random(); ballX = 0; ballY = 0; ballSpeedX = initialBallSpeed; ballSpeedY = initialBallSpeed; racketX = 200; score = 0; if (random.nextBool()) ballSpeedX = -ballSpeedX; if (random.nextBool()) ballSpeedY = -ballSpeedY; Future.delayed(const Duration(seconds: 1), () { ticker = Ticker((elapsed) { setState(() { moveBall(ballSpeedMultiplier); }); }); ticker.start(); }); } void stopGame() { ticker.dispose(); } void moveBall(double ballSPeedMultiplier) { ballX += ballSpeedX * ballSpeedMultiplier; ballY += ballSpeedY * ballSpeedMultiplier; final Size size = MediaQuery.of(context).size; if (ballX < 0 || ballX > size.width - ballSize) { ballSpeedX = -ballSpeedX; } if (ballY < 0) { ballSpeedY = -ballSpeedY; } // Was prüft diese if-Anweisung? if (ballY > size.height - ballSize - racketHeight - racketBottomOffset && ballX >= racketX && ballX <= racketX + racketWidth) { ballSpeedY = -ballSpeedY; } else if (ballY > size.height - ballSize) { debugPrint('Game over'); stopGame(); showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return PongMenu( title: 'Game over!', subTitle: 'Deine Punkte: $score', child: CupertinoButton( child: const Text('Nochmal Spielen'), onPressed: () { Navigator.of(context).pop(); startGame(); }, ), ); }, ); } } moveRacket(double x) { setState(() { racketX = x - racketWidth / 2; }); } @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ GestureDetector( onHorizontalDragUpdate: (details) { moveRacket(details.globalPosition.dx); }, child: CustomPaint( painter: PongGamePainter( racketHeight: racketHeight, racketWidth: racketWidth, racketX: racketX, racketBottomOffset: racketBottomOffset, ballSize: ballSize, ballX: ballX, ballY: ballY, ), size: Size.infinite, ), ), Center( child: Text( 'Punkte: $score', style: const TextStyle( fontSize: 30, fontWeight: FontWeight.bold, ), ), ), Positioned( top: 20, right: 20, child: IconButton( icon: const Icon( CupertinoIcons.pause, size: 30, ), onPressed: () { stopGame(); showDialog( context: context, builder: (context) { return PongMenu( title: 'Pause', subTitle: 'Deine Punkte: $score', child: CupertinoButton( onPressed: () {}, child: const Text('Weiter'), ), ); }); }, ), ) ], ), ); } } class PongGamePainter extends CustomPainter { final double ballSize; final double ballX; final double ballY; final double racketX; final double racketWidth; final double racketHeight; final double racketBottomOffset; PongGamePainter({ required this.ballSize, required this.ballX, required this.ballY, required this.racketX, required this.racketWidth, required this.racketHeight, required this.racketBottomOffset, }); @override void paint(Canvas canvas, Size size) { final racketPaint = Paint()..color = Colors.white; final ballPaint = Paint()..color = Colors.white; canvas.drawOval( Rect.fromLTWH(ballX, ballY, ballSize, ballSize), ballPaint, ); canvas.drawRect( Rect.fromLTWH( racketX, size.height - racketHeight - racketBottomOffset, racketWidth, racketHeight, ), racketPaint, ); } @override bool shouldRepaint(covariant PongGamePainter oldDelegate) { return ballX != oldDelegate.ballX || ballY != oldDelegate.ballY || racketX != oldDelegate.racketX; } }