Html5-Canvas: Viết game Rắn Săn Mồi

snake-iconMột trong những game đơn giản mà tôi từng viết lúc bắt đầu học lập trình là Snake. Tôi đã viết lại trên nền javascript và đây có thể là một ví dụ tốt cho những ai mới bắt đầu học Html5-Canvas.

Xem Demo


Html5-canvas-snake-gameGame này khá đơn giản nên tôi chỉ chú thích trong code, bạn có thể comment bên dưới nếu có thắc mắc cần giải thích.

Sourcecode:

Game.js:

var CELL_SIZE = 10;
var FPS = 10	;
var WIDTH = 400;
var HEIGHT = 400;

function Game(canvas_id){
	var _pressedKey;
	var _cols = WIDTH/CELL_SIZE;
	var _rows = HEIGHT/CELL_SIZE;
	var _snake = new Snake(_cols,_rows);

	var _canvas = document.getElementById(canvas_id);
	var _context = _canvas.getContext('2d');
	_context.fillStyle = "black";

	var _food = {};
	var _running = false;
	var _timer;

	this.init = function() {
		_canvas.width = WIDTH;
		_canvas.height = HEIGHT;

		_canvas.onkeydown = function(e) {
			e.preventDefault();
			if(e.keyCode == 13) // Enter key
			{
				if(!_running)
					startGame();
			}
			else if(_running)
			{
				_pressedKey = e.keyCode;
			}
		};

		// draw the welcome screen
		_context.textAlign = "center";
		//_context.font = "36px Arial";
		//_context.fillText("Canvas Snake v1.0",WIDTH/2,HEIGHT/3);
		_context.font = "16px Arial";
		_context.fillText("Press Enter to Start",WIDTH/2,HEIGHT/2);

	}

	function startGame() {
		_pressedKey = null;
		clearInterval(_timer);
		_snake.init();
		createFood();
		_running = true;
		_timer = setInterval(update,1000/FPS);

	}

	function update() {
		if(!_running)
			return;

		_snake.handleKey(_pressedKey);
		var ret = _snake.update(_food);

		if(ret==1)
		{
			createFood();
		}else if(ret==2) {
			// end game
			_running = false;
			_context.save();
			_context.fillStyle = "rgba(0,0,0,0.2)";
			_context.fillRect(0,0,WIDTH,HEIGHT);
			_context.restore();
			_context.fillText("Press Enter to Restart",WIDTH/2,HEIGHT/2);
			return;
		}

		draw();
	}
	function draw(){

		_context.beginPath();
		_context.clearRect(0,0,WIDTH,HEIGHT);
		_context.fill();

		_snake.draw(_context);
		// draw food
		_context.beginPath();
		_context.arc((_food.x*CELL_SIZE)+CELL_SIZE/2, (_food.y*CELL_SIZE)+CELL_SIZE/2, CELL_SIZE/2, 0, Math.PI*2, false);
		_context.fill();
	}

	function createFood() {
		var x = Math.floor(Math.random()*_cols);
		var y;
		do {
			y = Math.floor(Math.random()*_rows);
		} while(_snake.collide(x, y));

		_food = {x: x, y: y};
	}

}

snake.js:

function Snake(mapCols,mapRows){

	// directions
	var LEFT = 0, UP = 1, RIGHT = 2, DOWN = 3;

	var direction; // moving direction
	var data; // snake's body

	// PROTOTYPES
	this.init = function(){
		var x = 3;
		var y = 0;
		data = [
            {x: x, y: y},
            {x: x-1, y: y},
            {x: x-2, y: y}
        ];
		direction = RIGHT;
	};
	this.handleKey = function(key){
		// 37: left, 38: up, 39: rigth, 40: down
		if(key >= 37 && key <=40)
		{
			var newdir = key - 37;
			if(Math.abs(direction-newdir)!=2) // can not turn to the opposite direction
				direction = newdir;
		}
	};
    this.draw = function(ctx) {
        for(var i = 0;i < data.length; i++)
            ctx.fillRect(data[i].x*CELL_SIZE, data[i].y*CELL_SIZE, CELL_SIZE, CELL_SIZE);
    };

    this.update = function(food){
		var x = data[0].x;
		var	y = data[0].y;

        switch(direction) {
            case LEFT:
                x--; break;
			case UP:
                y--; break;
            case RIGHT:
                x++; break;
            case DOWN:
                y++; break;
        }

		// eat food: return 1
		if(x == food.x && y == food.y)
		{
			data.unshift(food);
			return 1;
		}
		// collide: return 2
		if(this.collide(x,y))
			return 2;
		// snake move by
		// adding the head
		data.unshift({x:x, y:y});
		// and cutting the tail
        data.pop();
		// default: return 0
		return 0;
	};

	this.collide = function(x, y) {

        if(x < 0 || x > mapCols-1)
            return true;

        if(y < 0 || y > mapRows-1)
            return true;

        for(var i = 0; i<data.length; i++) {
            if(x == data[i].x && y == data[i].y)
                return true;
        }
        return false;
    }
}

demo.html:

<html>
  <head>
  <title></title>
	<script src="snake.js"></script>
	<script src="Game.js"></script>
    <script type='text/javascript'>
	window.onload = function()
	{
		var game = new Game("canvas");
		game.init();
	}
    </script>
  </head>

  <body>
	<canvas id="canvas" tabindex="0" style="margin:0px; border: 1px solid"> </canvas>
  </body>
</html>
Advertisements

7 thoughts on “Html5-Canvas: Viết game Rắn Săn Mồi

  1. Bạn cho mình hỏi hai cách khai báo _food = {} và _data = [] có ý nghĩa gì vậy? Mình mới bắt đầu tìm hiễu về javascript nên chưa hiễu ý nghĩa của nó. Theo mình được biết đó là khai báo mãng nhưng hai cách này khác nhau như thế nào và nên dùng trong trường hợp nào?

    Phản hồi

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s