Chủ nhật, ngày 4 tháng 12 năm 2016

HTML5 – Canvas 2D: Hiệu ứng bóng chuyển động và phản xạ – part 2

Ngày đăng: 18/4/2012, 8:26:50PM | Lượt xem: 1,114
Hot!

Tiếp theo phần trước, tôi sẽ thêm các chướng ngại vật hình chữ nhật vào canvas để tạo đường di chuyển của trái bóng. Các chướng ngại vật được tôi lấy từ bài: HTML5 – Chọn và di chuyển đối tượng trên Canvas.

HTML5 - Canvas - Bouncing ball 2Tiếp theo phần trước, tôi sẽ thêm các chướng ngại vật hình chữ nhật vào canvas để tạo đường di chuyển của trái bóng. Các chướng ngại vật được tôi lấy từ bài: HTML5 – Chọn và di chuyển đối tượng trên Canvas.

Xem Demo.

Phần quan trọng của ví dụ này nằm ở phương thức kiểm tra va chạm của trái bóng. Phương thức này sẽ duyệt qua tất cả các chướng ngại vật và kiểm tra khoảng cách của nó so với chướng ngại vật theo hai phương dọc và ngang.

Với ví dụ này, tôi kiểm tra va chạm ở mức rất đơn giản nên việc phản xạ của trái bóng chưa hoàn toàn chính xác. Tôi sẽ giới thiệu các kĩ thuật kiểm tra va chạm và di chuyển trong các bài viết sau.

Phương thức kiểm tra va chạm của lớp Ball:

Ball.prototype.checkCollision = function(shapes) {

	if(this.left <= 0 || this.right >= this.mapWidth) this.speedX = -this.speedX;
	if(this.top <= 0 || this.bottom >= this.mapHeight) this.speedY = -this.speedY;

	for(var i = 0; i < shapes.items.length ; i++){

		var item = shapes.items[i];
		var hCollision = false;
		var vCollision = false;

		if(	this.right >= item.left && this.left <= item.right &&  	// the ball is
			((this.cy < item.top && this.bottom >= item.top) ||		// on or
			(this.cy > item.bottom && this.top <= item.bottom)))	// under the rectangle
		{
			this.speedY = -this.speedY;
			vCollision = true;
		}

		if(this.bottom >= item.top && this.top <= item.bottom &&  	// the ball is in the
			((this.cx < item.left && this.right >= item.left) ||	// left or
			(this.cx > item.right && this.left <= item.right)))		// right side of the rectangle
		{
			this.speedX = -this.speedX;
			hCollision = true;
		}

		if(hCollision || vCollision)
			break;
	}

}

Minh họa:

HTML5 - Canvas - Bouncing ball 2

Mã nguồn hoàn chỉnh:

ball.js:

function Ball(mapWidth, mapHeight){
	this.mapWidth = mapWidth;
	this.mapHeight = mapHeight;
	this.radius = 20;
	this.speedX = 2;
	this.speedY = 2;

	this.cx = Math.floor(Math.random()*(this.mapWidth-2*this.radius)) + this.radius;
	this.cy = Math.floor(Math.random()*(this.mapHeight-2*this.radius)) + this.radius;
	this.positions = [];
	this.counter = 0;
}
Ball.prototype.draw = function(context){

	for(var i=0; i<this.positions.length; i++)
	{
		var pos = this.positions[i];
		context.beginPath();
		context.fillStyle = "rgba(255, 100, 100," + (i+1)/10 + ")";
		context.arc(pos.x,pos.y,this.radius,0,Math.PI*2,true);
		context.closePath();
		context.fill();
	}

	context.beginPath();
	context.fillStyle = "red";
	context.arc(this.cx,this.cy,this.radius,0,Math.PI*2,true);
	context.closePath();
	context.fill();
}
Ball.prototype.move = function(){
	this.cx += this.speedX;
	this.cy += this.speedY;

	this.left = this.cx - this.radius;
	this.top = this.cy - this.radius;
	this.right = this.cx + this.radius;
	this.bottom = this.cy + this.radius;

	this.counter++;
	if(this.counter == 10)
	{
		this.trace();
		this.counter = 0;
	}
}
Ball.prototype.trace = function(){
	var b = {
		x : this.cx,
		y : this.cy
	};

	this.positions.push(b);
	if(this.positions.length>10)
		this.positions.splice(0,1);
}
Ball.prototype.checkCollision = function(shapes) {

	if(this.left <= 0 || this.right >= this.mapWidth) this.speedX = -this.speedX;
	if(this.top <= 0 || this.bottom >= this.mapHeight) this.speedY = -this.speedY;

	for(var i = 0; i < shapes.items.length ; i++){

		var item = shapes.items[i];
		var hCollision = false;
		var vCollision = false;

		if(	this.right >= item.left && this.left <= item.right &&  	// the ball is
			((this.cy < item.top && this.bottom >= item.top) ||		// on or
			(this.cy > item.bottom && this.top <= item.bottom)))	// under the rectangle
		{
			this.speedY = -this.speedY;
			vCollision = true;
		}

		if(this.bottom >= item.top && this.top <= item.bottom &&  	// the ball is in the
			((this.cx < item.left && this.right >= item.left) ||	// left or
			(this.cx > item.right && this.left <= item.right)))		// right side of the rectangle
		{
			this.speedX = -this.speedX;
			hCollision = true;
		}

		if(hCollision || vCollision)
			break;
	}

}

rect.js:

function Rect(left,top,width,height) {
	this.width = width ? width : 100;
	this.height = height ? height : 100;

	this.left = left ? left : 100;
	this.top = top ? top : 100;
	this.cx = this.left + this.width/2;
	this.cy = this.top + this.height/2;
	this.right = this.left + this.width;
	this.bottom = this.top + this.height;
	this.isSelected = false;

}
Rect.prototype.contains = function(x,y){
	var right = this.left + this.width;
	var bottom = this.top + this.height;
	return x > this.left && x < right &&
		 y > this.top && y < bottom;
}
Rect.prototype.setPosition = function(x,y){
	this.left = x;
	this.top = y;

	this.right = this.left + this.width;
	this.bottom = this.top + this.height;

}
Rect.prototype.draw = function(context){
	context.fillStyle = "blue";
	context.fillRect(this.left,this.top,this.width,this.height);

}

shape_list.js:

function ShapeList(){
	this.items = [];
	this.selectedItem = null;
}

ShapeList.prototype.addItem = function(x,y){
	var rect = new Rect(x,y);

	this.items.push(rect);

}

ShapeList.prototype.selectAt = function(x,y){
	if(this.selectedItem)
		this.selectedItem.isSelected = false;
	this.selectedItem = null;
	for (var i = 0; i < this.items.length; i++) {
		var rect = this.items[i];
		if(rect.contains(x,y))
		{
			this.selectedItem = this.items[i];
			this.items[i].isSelected = true;
			break;
		}
    }
}

sample.html:

<html>
<head>

<script src="Ball.js"></script>
<script src="rect.js"></script>
<script src="shape_list.js"></script>
<script>

var _canvas;
var _context;
var _shapes = new ShapeList;
var _ismoving = false;
var _ball;
var _offsetX;
var _offsetY;
var _timer;

function canvas_mousedown(e){

	var x = e.pageX - _canvas.offsetLeft;
	var y = e.pageY - _canvas.offsetTop;

	_shapes.selectAt(x,y)

	if(!_shapes.selectedItem)
		_shapes.addItem(x,y);
	else
	{
		_offsetX = x- _shapes.selectedItem.left;
		_offsetY = y - _shapes.selectedItem.top;

		_ismoving = true;
	}

	draw();
}
function canvas_mousemove(e){
	if(_ismoving && _shapes.selectedItem){
		var x = e.pageX - _canvas.offsetLeft - _offsetX;
		var y = e.pageY - _canvas.offsetTop - _offsetY;

		_shapes.selectedItem.setPosition(x,y);
		draw();
	}
}
function canvas_mouseup(e){
	_ismoving = false;
}

function clear(deleteData){

	_context.clearRect(0,0,_canvas.width,_canvas.height);
	if(deleteData)
		_shapes.items = [];
}

function draw(){
	clear();
    for (var i = _shapes.items.length-1;i>=0; i--) {
		_shapes.items[i].draw(_context);
    }

	_ball.draw(_context);
}
function update(){
	_ball.move();
	_ball.checkCollision(_shapes);
	draw();
}
function start_stop(){

	var button = document.getElementById("button2");

	if(_timer)
	{
		clearInterval(_timer);
		_timer = null;
		button.innerHTML = "Start";
	}
	else
	{
		_timer = setInterval("update()",10);
		button.innerHTML = "Stop";
	}
}
window.onload = function(){

	_canvas = document.getElementById("canvas");
	_context = _canvas.getContext("2d");

	_ball = new Ball(_canvas.width,_canvas.height);
	_canvas.onmousedown = canvas_mousedown;
	_canvas.onmousemove = canvas_mousemove;
	_canvas.onmouseup = canvas_mouseup;

	start_stop();

	document.getElementById("button1").onclick = function(){
		clear(true);
	};
	document.getElementById("button2").onclick = function(){
		start_stop();
	};
};
</script>
</head>
<body>
	<div>
	<button id="button1">Clear</button>
	<button id="button2">Stop</button>
	</div>
   <canvas id="canvas" width="400px" height="400px" style="border: 1px solid gray;"></canvas>
</body>
</html>

YinYang’s Programming 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.