Html5 – Canvas: Viết game bắn đại bác – part3 (end)

Html5 - Canvas - Gun Game Demo - thumbTiếp theo phần 1 và 2, trong phần cuối này tôi sẽ thực hiện nốt những công việc cần thiết để game có thể chơi được bởi nhiều người, đồng thời “trang điểm” một chút để game thêm bắt mắt.

Sát thương của đạn

Mỗi khi đạn trúng đất hoặc bất kì cannon nào, nó sẽ phát nổ mà gây sát thương cho các cannon nằm trong phạm vi nhất định. Sức sát thương của đạn còn bị ảnh hưởng bởi tốc độ của nó khi trúng mục tiêu. Vậy tôi tạo một thuộc tính lưu trữ năng lượng của viên đạn khi đang bay dựa vào công thức động lượng (E = 1/2*m*v^2):

Ball.prototype.update = function(wind){
    this.speedY += GRAVITY+wind.y;
	this.speedX += wind.x;

	this.energy = (this.speedY*this.speedY+this.speedX*this.speedX); // E = 1/2*m*v^2
	if(this.energy<1)
		this.energy = 1;

	this.cx += this.speedX;
    this.cy += this.speedY;
    if(this.cx < this.minX || this.cx > this.maxX ||
        this.cy < this.minY || this.cy > this.maxY)
        return true;
    return false;
}

Lượng hp bị tổn thất của cannon khi trúng đạn sẽ được tính bằng tổng của động năng viên đạn và sát thương khi phát nổ. Lực khi phát nổ tôi sẽ cho giá trị từ 0 đến 100 với mọi phạm vi sát thương khác nhau của đạn. Với cách tính này, bạn có thể đảm bảo rằng khi sử dụng một loại đạn có phạm vi sát thương lớn thì mức độ sát thương của nó cũng chỉ tương đương với loại có phạm vi sát thương nhỏ hơn (cần phân biệt lực và phạm vi sát thương của đạn).

// calculate damage after the ball exploded
Cannon.prototype.calculateDamage = function(ball){
	if(this.isDeath)
		return 0;
	var dx = this.cx - ball.cx;
	var dy = this.cy - ball.cy;

	// distance between two center of ball and cannon
	var d =  Math.sqrt(dx*dx+dy*dy);

	if(d<=ball.damageRange){

		var hp_lost = Math.floor(ball.energy+(200-100*d/ball.damageRange));
		this.hp -= hp_lost;

		if(this.hp<=0)
		{
			this.hp = 0;
			this.isDeath = true;
		}
		return hp_lost;
	}
	return 0;
}

Sử dụng thanh sạc năng lượng khi bắn

Trong các phần trước, vì cảm thấy cách xác định lực bắn dựa vào khoảng cách click chuột khá bất tiện, nhất là với những xe nằm ở rìa bản đồ muốn bắn sang phần bị khuất. Vì vậy tôi thay thế bằng cách tạo một thanh năng lượng biểu diễn độ lớn của lực bắn.
Người chơi sử dụng bằng cách nhấn và giữ chuột trái cho đến khi thanh năng lượng này đạt đến mức cần thiết mà nhả chuột ra. Khi năng lượng đạt đến giá trị lớn nhất, bạn có thể cho nó giảm dần hoặc bắt đầu lại từ 1.

function canvas_mousedown(e){
	if(_alivePlayers==1)
		return;
	// use e.button in IE instead of e.which
	if(_ball.visible || _cannons[_currentPlayer].isFalling || e.which!=1) // left mouse button
		return;
	_firepower = 1; // start charging power
}
function canvas_mouseup(e){

	if(_alivePlayers>1 && !_ball.visible && _firepower>0)
	{
		_cannons[_currentPlayer].fire(_ball,_firepower/10);
		_firepower = 0;
	}
}
function update() {

	if(_firepower>0 && _firepower<MAX_FIREPOWER)
		_firepower++;
	//  ...
}

Hỗ trợ nhiều người chơi

Bởi vì game không chơi qua mạng nên nhiều người phải chia sẻ cùng một màn hình. Mỗi khi đạn phát nổ hoặc bay ra khỏi bản đồ, ta sẽ thực hiện chuyển lượt chơi đến người tiếp theo. Nếu như người chơi tiếp theo đã chết, tiếp tục gọi đệ quy với điều kiện dừng là số người chơi còn sống nhỏ hơn 1 (_alivePlayers<1).
Ngoài nhiệm vụ chính trên, phương thức changeTurn() dưới đây còn có nhiệm vụ hiển thị hiệu ứng nổ tại vị trí của viên đạn, bởi vì đây là thời điểm ngay sau khi nó phát nổ.

function changeTurn(showExplosion){

	if(_ball.visible)
	{
		_explosionSprite.setPostion(Math.floor(_ball.cx), Math.floor(_ball.cy), true);
		_ball.visible = false;
	}

	if(_alivePlayers<1)
		return;
	if(showExplosion && _explosionSprite)
		_explosionSprite.show();

	_currentPlayer++;
	if(_currentPlayer>=TOTAL_PLAYERS)
		_currentPlayer = 0;
	if(_cannons[_currentPlayer].isDeath)
		changeTurn();
}

Phương thức update()

Phương thức update() chính của game khá quan trọng. Mặc dù khá dài nhưng có thể tóm lại các bước hoạt động của nó đơn giản như sau:
– Kiểm tra xem đạn có phát nổ (trúng mặt đất hoặc cannon) hoặc bay ra khỏi bản đồ chưa.
– Nếu nó phát nổ thì cập nhật các cannon và kiểm tra mức độ thiệt hại mà chúng bị ảnh hưởng (bao gồm trạng thái sống/chết).
– Chuyển qua lượt của cannon kế tiếp nếu như đạn đã biến mất hoặc người chơi hiện tại đã chết.

function update() {

	if(_firepower>0 && _firepower<MAX_FIREPOWER)
		_firepower++;

	_map.update();

	var exploded;
	var endTurn;

	// check if the cannon-ball is exploded
	if(_ball.visible)
	{
		endTurn = _ball.update(_map.wind);

		if(!endTurn)
		{

			exploded =_map.collide(_ball);

			if(!exploded)
				for(var i=0;i<_cannons.length;i++)
				{
					exploded = _cannons[i].collide(_ball);
					if(exploded)
						break;
				}
		}
	}

	// update all cannons

	for(var i=0;i<_cannons.length;i++)
	{
		if(_cannons[i].isDeath)
		{
			_cannons[i].update();
			continue;
		}

		_cannons[i].update();

		if(exploded)
		{
			var hp_lost = _cannons[i].calculateDamage(_ball);
			if(hp_lost>0)
				log(_cannons[i].color,": -"+hp_lost+" HP.");
		}
		if(_cannons[i].isDeath)
		{
			_alivePlayers--;
			log(_cannons[i].color," died.");
		}
	}

	if(endTurn || exploded || _cannons[_currentPlayer].isDeath)
		changeTurn(exploded);

	if(_explosionSprite)
		_explosionSprite.update();

    draw();
}

Demo và Sourcecode

Download.

Screenshot:

Html5 - Canvas - Gun Game Demo 1

Html5 - Canvas - Gun Game Demo 2

YinYangIt’s Blog

11 thoughts on “Html5 – Canvas: Viết game bắn đại bác – part3 (end)

  1. Chào anh yingyang!
    em muốn vẽ đường đi của viên đạn sau mỗi lần bắn, cụ thể sau lần bắn thứ nhất sẽ vẽ đường đi của viên đạn thứ nhất, lần bắn thứ hai sẻ xóa đường đi của lần bắn thứ nhất và vẽ đường đi thứ hai.
    (giống như game angry bird vậy). Em đã làm nhưng chỉ vẽ được một đường thứ nhất thôi. Anh cho em hỏi là có cách nào để mình làm được điều này không anh.

    Trả lời
      • Em cũng đã làm như cách anh nói là vẽ lên một canvas phụ nhưng do vòng lặp của game sẽ xóa đối tượng context sau mỗi vòng lặp nên hiện tại em chưa biết giải quyết sao. Anh có thể hướng dẫn chi tiết giúp em được không.
        Em cảm ơn anh.

Gửi phản hồ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 Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s