HTML5-Canvas: Viết game Mario – Part 3

Html5-Mario Game - Welcome ScreenTiếp theo phần 1, phần 2, trong phần này ta sẽ thực hiện một bước quan trọng để game có thể hấp dẫn người chơi: tạo menu và giao diện.


Xem Demo.

Html5-Mario Game -part3

Tạo menu, màn hình hướng dẫn

Tuần trước, tôi đã viết một bài hướng dẫn Tạo menu và chuyển đổi giữa các màn hình Game theo yêu cầu của một bạn. Bây giờ là lúc áp dụng hướng dẫn đó vào ứng dụng cụ thể. Việc đầu tiên cần làm là nhét đống code trong file html vào một lớp mới (Game.js), như vậy ta có thể dễ dàng quản lý và mở rộng ứng dụng hơn:

function Game(canvas,context){
	var _map;
	var _player;
	var _keyStates = {};
	var _timer;
	var _images;
	function clear() {
		context.clearRect(0, 0, canvas.width, canvas.height);
	};
	this.init = function() {

		canvas.onkeydown = canvas_keyDown;
		canvas.onkeyup = canvas_keyUp;
		context.textAlign = "left";
		_map = new Map(canvas.width,canvas.height);

		this.newGame();
	};

	this.newGame = function(){
		_map.reset();
		_player = new Player(_map,0,100);
		draw();
		_timer = window.setInterval(update,1000/FPS);
	};

	// ...
}

Trong phần này, tôi cũng sử dụng lớp ImgLoader để nạp trước các hình ảnh. Khi ảnh được nạp xong, tôi tạo ra 2 màn hình game:
– Welcome Screen chứa các menu và tiêu đề, logo,… của game.
– Help Screen: hướng dẫn chơi chơi game.


var loader = new ImgLoader(sources,
	function(image,percent) {	// on progressing
		context.clearRect(0,0,canvas.width,canvas.height);
		context.fillText("Loading: "+percent+"%",canvas.width/2,canvas.height/2);
	},
	function(images){			// completed

		_images = loader.images;
		// create the help screen
		var helpScreen,welcomeScreen;
		helpScreen = new Screen(canvas);
		helpScreen.beforeDraw = function(context){
			context.drawImage(_images.helpscreen,0,0,canvas.width, canvas.height);
		};
		var cx = canvas.width/2;
		helpScreen.addItem(new MenuItem({
					left: cx-100,
					top: canvas.height-60,
					width: 200,
					height: 40,
					text: "Back",
					onclick: function(){
						// back to welcome screen
						helpScreen.stop();
						welcomeScreen.start();
					}
				}));

			// create the welcome screen
			welcomeScreen = new Screen(canvas,true);
			var titles = ["Play","Help","Visit My Blogs"];

			for(var i=0;i<titles.length;i++){
				welcomeScreen.addItem(new MenuItem({
					left: cx-100,
					top: 150+50*i,
					width: 200,
					height: 40,
					text: titles[i]
				}));
			}
			welcomeScreen.items[0].onclick = function(){
				welcomeScreen.stop();
				// start game
				new Game(canvas,context).init();
			};
			welcomeScreen.items[1].onclick = function(){
				welcomeScreen.stop();
				helpScreen.start();
			};
			welcomeScreen.items[2].onclick = function(){
				window.open('https://yinyangit.wordpress.com', '_blank');
			};
			welcomeScreen.start();
	}
);

Kết quả:

Html5-Mario Game - Welcome Screen

Thêm các sprite

Các phần trước tôi giữ cho ví dụ không sử dụng bất kì hình ảnh nào để tập trung vào phần chính. Mặc dù làm cho game nhìn có vẻ xấu và thiếu hấp dẫn nhưng đây là cách mà tôi hay sử dụng: nếu không còn muốn tiếp tục phát triển game đó, tôi sẽ không phải tiếc khoảng thời gian ngồi trau truốt giao diện của nó. Mặc dù game này vẫn chưa hoàn thành, nhưng tôi vẫn quyết định “khoác áo mới” cho nó để các phần của series này đỡ nhàm chán.

Trước tiên, bạn có thể cần tìm hiểu một chút về Animated Sprite được giới thiệu khá chi tiết và dễ hiểu bởi anh Nguyễn Tài Hải. Với ví dụ này, tôi sử dụng lớp AnimatedSprite mà tôi đã giới thiệu trước đây (xem) sau khi thay đổi một vài đặc điểm để phù hợp hơn với game.

Tiếp tục, tôi cho lớp Character thừa kế từ AnimatedSprite, và bổ sung thêm phương thức draw() cho lớp này, như vậy trong các lớp con của nó (Monster, Mushroom,…) ta không cần phải hiện thực phương thức draw() bởi vì tất cả đều giống nhau:

Character.prototype = new AnimatedSprite();
// ...
Character.prototype.draw = function(context){
	AnimatedSprite.prototype.draw.call(this,context,this.map.offsetX,this.map.offsetY);
}

Thiết lập sprite trong constructor:

function Character(map,options){

	if(!options)
		options = {};
	// ...

	if(options.spriteData){

		options.spriteData.left = this.left;
		options.spriteData.top = this.top;
		options.spriteData.width = this.width;
		options.spriteData.height = this.height;

		// Animated Sprite
		this.init(options.spriteData);
	}
}

Dựa vào sprite, tôi cũng có chia Monster thành 2 loại dựa vào thuộc tính canJump của nó. Monster nào có thuộc tính canJump = true sẽ có khả năng nhảy liên tục và mang hình dáng những con rùa có cánh. Một Character thường có nhiều sprite (mỗi sprite có nhiều frame) để phù hợp với từng tư thế và hướng di chuyển của chúng:

function Monster(map,left,top){
	// call the super-constructor
	Character.call(this,map,{
		left: left,
		top: top,
		speed: 1,
		isAutoMoving: true,
		canJump: Math.random()>0.3,
		spriteData: {
			image: _images.enemies,
			frameWidth: 29,
			frameHeight: 29,
			interval: 200,

		}
	});
	if(this.canJump)
	{
		this.addSprite({	// flying turtle
			name: "turtle_left",
			startFrame: 3,
			framesCount: 4,
			marginTop: 4,
			marginBottom: 10,
			marginRight: 8
		});
		this.addSprite({
			name: "turtle_right",
			startFrame: 7,
			framesCount: 4,
			marginTop: 4,
			marginBottom: 10,
			marginLeft: 6,
			marginRight: 8
		});
	}
	else
		this.addSprite({		// Goomba
			startFrame: 0,
			framesCount: 2,
			marginTop: 4,
			marginBottom: 13,
			marginRight: 10
		});
}

YinYangIt’s Blog

One thought on “HTML5-Canvas: Viết game Mario – Part 3

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