Skip to content

Instantly share code, notes, and snippets.

@FantasyCheese
Last active September 23, 2020 15:33
Show Gist options
  • Save FantasyCheese/04142b1e7777543aa4f753a096733ca1 to your computer and use it in GitHub Desktop.
Save FantasyCheese/04142b1e7777543aa4f753a096733ca1 to your computer and use it in GitHub Desktop.
Pacman in Flutter
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:math';
const originalMap = [
[1,1,1,1,1,1,1,1,1,1,1,],
[1,0,0,0,0,0,0,0,0,0,1,],
[1,0,1,0,1,0,1,0,1,0,1,],
[1,0,1,0,1,1,1,0,1,0,1,],
[1,0,1,0,0,0,0,0,1,0,1,],
[1,0,1,0,1,0,1,0,1,0,1,],
[1,0,0,0,1,0,1,0,0,0,1,],
[1,1,1,1,1,0,1,1,1,1,1,],
[0,0,0,0,0,0,0,0,0,0,0,],
[1,1,1,1,1,0,1,1,1,1,1,],
[1,0,0,0,1,0,1,0,0,0,1,],
[1,0,1,0,1,0,1,0,1,0,1,],
[1,0,1,0,0,0,0,0,1,0,1,],
[1,0,1,0,1,1,1,0,1,0,1,],
[1,0,1,0,1,0,1,0,1,0,1,],
[1,0,0,0,0,0,0,0,0,0,1,],
[1,1,1,1,1,1,1,1,1,1,1,],
];
enum Direction { LEFT, UP, DOWN, RIGHT }
class Character {
Character(this.position);
Point position;
static Point _nextPosition(Point position, Direction direction) {
Point newPosition = position;
switch (direction) {
case Direction.UP: newPosition += Point(0, -1); break;
case Direction.DOWN: newPosition += Point(0, 1); break;
case Direction.LEFT: newPosition += Point(-1, 0); break;
case Direction.RIGHT: newPosition += Point(1, 0); break;
}
return newPosition;
}
bool tryMove(List<List<int>> map, Direction direction) {
final nextPosition = _nextPosition(position, direction);
if (map[nextPosition.y][nextPosition.x] == 1)
return false;
position = nextPosition;
return true;
}
}
class Pacman extends Character {
Pacman(Point position) : super(position);
Direction facing = Direction.RIGHT;
@override
bool tryMove(List<List<int>> map, Direction direction) {
final moved = super.tryMove(map, direction);
if (moved) {
facing = direction;
map[position.y][position.x] = -1;
}
return moved;
}
}
class Ghost extends Character {
Ghost(Point position) : super(position);
Direction heading = Direction.UP;
void move(List<List<int>> map) {
while (!tryMove(map, heading)) {
heading = Direction.values[Random().nextInt(3)];
}
}
}
void main() {
runApp(MaterialApp(
home: PacManScreen(),
));
}
class PacManScreen extends StatefulWidget {
@override
_PacManScreenState createState() => _PacManScreenState();
}
class _PacManScreenState extends State<PacManScreen> {
Pacman pacman;
List<Ghost> ghosts;
List<List<int>> currentMap;
Timer timer;
bool gameOver;
@override
void initState() {
super.initState();
_startGame();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Column(
children: [
Expanded(child: Container(
color: Colors.black,
child: _buildGameDisplay(),
)),
_buildGameInfo(),
_buildGameControl(),
],
),
);
}
void _startGame() {
setState(() {
gameOver = false;
pacman = Pacman(Point(1, 1));
ghosts = [
Ghost(Point(7,1)),
Ghost(Point(1, 15)),
Ghost(Point(9, 13)),
];
currentMap = List.generate(originalMap.length, (i) => List.from(originalMap[i]));
timer?.cancel();
timer = Timer.periodic(Duration(seconds: 1), (timer) {
setState(() {
ghosts.forEach((it) => it.move(currentMap));
_checkGameOver();
});
});
});
}
void _checkGameOver() {
gameOver = ghosts.any((it) => it.position == pacman.position);
if (gameOver) timer.cancel();
}
Row _buildGameInfo() {
final score = currentMap.map((row) => row.where((it) => it == -1).length).fold(0, (a, b) => a+b);
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FlatButton(
child: Text("START"),
onPressed: () => _startGame(),
color: Colors.green,
),
Text("SCORE: $score"),
],
);
}
Row _buildGameControl() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: Direction.values.map(_buildKey).toList(),
);
}
Widget _buildKey(Direction direction) {
IconData icon;
switch(direction) {
case Direction.RIGHT: icon = Icons.arrow_forward; break;
case Direction.LEFT: icon = Icons.arrow_back; break;
case Direction.UP: icon = Icons.arrow_upward; break;
case Direction.DOWN: icon = Icons.arrow_downward; break;
}
return GestureDetector(
onTap: () {
if (gameOver) return;
setState(() {
pacman.tryMove(currentMap, direction);
_checkGameOver();
});
},
child: Padding(
padding: EdgeInsets.all(8),
child: Icon(icon),
),
);
}
Widget _buildGameDisplay() {
if (gameOver) {
return Center(child: Text("GAME OVER!", style: TextStyle(color: Colors.red)));
}
final rows = currentMap.length;
final columns = currentMap[0].length;
return GridView.count(
crossAxisCount: columns,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
childAspectRatio: 1.1,
children: List.generate(rows * columns, (index) {
final position = Point(index % columns, index ~/ columns);
final cellValue = currentMap[position.y][position.x];
return _buildCell(position, cellValue);
}),
);
}
Widget _buildCell(Point<int> position, int cell) {
if (ghosts.any((ghost) => ghost.position == position)) {
return Image.network("https://i.imgur.com/1uneU2Q.png");
}
if (pacman.position == position) {
return RotatedBox(
quarterTurns: [Direction.RIGHT, Direction.DOWN, Direction.LEFT, Direction.UP,].indexOf(pacman.facing),
child: Image.network("https://i.imgur.com/8foCiWg.png"),
);
}
switch (cell) {
case -1: return Container();
case 0: return Padding(
padding: const EdgeInsets.all(12.0),
child: Container(
decoration: BoxDecoration(
color: Colors.yellow,
borderRadius: BorderRadius.circular(16),
),
),
);
case 1: return Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8)
),
);
}
return Container();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment