import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bouncing Ball App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MainScreen(),
);
}
}
class MainScreen extends StatefulWidget {
const MainScreen({Key? key}) : super(key: key);
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
double _ballXPosition = 0; // X-axis position of the ball
double _ballYPosition = 0; // Y-axis position of the ball
double _ballXVelocity = 5; // X-axis velocity of the ball
double _ballYVelocity = 5; // Y-axis velocity of the ball
final double _ballDiameter = 50; // Ball size
final Random _random = Random();
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 16), // Frame duration
);
// Randomize initial direction for both X and Y velocities
_setRandomVelocity();
// Add listener for updating ball position
_controller.addListener(() {
setState(() {
_ballXPosition += _ballXVelocity;
_ballYPosition += _ballYVelocity;
// Get the container bounds
final containerWidth = 300 - _ballDiameter; // Container width minus ball
diameter
final containerHeight = 300 - _ballDiameter; // Container height minus ball
diameter
// Check for collisions with horizontal edges
if (_ballXPosition <= 0 || _ballXPosition >= containerWidth) {
_setRandomVelocity(); // Set a new random direction
_ballXPosition = _ballXPosition.clamp(0, containerWidth); // Keep ball
within bounds
}
// Check for collisions with vertical edges
if (_ballYPosition <= 0 || _ballYPosition >= containerHeight) {
_setRandomVelocity(); // Set a new random direction
_ballYPosition = _ballYPosition.clamp(0, containerHeight); // Keep ball
within bounds
}
});
});
}
// Function to set random velocity for bouncing in various directions
void _setRandomVelocity() {
double angle = _random.nextDouble() * 2 * pi; // Random angle in radians
// Increase the multiplier to make the ball faster
_ballXVelocity = 6 * cos(angle); // Random X velocity (faster)
_ballYVelocity = 6 * sin(angle); // Random Y velocity (faster)
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
// Method to start the animation
void _startAnimation() {
_controller.repeat();
}
// Method to stop the animation
void _stopAnimation() {
_controller.stop();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
elevation: 3,
title: const Text('Bouncing Ball App'),
),
body: Center(
child: Column(
children: <Widget>[
const SizedBox(
height: 50,
),
Container(
height: 300,
width: 300,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.black,
width: 5,
),
),
child: Stack(
children: [
Positioned(
top: _ballYPosition,
left: _ballXPosition,
child: Container(
height: _ballDiameter,
width: _ballDiameter,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(_ballDiameter / 2),
color: Colors.blue, // Ball color
),
),
),
],
),
),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FilledButton(
onPressed: _startAnimation,
child: const Text(
'Start',
style: TextStyle(
fontSize: 16,
),
),
),
FilledButton(
onPressed: _stopAnimation,
child: const Text(
'Stop',
style: TextStyle(
fontSize: 16,
),
),
),
],
),
],
),
),
);
}
}