Initial commit: labirynt 3D pseudo-raycasting game
This commit is contained in:
209
lib/main.dart
Normal file
209
lib/main.dart
Normal file
@@ -0,0 +1,209 @@
|
||||
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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user