여러분이 사용하고 계신 브라우저는 HTML5를 지원하지 않기 때문에 몇몇 요소가 제대로 보이도록 JScript를 사용하고 있습니다. 하지만 여러분의 브라우저 설정에서 스크립트 기능이 꺼져있으므로, 현재 페이지를 제대로 확인하시려면 스크립트 기능을 켜주셔야 합니다. HTML 게임 - 회전

HTML 게임 – 회전

1개월전 작성

게임 회전

HTML5 Canvas 게임에서 게임 구성 요소를 회전시키는 방법을 배워보자. 회전 기능은 우주선, 자동차, 캐릭터 등 다양한 게임 오브젝트에 동적인 움직임을 부여하는 핵심 기술이다.

기본 회전 개념

Canvas에서 회전을 구현하려면 다음 단계를 따른다.

  1. Canvas 컨텍스트의 좌표계를 객체의 중심으로 이동한다
  2. 원하는 각도만큼 회전시킨다
  3. 객체를 그린다
  4. 좌표계를 원래 상태로 복원한다

간단한 회전 예제

먼저 빨간색 사각형이 회전하는 간단한 예제를 만들어보자.

<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()를 사용하여 회전된 방향으로의 이동을 계산할 수 있다
• 부드러운 회전을 위해서는 가속도와 감속도를 적절히 조절하는 것이 중요하다

게임에서 회전 기능은 플레이어의 조작감과 게임의 재미에 직접적인 영향을 준다. 이러한 기본적인 회전 원리를 이해하고 응용하면 다양한 게임 장르에서 활용할 수 있는 회전 시스템을 구축할 수 있다.

참고
Mingg`s Diary
밍구
공부 목적 블로그