
게임 회전
HTML5 Canvas 게임에서 게임 구성 요소를 회전시키는 방법을 배워보자. 회전 기능은 우주선, 자동차, 캐릭터 등 다양한 게임 오브젝트에 동적인 움직임을 부여하는 핵심 기술이다.
기본 회전 개념
Canvas에서 회전을 구현하려면 다음 단계를 따른다.
- Canvas 컨텍스트의 좌표계를 객체의 중심으로 이동한다
- 원하는 각도만큼 회전시킨다
- 객체를 그린다
- 좌표계를 원래 상태로 복원한다
간단한 회전 예제
먼저 빨간색 사각형이 회전하는 간단한 예제를 만들어보자.
<canvas id="myCanvas1" width="400" height="200" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var myGamePiece;
function startGame() {
myGameArea.start();
myGamePiece = new component(30, 30, "red", 200, 100);
}
var myGameArea = {
canvas : document.getElementById("myCanvas1"),
start : function() {
this.context = this.canvas.getContext("2d");
this.interval = setInterval(updateGameArea, 20);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component(width, height, color, x, y) {
this.width = width;
this.height = height;
this.angle = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.fillStyle = color;
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
ctx.restore();
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.angle += 0.01;
myGamePiece.update();
}
startGame();
</script>
이 예제에서는 빨간색 사각형이 중심을 기준으로 계속 회전한다. angle 속성이 매 프레임마다 0.01씩 증가하여 회전 효과를 만든다.
키보드로 회전 제어하기
이제 키보드 입력으로 게임 오브젝트의 회전을 제어해보자.
<canvas id="myCanvas2" width="400" height="200" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<p>화살표 키를 사용하여 빨간색 사각형을 회전시키세요. 위/아래 화살표는 회전, 좌/우 화살표는 이동입니다.</p>
<script>
var myGamePiece2;
function startGame2() {
myGameArea2.start();
myGamePiece2 = new component2(30, 30, "red", 200, 100);
}
var myGameArea2 = {
canvas : document.getElementById("myCanvas2"),
start : function() {
this.context = this.canvas.getContext("2d");
this.interval = setInterval(updateGameArea2, 20);
window.addEventListener('keydown', function (e) {
myGameArea2.key = e.keyCode;
})
window.addEventListener('keyup', function (e) {
myGameArea2.key = false;
})
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component2(width, height, color, x, y) {
this.width = width;
this.height = height;
this.angle = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea2.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.fillStyle = color;
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
ctx.restore();
}
}
function updateGameArea2() {
myGameArea2.clear();
if (myGameArea2.key && myGameArea2.key == 37) {myGamePiece2.x -= 1; }
if (myGameArea2.key && myGameArea2.key == 39) {myGamePiece2.x += 1; }
if (myGameArea2.key && myGameArea2.key == 38) {myGamePiece2.angle -= 0.05; }
if (myGameArea2.key && myGameArea2.key == 40) {myGamePiece2.angle += 0.05; }
myGamePiece2.update();
}
startGame2();
</script>
이 예제에서는 위/아래 화살표 키로 회전을 제어하고, 좌/우 화살표 키로 좌우 이동을 제어한다. keyCode 37(왼쪽), 38(위), 39(오른쪽), 40(아래)을 사용한다.
회전하며 전진하는 우주선
실제 게임에서 자주 사용되는 패턴인 회전하며 전진하는 우주선을 구현해보자.
<canvas id="myCanvas3" width="400" height="200" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<p>화살표 키로 우주선을 조종하세요. 위 화살표: 전진, 좌/우 화살표: 회전</p>
<script>
var myGamePiece3;
function startGame3() {
myGameArea3.start();
myGamePiece3 = new component3(30, 30, "red", 200, 100);
}
var myGameArea3 = {
canvas : document.getElementById("myCanvas3"),
start : function() {
this.context = this.canvas.getContext("2d");
this.interval = setInterval(updateGameArea3, 20);
window.addEventListener('keydown', function (e) {
myGameArea3.keys = (myGameArea3.keys || []);
myGameArea3.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
myGameArea3.keys[e.keyCode] = false;
})
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component3(width, height, color, x, y) {
this.width = width;
this.height = height;
this.angle = 0;
this.x = x;
this.y = y;
this.speedX = 0;
this.speedY = 0;
this.update = function() {
ctx = myGameArea3.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.fillStyle = color;
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
ctx.restore();
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
if (this.x > myGameArea3.canvas.width) this.x = 0;
if (this.x < 0) this.x = myGameArea3.canvas.width;
if (this.y > myGameArea3.canvas.height) this.y = 0;
if (this.y < 0) this.y = myGameArea3.canvas.height;
}
}
function updateGameArea3() {
myGameArea3.clear();
if (myGameArea3.keys && myGameArea3.keys[37]) {myGamePiece3.angle -= 0.05; }
if (myGameArea3.keys && myGameArea3.keys[39]) {myGamePiece3.angle += 0.05; }
if (myGameArea3.keys && myGameArea3.keys[38]) {
myGamePiece3.speedX += Math.sin(myGamePiece3.angle) * 0.1;
myGamePiece3.speedY -= Math.cos(myGamePiece3.angle) * 0.1;
}
myGamePiece3.speedX *= 0.99;
myGamePiece3.speedY *= 0.99;
myGamePiece3.newPos();
myGamePiece3.update();
}
startGame3();
</script>[/code]
이 예제에서는 다음과 같은 기능을 구현했다.
- 좌/우 화살표로 우주선 회전
- 위 화살표로 현재 방향으로 추진력 생성
- 관성 효과 (speedX, speedY가 점진적으로 감소)
- 화면 가장자리에서 반대편으로 나타나는 랩어라운드 효과
- 삼각함수를 사용한 방향 계산
이미지를 사용한 회전 스프라이트
실제 게임에서는 단순한 사각형 대신 이미지를 사용한다. 이미지 스프라이트의 회전을 구현해보자.
[code lang="markup"]<canvas id="myCanvas4" width="400" height="200" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<p>화살표 키로 우주선 이미지를 회전시키세요.</p>
<script>
var myGamePiece4;
var spaceshipImg;
function startGame4() {
spaceshipImg = new Image();
spaceshipImg.onload = function() {
myGameArea4.start();
myGamePiece4 = new component4(40, 40, spaceshipImg, 200, 100, "image");
};
spaceshipImg.src = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTIwIDVMMzAgMzVIMTBMMjAgNVoiIGZpbGw9IiMzMzMiLz4KPHN2Zz4K";
}
var myGameArea4 = {
canvas : document.getElementById("myCanvas4"),
start : function() {
this.context = this.canvas.getContext("2d");
this.interval = setInterval(updateGameArea4, 20);
window.addEventListener('keydown', function (e) {
myGameArea4.keys = (myGameArea4.keys || []);
myGameArea4.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
myGameArea4.keys[e.keyCode] = false;
})
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component4(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.angle = 0;
this.x = x;
this.y = y;
this.speedX = 0;
this.speedY = 0;
this.update = function() {
ctx = myGameArea4.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
if (this.type == "image") {
ctx.drawImage(color, this.width / -2, this.height / -2, this.width, this.height);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
}
ctx.restore();
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
if (this.x > myGameArea4.canvas.width) this.x = 0;
if (this.x < 0) this.x = myGameArea4.canvas.width;
if (this.y > myGameArea4.canvas.height) this.y = 0;
if (this.y < 0) this.y = myGameArea4.canvas.height;
}
}
function updateGameArea4() {
myGameArea4.clear();
if (myGameArea4.keys && myGameArea4.keys[37]) {myGamePiece4.angle -= 0.05; }
if (myGameArea4.keys && myGameArea4.keys[39]) {myGamePiece4.angle += 0.05; }
if (myGameArea4.keys && myGameArea4.keys[38]) {
myGamePiece4.speedX += Math.sin(myGamePiece4.angle) * 0.1;
myGamePiece4.speedY -= Math.cos(myGamePiece4.angle) * 0.1;
}
myGamePiece4.speedX *= 0.99;
myGamePiece4.speedY *= 0.99;
myGamePiece4.newPos();
myGamePiece4.update();
}
startGame4();
</script>[/code]
이 예제에서는 SVG로 생성한 우주선 이미지를 사용하여 더 현실적인 게임 오브젝트를 만들었다.
부드러운 회전 애니메이션
급격한 회전 대신 부드러운 회전 애니메이션을 구현해보자.
[code lang="markup"]<canvas id="myCanvas5" width="400" height="200" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<p>좌/우 화살표 키로 부드러운 회전을 경험하세요.</p>
<script>
var myGamePiece5;
function startGame5() {
myGameArea5.start();
myGamePiece5 = new component5(30, 30, "blue", 200, 100);
}
var myGameArea5 = {
canvas : document.getElementById("myCanvas5"),
start : function() {
this.context = this.canvas.getContext("2d");
this.interval = setInterval(updateGameArea5, 20);
window.addEventListener('keydown', function (e) {
myGameArea5.keys = (myGameArea5.keys || []);
myGameArea5.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
myGameArea5.keys[e.keyCode] = false;
})
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component5(width, height, color, x, y) {
this.width = width;
this.height = height;
this.angle = 0;
this.x = x;
this.y = y;
this.rotationSpeed = 0;
this.maxRotationSpeed = 0.1;
this.rotationAcceleration = 0.005;
this.rotationDeceleration = 0.95;
this.update = function() {
ctx = myGameArea5.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.fillStyle = color;
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
ctx.restore();
}
this.updateRotation = function() {
this.angle += this.rotationSpeed;
this.rotationSpeed *= this.rotationDeceleration;
}
}
function updateGameArea5() {
myGameArea5.clear();
if (myGameArea5.keys && myGameArea5.keys[37]) {
myGamePiece5.rotationSpeed -= myGamePiece5.rotationAcceleration;
if (myGamePiece5.rotationSpeed < -myGamePiece5.maxRotationSpeed) {
myGamePiece5.rotationSpeed = -myGamePiece5.maxRotationSpeed;
}
}
if (myGameArea5.keys && myGameArea5.keys[39]) {
myGamePiece5.rotationSpeed += myGamePiece5.rotationAcceleration;
if (myGamePiece5.rotationSpeed > myGamePiece5.maxRotationSpeed) {
myGamePiece5.rotationSpeed = myGamePiece5.maxRotationSpeed;
}
}
myGamePiece5.updateRotation();
myGamePiece5.update();
}
startGame5();
</script>
이 예제에서는 회전 가속도와 감속을 구현하여 더 자연스러운 회전 움직임을 만들었다. 키를 누르면 점진적으로 회전 속도가 증가하고, 키를 놓으면 점진적으로 감속한다.
💡 게임 회전 구현 팁:
• save()와 restore() 메서드를 사용하여 회전 변환이 다른 객체에 영향을 주지 않도록 한다
• 각도는 라디안 단위로 계산된다. 도(degree)를 라디안으로 변환하려면 (도 * Math.PI / 180)을 사용한다
• 삼각함수 Math.sin()과 Math.cos()를 사용하여 회전된 방향으로의 이동을 계산할 수 있다
• 부드러운 회전을 위해서는 가속도와 감속도를 적절히 조절하는 것이 중요하다
게임에서 회전 기능은 플레이어의 조작감과 게임의 재미에 직접적인 영향을 준다. 이러한 기본적인 회전 원리를 이해하고 응용하면 다양한 게임 장르에서 활용할 수 있는 회전 시스템을 구축할 수 있다.