Files
labirynt/lib/main.dart
2026-02-07 10:20:50 +01:00

210 lines
6.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'maze.dart';
import 'player.dart';
import 'raycaster.dart';
void main() {
runApp(const LabiryntApp());
}
class LabiryntApp extends StatelessWidget {
const LabiryntApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Labirynt 3D',
theme: ThemeData.dark(),
home: const GameScreen(),
);
}
}
class GameScreen extends StatefulWidget {
const GameScreen({super.key});
@override
State<GameScreen> createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> with SingleTickerProviderStateMixin {
late Maze maze;
late Player player;
late AnimationController _controller;
final Set<LogicalKeyboardKey> _pressedKeys = {};
bool _won = false;
int _mazeSize = 15;
@override
void initState() {
super.initState();
_initGame();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
)..addListener(_gameLoop);
_controller.repeat();
}
void _initGame() {
if (_mazeSize.isEven) _mazeSize++;
maze = Maze(_mazeSize, _mazeSize);
player = Player(x: 1.5, y: 1.5);
_won = false;
}
void _gameLoop() {
if (_won) return;
setState(() {
if (_pressedKeys.contains(LogicalKeyboardKey.keyW) ||
_pressedKeys.contains(LogicalKeyboardKey.arrowUp)) {
player.moveForward(maze);
}
if (_pressedKeys.contains(LogicalKeyboardKey.keyS) ||
_pressedKeys.contains(LogicalKeyboardKey.arrowDown)) {
player.moveBackward(maze);
}
if (_pressedKeys.contains(LogicalKeyboardKey.keyA)) {
player.strafeLeft(maze);
}
if (_pressedKeys.contains(LogicalKeyboardKey.keyD)) {
player.strafeRight(maze);
}
if (_pressedKeys.contains(LogicalKeyboardKey.arrowLeft)) {
player.rotateLeft();
}
if (_pressedKeys.contains(LogicalKeyboardKey.arrowRight)) {
player.rotateRight();
}
if (maze.isGoal(player.x, player.y)) {
_won = true;
}
});
}
void _newGame() {
setState(() {
_mazeSize += 2;
if (_mazeSize > 31) _mazeSize = 15;
_initGame();
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: KeyboardListener(
focusNode: FocusNode()..requestFocus(),
autofocus: true,
onKeyEvent: (event) {
if (event is KeyDownEvent) {
_pressedKeys.add(event.logicalKey);
} else if (event is KeyUpEvent) {
_pressedKeys.remove(event.logicalKey);
}
},
child: Stack(
children: [
CustomPaint(
painter: RaycasterPainter(maze: maze, player: player),
size: Size.infinite,
),
Positioned(
bottom: 16,
left: 16,
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'WASD / Strzalki — ruch\nCel: zielony punkt na mapie',
style: TextStyle(color: Colors.white70, fontSize: 14),
),
),
),
Positioned(
bottom: 16,
right: 16,
child: Column(
children: [
_controlButton(Icons.arrow_upward, () => player.moveForward(maze)),
Row(
mainAxisSize: MainAxisSize.min,
children: [
_controlButton(Icons.rotate_left, () => player.rotateLeft()),
const SizedBox(width: 8),
_controlButton(Icons.rotate_right, () => player.rotateRight()),
],
),
_controlButton(Icons.arrow_downward, () => player.moveBackward(maze)),
],
),
),
if (_won)
Container(
color: Colors.black87,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'WYGRANA!',
style: TextStyle(
color: Colors.greenAccent,
fontSize: 64,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 24),
Text(
'Labirynt ${_mazeSize}x$_mazeSize ukonczony',
style: const TextStyle(color: Colors.white70, fontSize: 24),
),
const SizedBox(height: 32),
ElevatedButton(
onPressed: _newGame,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
),
child: const Text('Nastepny poziom', style: TextStyle(fontSize: 20)),
),
],
),
),
),
],
),
),
);
}
Widget _controlButton(IconData icon, VoidCallback onPressed) {
return Padding(
padding: const EdgeInsets.all(2),
child: GestureDetector(
onTapDown: (_) => setState(onPressed),
child: Container(
width: 56,
height: 56,
decoration: BoxDecoration(
color: Colors.white24,
borderRadius: BorderRadius.circular(12),
),
child: Icon(icon, color: Colors.white70, size: 28),
),
),
);
}
}