Thứ tư, ngày 7 tháng 12 năm 2016

Html5-Canvas: Viết game Mario – part 5 (end)

Ngày đăng: 12/7/2012, 8:32:17PM | Lượt xem: 4,796
Hot!

 Qua 1 tuần tìm hiểu về game này, đã đến lúc nên kết thúc để chuyển qua một đề tài khác. Vì vậy mặc dù còn rất nhiều điều cần làm để hoàn chỉnh game này, tôi sẽ kết thúc nó tại phần 5 này. Bạn có thể đọc lại các phần trước 1, 2, 3, 4 nếu như thấy thích tut này.

 Các cập nhật

 
- Thêm các ống nước và cây ăn thịt (Piranha Plant).
- Xác định số lượng, vị trí và thời điểm xuất hiện các monster.
Xem Demo

Thêm Piranha Plant

 
Cây ăn thịt là một loại monster đặc biệt có khả năng tiêu diệt người chơi bằng cách “núp lùm” và miễn dịch với chiêu “giẫm đạp” của mario.
Trong lớp này, ta định nghĩa hai khoảng thời gian mà cây sẽ duy trì trạng thái ngủ và thức. Thời gian ngủ sẽ lâu hơn thời gian thức nên 5 và 2 giây là một con số thích hợp.
function PiranhaPlant(map,left,top){
	// ...
	this.maxheight = this.height;
	this.isRaising = false;

	this.sleepDelay = 5000;	// sleep 5 seconds
	this.lastSleep = 0;

	this.awakeDelay = 2000;	// keep awake for 2 seconds
	this.lastAwake = 0;
	this.canDamage = true; // if it's sleeping, it won't be able to damage player
}
Trong phương thức update(), tôi cần phải thay đổi cả vị trí lẫn chiều cao của cây, do các monster sẽ được vẽ đè lên nền và như vậy không thể dùng các vật cản (ống nước) để giấu nó.
 
Ngoài ra, ta cần đảm bảo ảnh (sprite) không bị co lại khi kích thước giảm, tôi cũng phải thay đổi kích thước frame của sprite, bằng cách thay đổi trực tiếp giá trị marginBottom của currentSprite (thừa kế từ lớp AnimatedSprite). Tôi chưa tìm được cách tốt hơn nên tạm thời dùng cách này.
 
PiranhaPlant.prototype.update = function(){

	AnimatedSprite.prototype.update.call(this);

	var newTick = (new Date()).getTime();

	if(newTick-this.lastSleep<this.sleepDelay ||
		newTick-this.lastAwake<this.awakeDelay)
		return;

	this.canDamage = true;
	if(this.isRaising)
	{
		this.top--;
		this.height++;
		if(this.height==this.maxheight)
		{
			this.isRaising = false;
			this.lastAwake = newTick;
		}
	}
	else
	{
		this.top++;
		this.height--;
		if(this.height==0)
		{
			this.lastSleep = newTick;
			this.isRaising = true;
			this.canDamage = false;
		}
	}

	this.currentSprite.marginBottom = this.frameHeight-this.height;

}
 

Thêm các ống nước

 
Ống nước là một đặc trưng của game Mario (thợ sửa ống nước) nên đây là thành phần không thể thiếu. Tuy nhiên do kích thước của nó nên việc thêm vào bản đồ có một chút khác biệt. Chiều rộng của ống nước chiếm 2 ô (gấp đôi các vật cản khác) và chiều cao không xác định. Trong dữ liệu bản đồ, ta vẫn thiết lập tương tự như các vật cản khác. Khi vẽ ta chỉ cần vẽ cột đầu tiên của phần dữ liệu ống nước và với chiều rộng gấp đôi.
 
Để vẽ ống nước có chiều cao bất kì, ta cần sử dụng hai hình ảnh: 1 cho phần đầu và 1 cho phần thân. Chiều cao của phần đầu ống nước là cố định và chiều cao của thân thì có thể giãn ra bao nhiêu tùy ý.
 
Khi vẽ ra một đầu ống nước, ta cũng đồng thời thêm một PiranhaPlant vào tại vị trí đó. Như vậy mọi ống nước đều có một cây ăn thịt ẩn nấp:
// Map
// create map buffer
// ...
// i: col, j: row
else if(val==PIPE && data[(i-1)+j*COLS]!=PIPE)
{
	if(data[i+(j-1)*COLS]!=PIPE)
	{
		context.drawImage(_images.pipe_head,i*CELL_SIZE-5,j*CELL_SIZE,CELL_SIZE*2+10,CELL_SIZE);
		// add a piranha plant to this pipe
		var p = new PiranhaPlant(this, i*CELL_SIZE+HALF_SIZE,j*CELL_SIZE);
		p.top -= p.height;
		this.plants.push(p);
	}
	else
		context.drawImage(_images.pipe_body,i*CELL_SIZE,j*CELL_SIZE,CELL_SIZE*2,CELL_SIZE);
}
 

Thay đổi dữ liệu bản đồ

 
Dữ liệu bản đồ của mỗi level ngoài chứa cấu trúc của bản đồ thì còn chứa thêm các thông tin khác như số lượng monster, vị trí xuất hiện,… và tất nhiên có thể định nghĩa cả kích thước. Ví dụ:
 
var MAPS = [];
MAPS.push({
		// enemies Queue
		enemies: [
			{col: 20, row: 10},
			{col: 30, row: 10},
			{col: 40, row: 10},
			{col: 50, row: 10},
			{col: 60, row: 10},
			{col: 70, row: 10},
			{col: 80, row: 10},
			{col: 90, row: 10},
		],
		data: [
		0,0,0,0,0,0,0,....
		]
	});
 
Trong phương thức Map.update(), ta sẽ so sánh tọa độ của khung nhìn hiện tại với tọa độ của các enemies/monster được định nghĩa trong dữ liệu bản đồ bên trên. Các tọa độ cần được sắp xếp tăng dần theo thuộc tính col như vậy ta chỉ cần kiểm tra lần lượt từng phần tử.
// Map.update():
// check and add new monster from the enemiesQueue
var col = Math.floor((this.offsetX+this.viewWidth)/CELL_SIZE);
if(enemiesQueue.length>0 && enemiesQueue[0].col<=col)
{
	// remove the first enemy from queue
	var e = enemiesQueue.shift();
	// and add it to the monsters collection
	this.monsters.push(new Monster(this,e.col*CELL_SIZE,e.row*CELL_SIZE));
}
 
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.