Skip to content

Instantly share code, notes, and snippets.

@liposo
Created December 11, 2018 12:16
Show Gist options
  • Save liposo/98d2d06f6f0df256fd8c5197d97f3dbd to your computer and use it in GitHub Desktop.
Save liposo/98d2d06f6f0df256fd8c5197d97f3dbd to your computer and use it in GitHub Desktop.
Snake Game in Dart
<div id="wrapper">
<canvas id="canvas" width="450" height="450"></canvas>
</div>
import 'dart:html';
import 'dart:math';
import 'dart:collection';
import 'dart:async';
const int CELL_SIZE = 10;
CanvasElement canvas;
CanvasRenderingContext2D context2D;
Keyboard keyboard = new Keyboard();
void main() {
canvas = querySelector('#canvas');
context2D = canvas.getContext('2d');
new Game()..run();
}
void clear() {
//Use of Dart cascade operator to set both properties in a single statement
context2D
..fillStyle = "white"
..fillRect(0, 0, canvas.width, canvas.height);
}
void drawCell(Point coordinates, String color) {
context2D
..fillStyle = color
..strokeStyle = "white";
final int x = coordinates.x * CELL_SIZE;
final int y = coordinates.y * CELL_SIZE;
context2D
..fillRect(x, y, CELL_SIZE, CELL_SIZE)
..strokeRect(x, y, CELL_SIZE, CELL_SIZE);
}
class Game {
static const num GAME_SPEED = 50;
num _lastTimeStamp = 0;
int _rightEdgeX;
int _bottomEdgeY;
Snake _snake;
Point _food;
Game() {
_rightEdgeX = canvas.width ~/ CELL_SIZE;
_bottomEdgeY = canvas.height ~/ CELL_SIZE;
init();
}
Future run() async {
update(await window.animationFrame);
}
void update(num delta) {
final num diff = delta - _lastTimeStamp;
if (diff > GAME_SPEED) {
_lastTimeStamp = delta;
clear();
drawCell(_food, "blue");
_snake.update();
_checkCollisions();
}
run();
}
void init() {
_snake = new Snake();
_food = _randomPoint();
}
Point _randomPoint() {
Random random = new Random();
return new Point(random.nextInt(_rightEdgeX), random.nextInt(_bottomEdgeY));
}
void _checkCollisions() {
if (_snake.head == _food) {
_snake.grow();
_food = _randomPoint();
}
if (_snake.head.x <= -1 ||
_snake.head.x >= _rightEdgeX ||
_snake.head.y <= -1 ||
_snake.head.y >= _bottomEdgeY ||
_snake.checkBodyCollision()) {
init();
}
}
}
class Keyboard {
HashMap<int, num> _keys = new HashMap<int, num>();
Keyboard() {
window.onKeyDown.listen((KeyboardEvent event) {
_keys.putIfAbsent(event.keyCode, () => event.timeStamp);
});
window.onKeyUp.listen((KeyboardEvent event) {
_keys.remove(event.keyCode);
});
}
bool isPressed(int keyCode) => _keys.containsKey(keyCode);
}
class Snake {
static const Point LEFT = const Point(-1, 0);
static const Point RIGHT = const Point(1, 0);
static const Point UP = const Point(0, -1);
static const Point DOWN = const Point(0, 1);
static const int START_LENGTH = 6;
// coordinates of the snake body
List<Point> _body;
Point _direction = RIGHT;
Snake() {
int i = START_LENGTH - 1;
_body = new List<Point>.generate(
START_LENGTH, (int index) => new Point(i--, 0));
}
Point get head => _body.first;
void _checkInput() {
if (keyboard.isPressed(KeyCode.LEFT) && _direction != RIGHT) {
_direction = LEFT;
} else if (keyboard.isPressed(KeyCode.RIGHT) && _direction != LEFT) {
_direction = RIGHT;
} else if (keyboard.isPressed(KeyCode.UP) && _direction != DOWN) {
_direction = UP;
} else if (keyboard.isPressed(KeyCode.DOWN) && _direction != UP) {
_direction = DOWN;
}
}
void grow() {
//Add new head based on current direction
_body.insert(0, head + _direction);
}
void _move() {
//Add new head
grow();
//Remove tails
_body.removeLast();
}
void _draw() {
for (Point point in _body) {
drawCell(point, "green");
}
}
bool checkBodyCollision() {
for (Point point in _body.skip(1)) {
if (point == head) {
return true;
}
}
return false;
}
void update() {
_checkInput();
_move();
_draw();
}
}
html, body {
width: 100%;
height: 100%;
maring: 0;
padding: 0;
}
#wrapper {
width: 450px;
margin: auto;
border: solid thin black;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment