Thứ bảy, ngày 3 tháng 12 năm 2016

Html5-Canvas: Viết game Tower Defense – part 1

Ngày đăng: 12/7/2012, 12:55:58AM | Lượt xem: 5,341
Hot!

 Tower Defender (tháp phòng thủ) là một thể loại game rất phổ biến và có sức hấp dẫn người chơi bởi có cách chơi đơn giản nhưng lại mang tính chiến thuật và đối kháng của nó. Hơn nữa mỗi game lại có thể khả năng sáng tạo và mở rộng linh hoạt để đem đến những tính năng hấp dẫn người chơi.

 Giới thiệu

 
Trong tut này, tôi sẽ hướng dẫn viết một nền tảng game Tower Defense để bạn có thể phát triển lên thành một sản phẩm mang tính đặc trưng của riêng mình.
 
“Mục tiêu của trò chơi tháp phòng thủ là cố gắng để ngăn chặn kẻ thù vượt qua bản đồ bằng cách xây dựng các tòa tháp bắn vào họ khi họ đi qua. Kẻ thù và tháp thường có đa dạng về khả năng, chi phí. Khi kẻ địch bị đánh bại, người chơi kiếm được tiền hoặc điểm, được sử dụng để mua hoặc nâng cấp tháp, hoặc nâng cấp các số tiền hoặc các điểm thu được, hoặc thậm chí nâng cấp để giảm thời gian nâng cấp.” (Wikipedia)
 
Mục đích của tôi là tạo ra một game có những đặc điểm sau:
- Hỗ trợ nhiều con đường, cũng như nhiều điểm bắt đầu và kết thúc.
- Các tower có thể thay đổi về tầm bắn, sát thương, tốc độ,… và có thể nâng cấp.
- Các tower có thể đặt tại vị trí bất kì được phép mà không cần phải đặt chính xác vào từng ô.
- …
 
Trong tut này, tôi rút kinh nghiệm và sẽ sử dụng lập trình theo hướng event để xác định trạng thái của các đối tượng. Ví dụ như khi enemy đến đích, nó sẽ kích hoạt một event là reachedTarget.

Xem Demo

Tạo Enemy

 

Trong game này, enemy có thể coi là một đối tượng AI nhưng cũng có thể là đối tượng đơn giản nhất bởi vì nó chỉ có khả năng “cắm đầu chạy” theo một con đường định sẵn. Vì vậy công việc của ta là chỉ cần “dẫn lỗi” để chúng đi lần lượt đến từng điểm trên con đường và đến đích.

Thuật toán rất đơn giản:

- Cho enemy xuất phát tại điểm đầu tiên của con đường.

- Lấy tọa độ điểm tiếp theo và tính toán góc xoay, hướng di chuyển và coi đó là một đích tạm thời.

- Di chuyển cho đến đích tạm thời và lặp lại bước trên cho đến điểm cuối cùng.

 

Ví dụ tôi có phương thức tính góc xoay và hướng di chuyển từ điểm hiện tại (preX, preY) của enemy đến điểm kế tiếp trên đường (lấy bằng chỉ số currentPoint) với hàm Math.atan2. Bạn có thể đọc về một ví dụ khác giới thiệu cách sử dụng hàm atan2 là Game xe tăng đơn giản.

function calcDirection(preX, preY){

	var dx = roadX[currentPoint] - preX;
	var dy = roadY[currentPoint] - preY;

	var angle = Math.atan2(dy, dx);
	speedX = Math.cos(angle) * speed;
	speedY = Math.sin(angle) * speed;

}; 

Để kiểm tra enemy chạm đích mới, ta cần tính toán khoảng cách từ tâm enemy đến điểm đó với một sai số EPSILON. Và khi đó, ta sẽ tính toán đích mới dựa vào phương thức calcuDirection() trên. Nếu enemy đến điểm cuối cùng nó sẽ kích hoạt một event là reachedTarget nếu như event này được định nghĩa.

this.update = function(){

	var x = roadX[currentPoint];
	var y = roadY[currentPoint];

	var cx = this.left + HALF_UNIT_SIZE;
	var cy = this.top + HALF_UNIT_SIZE;

	var dx = Math.abs(cx - x);
	var dy = Math.abs(cy - y);

	if(dx < EPSILON && dy < EPSILON)
	{
		if(currentPoint < roadX.length - 1)
		{
			currentPoint++;
			calcDirection(cx, cy);
		}
		// reached the last point
		else if (this.reachedTarget)
			this.reachedTarget(); // raise reachedTarget event
	}else
	{
		this.left += speedX;
		this.top += speedY;
	}
}; 

Tạo bản đồ

Với bản đồ đơn giản, tôi chỉ tạo một con đường duy nhất đi từ điểm đầu đến đích. Con đường này được chia thành hai mảng roadX, roadY theo tọa độ ngang và dọc. Mỗi phần tử của mảng là 1 điểm trên bản đồ để nối lại thành một con đường hoàn chỉnh. Với số lượng và vị trí các điểm không bị giới hạn, ta có thể tạo ra các con đường uốn khúc hoặc thẳng tắp bằng cách thêm/bớt các điểm.

Trong dữ liệu này, tôi cũng định nghĩa cả số lượng enemy của mỗi lượt trong map.

MAPS.push
	({
		numEnemies		: 10,

		roadX 	: [10,50,50,300,250,90,30,50,160,340,200,WIDTH],
		roadY 	: [10,30,50,70,110,100,200,300,220,140,340,HEIGHT],
	}); 

Để vẽ bản đồ, tôi tạo một canvas phụ làm buffer và vẽ lên đó. Ta cũng sẽ dùng buffer này để xác định xem một vị trí nào đó có thể được đặt tower hay không (dựa vào màu sắc).

this.buffer = document.createElement("canvas");
this.buffer.width = WIDTH;
this.buffer.height = HEIGHT;
this.context = this.buffer.getContext("2d");

// ...
// draw the road
this.context.strokeStyle = "white";
this.context.lineWidth = UNIT_SIZE*1.2;
this.context.lineJoin = "round";

this.context.beginPath();
this.context.moveTo(this.levelData.roadX[0],this.levelData.roadY[0]);
for(var i = 1;i < this.levelData.roadX.length; i++)
{
	this.context.lineTo(this.levelData.roadX[i],this.levelData.roadY[i]);
}
// ... 

Trong Map, khi tạo mới một enemy, ta sẽ đồng thời định nghĩa một function để xử lý event reachedTarget của nó:

Map.prototype.update = function(){

	var enemies = this.enemies;
	if(enemies.length < this.levelData.numEnemies)
	{
		var tick = (new Date()).getTime();
		if(tick - this.lastAddEnemy > this.addEnemyDelay)
		{
			this.lastAddEnemy = tick;
			var e = new Enemy(this.levelData.roadX, this.levelData.roadY);
			e.reachedTarget = function(){
				enemies.shift();
			};
			enemies.push(e);
		}
	}
	for(x in this.enemies)
		enemies[x].update();

}

 

YinYangIt’s Blog
 Chia sẻ qua: 
Hot!
Ý kiến bạn đọc

These items will be permanently deleted and cannot be recovered. Are you sure?

Gallery

image

Maecenas viverra rutrum pulvinar

Maecenas viverra rutrum pulvinar! Aenean vehicula nulla sit amet metus aliquam et malesuada risus aliquet. Vestibulum rhoncus, dolor sit amet venenatis porta, metus purus sagittis nisl, sodales volutpat elit lorem…

Read more

Text Links

Thiết kế logo chuyên nghiệp Insky
DAFABET
W88 w88b.com/dang-ky-tai-khoan-w88
W88
Copyright © 2011 - 2012 vietshare.vn by phamkhuong102@gmail.com doanhkisi2315@gmail.com. All rights reserved.