본문 바로가기

HTML5/Transform

HTML5 Canvas Transform example

HTML5 Canvas 이동 및 회전변환 예제


translate()의 효과 : 호출될 때마다 이동변환의 량은 내부에서 사용되는 변환행렬에 저장되고 유지됨

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>이동</title>
<script type="text/javascript">
var canvas;
var ctx;

window.addEventListener('load', function() {
	canvas = document.getElementById("gameCanvas");
	ctx = canvas.getContext("2d");

	setInterval(gameLoop,30);
});

function gameLoop() {
	draw_test();
}

function draw_test(){
	ctx.beginPath();
	ctx.translate(10,10); // 반복실행되면 이동량이 누적된다(변환행렬에 저장됨)
	ctx.fillStyle = 'black';
	ctx.fillRect(0, 0, 5, 40);
	ctx.closePath();
	//ctx.setTransform(1,0,0,1,0,0); // 변환행렬을 초기화한다
} 
</script>
</head>
<body>
<canvas id="gameCanvas" width="300" height="200" style="border:1px solid black;">
</canvas>
</body>
</html>

위의 코드에서 ctx.setTransform(1,0,0,1,0,0)을 사용하면 내부에서 사용되는 변환행렬을 초기화하므로 translate(), rotate() 등을 사용하여 적용한 변환이 해제되어 초기화된다




위와 동일한 코드에 rotate()를 사용한 예

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>회전</title>
<script type="text/javascript">
var canvas;
var ctx;

window.addEventListener('load', function() {
	canvas = document.getElementById("gameCanvas");
	ctx = canvas.getContext("2d");

	setInterval(gameLoop,30);
});

function gameLoop() {
	draw_test();
}

function draw_test(){
	ctx.beginPath();
	ctx.rotate(20 * Math.PI/180); // 반복실행되면 회전량이 누적된다(변환행렬에 저장됨)
	ctx.fillStyle = 'black';
	ctx.fillRect(0, 0, 5, 40);
	ctx.closePath();
	//ctx.setTransform(1,0,0,1,0,0); // 변환행렬을 초기화한다
} 
</script>
</head>
<body>
<canvas id="gameCanvas" width="300" height="200" style="border:1px solid black;">
</canvas>
</body>
</html>


위의 코드를 실행한 결과



translate(), rotate()를 동시에 사용하는 예 (이동변환량은 고정하고 회전변환량은 누적함)

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>회전</title>
<script type="text/javascript">
var canvas;
var ctx;
var angle = 0;

window.addEventListener('load', function() { canvas = document.getElementById("gameCanvas"); ctx = canvas.getContext("2d"); setInterval(gameLoop,30); }); function gameLoop() { draw_test(); } function draw_test(){

var x = canvas.width/2; var y = canvas.height/2; ctx.beginPath(); ctx.translate(x,y); angle += 15; ctx.rotate(angle*Math.PI/180); ctx.fillStyle = 'black'; ctx.fillRect(0, 0, 5, 40); ctx.closePath(); ctx.setTransform(1,0,0,1,0,0); } </script> </head> <body> <canvas id="gameCanvas" width="300" height="200" style="border:1px solid black;"> </canvas> </body> </html>


위의 코드 실행결과


방향키로 방향을 지시하고 그 방향으로 포탄을 발사(직선이동)하는 예제

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>발사</title>
<script type="text/javascript">
var canvas;
var ctx;
var launcherX=0, launcherY=0;
var bulletX=0.0, bulletY=0.0;
var isFire = false;

window.addEventListener('load', function() {
	window.addEventListener('keydown', onKeyDown);
    canvas = document.getElementById("gameCanvas");
    ctx = canvas.getContext("2d");
    
    launcherX = canvas.width/2;
    launcherY = canvas.height - 50;
    
	setInterval(gameLoop,30);
});

function gameLoop() {
	drawLauncher();
	fire();
}

/* 발사각을 이용하여 탄도의 기울기(cos, sin)를 구하고 발사체에 적용한다 */
function fire() {
	if(!isFire) return;
	ctx.beginPath();
	ctx.fillStyle = 'black';
	var dx = 0.0;
	var dy = 0.0;
	var _angle = 0.0;
	
	if(angle<0) {
		_angle = 180+angle-90;
		dy = Math.sin(_angle*Math.PI/180);
		dx = -Math.cos(_angle*Math.PI/180);
	}else {
		_angle = angle-90;
		dy = -Math.sin(_angle*Math.PI/180);
		dx = Math.cos(_angle*Math.PI/180);
	}
	// 속도 증폭
	dx *= 5;
	dy *= 5;

	ctx.translate(bulletX+=dx,bulletY-=dy);
	ctx.rotate(angle*Math.PI/180);

    ctx.fillRect(-3,-40,5,5);
    ctx.closePath();
	ctx.setTransform(1,0,0,1,0,1);
    if(bulletY < 0) isFire = false;
}

/*방향키로 발사각을 조정하고 스페이스키를 누르면 발사된다*/
var angle = 0;
function onKeyDown(evt) {
	
	if(evt.keyCode==37) { // 왼쪽으로 회전
		angle--;
	}else if(evt.keyCode==39){ // 오른쪽으로 회전
		angle++;
	}else if(evt.keyCode==32) { // 발사
		bulletX = launcherX;
		bulletY = launcherY;
		isFire = true;
	}
}

/* 작은 사각형의 하단을 중심으로 좌우로 회전하여 발사방향을 지시한다*/
function drawLauncher(){
	ctx.beginPath();
	ctx.fillStyle = 'white';
	ctx.fillRect(0,0,canvas.width, canvas.height); // 캔바스 지움
	ctx.closePath();
	
  	ctx.beginPath();
  	ctx.translate(launcherX,launcherY);
	ctx.rotate(angle*Math.PI/180);
	ctx.fillStyle = 'black';
	ctx.fillRect(-3, -40, 5, 40);
	ctx.closePath();
	ctx.setTransform(1,0,0,1,0,0); 
} 
</script>
</head>
<body>
<canvas id="gameCanvas"  width="500"  height="400" style="border:1px solid black;">
</canvas>
</body>
</html>


위의 코드를 실행한 결과


포물선 궤적을 따라 이동하면서 이동방향으로 기수 회전하기

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>포물선과 비행방향으로 회전하기</title>
<script type="text/javascript">
var canvas;
var ctx;
var launcherX=0, launcherY=0;
var bulletX=0.0, bulletY=0.0;
var isFire = false;

window.addEventListener('load', function() {
	window.addEventListener('keydown', onKeyDown);
    canvas = document.getElementById("gameCanvas");
    ctx = canvas.getContext("2d");
    
    launcherX = canvas.width/2;
    launcherY = canvas.height - 50;
    
	setInterval(gameLoop,30);
});

function gameLoop() {
	drawLauncher();
	fire();
}

/* 발사각을 이용하여 탄도의 기울기(cos, sin)를 구하고 발사체에 적용한다 */
var g = 0.1;
var xSpeed = 4.0;
var ySpeed = 4.0;
var prevPos;
var currPos;

function fire() {
	if(!isFire) return;
	ctx.beginPath();
	ctx.fillStyle = 'black';
	var dx = 0.0;
	var dy = 0.0;
	var _angle = 0.0;
	
	if(angle<0) {
		_angle = 180+angle-90;
		dy = Math.sin(_angle*Math.PI/180);
		dx = -Math.cos(_angle*Math.PI/180);
	}else {
		_angle = angle-90;
		dy = -Math.sin(_angle*Math.PI/180);
		dx = Math.cos(_angle*Math.PI/180);
	}
	// 속도 증폭
	dx *= xSpeed;
	dy *= ySpeed;
	ySpeed -= g;	// 중력가속도를 적용하여 포물선 이동 구현
	
	currPos = new Position(bulletX+=dx, bulletY-=dy);
	ctx.translate(currPos.x, currPos.y);
	
	// 발사체의 비행방향으로 기수를 회전한다
	// 비행궤적의 기울기를 구하여 각도 계산하여 발사체에 적용한다
	var rad = 0.0; // 비행각도
 	if(prevPos!=null){
		var dx = currPos.x - prevPos.x;
		var dy = currPos.y - prevPos.y;
		
		rad = Math.atan2(dy, dx);
		rad -= Math.PI/2;
	}

	ctx.rotate(rad); // 비행방향으로 기수를 회전한다
    ctx.fillRect(-3,0,5,15);
    ctx.closePath();
	ctx.setTransform(1,0,0,1,0,1);
	
    if(bulletY < 0 || bulletY>=canvas.height) {
    	isFire = false;
    	ySpeed = 4.0;
    	prevPos = null;
    	currPos = null;
    }
    prevPos = currPos;
}

/*방향키로 발사각을 조정하고 스페이스키를 누르면 발사된다*/
var angle = 0;
function onKeyDown(evt) {
	
	if(evt.keyCode==37) { // 왼쪽으로 회전
		angle--;
	}else if(evt.keyCode==39){ // 오른쪽으로 회전
		angle++;
	}else if(evt.keyCode==32) { // 발사
		bulletX = launcherX;
		bulletY = launcherY;
		isFire = true;
	}
}

/* 작은 사각형의 하단을 중심으로 좌우로 회전하여 발사방향을 지시한다*/
function drawLauncher(){
	ctx.beginPath();
	ctx.fillStyle = 'white';
	ctx.fillRect(0,0,canvas.width, canvas.height); // 캔바스 지움
	ctx.closePath();
	
  	ctx.beginPath();
  	ctx.translate(launcherX,launcherY);
	ctx.rotate(angle*Math.PI/180);
	ctx.fillStyle = 'black';
	ctx.fillRect(-3, -40, 5, 40);
	ctx.closePath();
	ctx.setTransform(1,0,0,1,0,0); 
}

function Position(x,y){
	this.x = x;
	this.y = y;
}
</script>
</head>
<body>
<canvas id="gameCanvas"  width="500"  height="400" style="border:1px solid black;">
</canvas>
</body>
</html>


위의 코드를 실행하여 방향키로 발사각을 지정하고 스페이스 키를 눌러 포탄을 발사하여 포물선 운동을 테스트한 결과