Skip to content

Instantly share code, notes, and snippets.

@yashlamba
Created April 24, 2022 16:17
Show Gist options
  • Save yashlamba/7382e974f847b6361cf7159e6890a209 to your computer and use it in GitHub Desktop.
Save yashlamba/7382e974f847b6361cf7159e6890a209 to your computer and use it in GitHub Desktop.
Snake Game Complete
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const SnakeGame());
}
class SnakeGame extends StatelessWidget {
const SnakeGame({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: "Snake Game",
home: Center(
child: Game(),
),
);
}
}
class Snake {
List<Point<int>> snake = [const Point(0, 0)];
Point<int> direction = Constants.right;
Point<int> get head {
return snake[0];
}
bool didBiteItself() {
for (int i = 1; i < snake.length; i++) {
if (snake[i] == head) {
return true;
}
}
return false;
}
bool pointOnSnake(Point<int> point) {
for (Point body in snake) {
if (body == point) {
return true;
}
}
return false;
}
void update() {
// For moving in a direction, move all body parts to the location of the
// part before them
for (int i = snake.length - 1; i > 0; --i) {
snake[i] = snake[i - 1];
}
// Then update in the direction snake is moving
snake[0] = Point((head.x + direction.x) % 50, (head.y + direction.y) % 50);
}
void eatFood() {
// Since food is added to the end and snake would ultimately
// Update one position, save the last location and append it again.
var foodLoc = snake.last;
update();
snake.add(foodLoc);
}
}
class Constants {
// Canvas
static const double canvasSize = 500;
static const double blockSize = 10;
// Directions
static const up = Point(0, -1);
static const down = Point(0, 1);
static const right = Point(1, 0);
static const left = Point(-1, 0);
}
class Game extends StatefulWidget {
const Game({Key? key}) : super(key: key);
@override
State<Game> createState() => _GameState();
}
class _GameState extends State<Game> {
late Snake snake;
late Point<int> food;
Random random = Random();
@override
void initState() {
initGame();
Timer.periodic(const Duration(milliseconds: 50), (t) {
gameUpdate();
});
super.initState();
}
initGame() {
snake = Snake();
foodUpdate();
}
void gameUpdate() {
// update this
if (food == snake.head) {
snake.eatFood();
foodUpdate();
} else {
snake.update();
}
if (snake.didBiteItself()) {
initGame();
}
setState(() {});
}
void foodUpdate() {
do {
food = Point(random.nextInt(Constants.canvasSize ~/ Constants.blockSize),
random.nextInt(Constants.canvasSize ~/ Constants.blockSize));
} while (snake.pointOnSnake(food));
}
void keyHandler(RawKeyEvent event) {
if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
if (snake.direction != Constants.up) {
snake.direction = Constants.down;
}
} else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
if (snake.direction != Constants.down) {
snake.direction = Constants.up;
}
} else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
if (snake.direction != Constants.left) {
snake.direction = Constants.right;
}
} else if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
if (snake.direction != Constants.right) {
snake.direction = Constants.left;
}
}
}
@override
Widget build(BuildContext context) {
return RawKeyboardListener(
focusNode: FocusNode(),
onKey: keyHandler,
autofocus: true,
child: Container(
width: Constants.canvasSize,
height: Constants.canvasSize,
color: Colors.black,
child: Stack(
children: snake.snake // Update This
.map((e) => Positioned(
top: Constants.blockSize * e.y,
left: Constants.blockSize * e.x,
child: Container(
height: Constants.blockSize,
width: Constants.blockSize,
color: Colors.green,
),
))
.toList() +
[
Positioned(
top: Constants.blockSize * food.y,
left: Constants.blockSize * food.x,
child: Container(
height: Constants.blockSize,
width: Constants.blockSize,
color: Colors.red,
),
)
],
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment