Created
December 11, 2018 12:16
-
-
Save liposo/98d2d06f6f0df256fd8c5197d97f3dbd to your computer and use it in GitHub Desktop.
Snake Game in Dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="wrapper"> | |
<canvas id="canvas" width="450" height="450"></canvas> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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