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

HTML 게임 – 점수

6일전 작성

HTML Canvas 게임 점수

HTML Canvas 게임에서 점수 시스템을 구현하는 방법을 알아본다. 점수를 표시하고 관리하는 다양한 기법을 통해 게임에 경쟁 요소를 추가해보자.

기본 점수 표시

게임에 점수를 표시하는 기본적인 방법을 구현해보자.

<canvas id="myCanvas1" width="480" height="270" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var myGamePiece;
var myObstacle;
var myScore;
var myGameArea = {
canvas: document.getElementById("myCanvas1"),
start: function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
this.frameNo = 0;
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, type) {
this.type = type;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
if (this.type == "text") {
ctx.font = this.width + " " + this.height;
ctx.fillStyle = color;
ctx.fillText(this.text, this.x, this.y);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
}
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myObstacle = new component(10, 200, "green", 300, 120);
myScore = new component("30px", "Consolas", "black", 280, 40, "text");
myGameArea.start();
}
function updateGameArea() {
myGameArea.clear();
myGameArea.frameNo += 1;
myObstacle.speedX = -1;
myObstacle.newPos();
myObstacle.update();
myGamePiece.newPos();
myGamePiece.update();
myScore.text = "점수: " + myGameArea.frameNo;
myScore.update();
}
startGame();
</script>

myScore 컴포넌트는 텍스트 타입으로 생성되며, frameNo를 사용하여 시간에 따라 점수가 증가한다. 점수는 매 프레임마다 업데이트된다.

키보드 조작과 점수

플레이어가 조작할 수 있는 게임에 점수 시스템을 추가해보자.

<canvas id="myCanvas2" width="480" height="270" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var myGamePiece;
var myObstacle;
var myScore;
var myGameArea = {
canvas: document.getElementById("myCanvas2"),
start: function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
myGameArea.key = e.keyCode;
})
window.addEventListener('keyup', function (e) {
myGameArea.key = false;
})
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
if (this.type == "text") {
ctx.font = this.width + " " + this.height;
ctx.fillStyle = color;
ctx.fillText(this.text, this.x, this.y);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
crash = false;
}
return crash;
}
}
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myObstacle = new component(10, 200, "green", 300, 120);
myScore = new component("30px", "Consolas", "black", 280, 40, "text");
myGameArea.start();
}
function updateGameArea() {
if (myGamePiece.crashWith(myObstacle)) {
myGameArea.stop();
} else {
myGameArea.clear();
myGameArea.frameNo += 1;
myObstacle.speedX = -1;
myObstacle.newPos();
myObstacle.update();
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
if (myGameArea.key && myGameArea.key == 37) {myGamePiece.speedX = -1; }
if (myGameArea.key && myGameArea.key == 39) {myGamePiece.speedX = 1; }
if (myGameArea.key && myGameArea.key == 38) {myGamePiece.speedY = -1; }
if (myGameArea.key && myGameArea.key == 40) {myGamePiece.speedY = 1; }
myGamePiece.newPos();
myGamePiece.update();
myScore.text = "점수: " + myGameArea.frameNo;
myScore.update();
}
}
startGame();
</script>

키보드 컨트롤과 충돌 감지를 추가했다. 플레이어가 장애물과 충돌하면 게임이 멈추고 최종 점수가 표시된다.

다중 점수 정보 표시

여러 종류의 점수 정보를 동시에 표시해보자.

<canvas id="myCanvas3" width="480" height="270" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var myGamePiece;
var myObstacle;
var myScore;
var myTime;
var myLevel;
var gameTime = 0;
var gameLevel = 1;
var myGameArea = {
canvas: document.getElementById("myCanvas3"),
start: function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
myGameArea.key = e.keyCode;
})
window.addEventListener('keyup', function (e) {
myGameArea.key = false;
})
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
if (this.type == "text") {
ctx.font = this.width + " " + this.height;
ctx.fillStyle = color;
ctx.fillText(this.text, this.x, this.y);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
crash = false;
}
return crash;
}
}
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myObstacle = new component(10, 200, "green", 300, 120);
myScore = new component("20px", "Arial", "black", 280, 30, "text");
myTime = new component("20px", "Arial", "black", 280, 55, "text");
myLevel = new component("20px", "Arial", "black", 280, 80, "text");
myGameArea.start();
}
function updateGameArea() {
if (myGamePiece.crashWith(myObstacle)) {
myGameArea.stop();
} else {
myGameArea.clear();
myGameArea.frameNo += 1;
gameTime = Math.floor(myGameArea.frameNo / 50);
gameLevel = Math.floor(gameTime / 10) + 1;
myObstacle.speedX = -1 - (gameLevel * 0.2);
myObstacle.newPos();
myObstacle.update();
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
if (myGameArea.key && myGameArea.key == 37) {myGamePiece.speedX = -2; }
if (myGameArea.key && myGameArea.key == 39) {myGamePiece.speedX = 2; }
if (myGameArea.key && myGameArea.key == 38) {myGamePiece.speedY = -2; }
if (myGameArea.key && myGameArea.key == 40) {myGamePiece.speedY = 2; }
myGamePiece.newPos();
myGamePiece.update();
myScore.text = "점수: " + myGameArea.frameNo;
myScore.update();
myTime.text = "시간: " + gameTime + "초";
myTime.update();
myLevel.text = "레벨: " + gameLevel;
myLevel.update();
}
}
startGame();
</script>

점수, 시간, 레벨을 동시에 표시한다. 레벨이 올라갈수록 장애물의 속도가 빨라져서 난이도가 증가한다.

점수 기반 이벤트

특정 점수에 도달했을 때 이벤트가 발생하는 시스템을 만들어보자.

<canvas id="myCanvas4" width="480" height="270" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var myGamePiece;
var myObstacles = [];
var myScore;
var myMessage;
var bonusActive = false;
var myGameArea = {
canvas: document.getElementById("myCanvas4"),
start: function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
myGameArea.key = e.keyCode;
})
window.addEventListener('keyup', function (e) {
myGameArea.key = false;
})
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
if (this.type == "text") {
ctx.font = this.width + " " + this.height;
ctx.fillStyle = color;
ctx.fillText(this.text, this.x, this.y);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
crash = false;
}
return crash;
}
}
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myScore = new component("20px", "Arial", "black", 280, 30, "text");
myMessage = new component("16px", "Arial", "blue", 280, 55, "text");
myGameArea.start();
}
function updateGameArea() {
for (i = 0; i < myObstacles.length; i += 1) { if (myGamePiece.crashWith(myObstacles[i])) { myGameArea.stop(); return; } } myGameArea.clear(); myGameArea.frameNo += 1; if (myGameArea.frameNo == 1 || everyinterval(150)) { var x = myGameArea.canvas.width; var y = Math.floor(Math.random() * (myGameArea.canvas.height - 100)); var width = Math.floor(Math.random() * 20 + 10); var height = Math.floor(Math.random() * 80 + 40); myObstacles.push(new component(width, height, "green", x, y)); } if (myGameArea.frameNo % 500 == 0) { bonusActive = true; myGamePiece.width = 20; myGamePiece.height = 20; setTimeout(function() { bonusActive = false; myGamePiece.width = 30; myGamePiece.height = 30; }, 3000); } for (i = myObstacles.length - 1; i >= 0; i -= 1) {
myObstacles[i].speedX = -2;
myObstacles[i].newPos();
if (myObstacles[i].x + myObstacles[i].width < 0) { myObstacles.splice(i, 1); } else { myObstacles[i].update(); } } myGamePiece.speedX = 0; myGamePiece.speedY = 0; if (myGameArea.key && myGameArea.key == 37) {myGamePiece.speedX = -2; } if (myGameArea.key && myGameArea.key == 39) {myGamePiece.speedX = 2; } if (myGameArea.key && myGameArea.key == 38) {myGamePiece.speedY = -2; } if (myGameArea.key && myGameArea.key == 40) {myGamePiece.speedY = 2; } myGamePiece.newPos(); myGamePiece.update(); myScore.text = "점수: " + myGameArea.frameNo; myScore.update(); if (bonusActive) { myMessage.text = "보너스 타임! 작은 크기!"; } else { myMessage.text = ""; } myMessage.update(); } function everyinterval(n) { if ((myGameArea.frameNo / n) % 1 == 0) {return true;} return false; } startGame(); </script>[/code]

500점마다 보너스 타임이 발생하여 플레이어의 크기가 작아진다. 메시지를 통해 현재 상태를 알려준다.

최고 점수 기록

최고 점수를 기록하고 표시하는 시스템을 구현해보자.

[code lang="markup"]<canvas id="myCanvas5" width="480" height="270" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<button onclick="restartGame()">게임 재시작</button>
<script>
var myGamePiece;
var myObstacle;
var myScore;
var myHighScore;
var highScore = 0;
var gameRunning = false;
var myGameArea = {
canvas: document.getElementById("myCanvas5"),
start: function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
myGameArea.key = e.keyCode;
})
window.addEventListener('keyup', function (e) {
myGameArea.key = false;
})
gameRunning = true;
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
if (this.frameNo > highScore) {
highScore = this.frameNo;
localStorage.setItem('highScore', highScore);
}
gameRunning = false;
}
}
function component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
if (this.type == "text") {
ctx.font = this.width + " " + this.height;
ctx.fillStyle = color;
ctx.fillText(this.text, this.x, this.y);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
crash = false;
}
return crash;
}
}
function startGame() {
if (localStorage.getItem('highScore')) {
highScore = parseInt(localStorage.getItem('highScore'));
}
myGamePiece = new component(30, 30, "red", 10, 120);
myObstacle = new component(10, 200, "green", 300, 120);
myScore = new component("20px", "Arial", "black", 280, 30, "text");
myHighScore = new component("20px", "Arial", "purple", 280, 55, "text");
myGameArea.start();
}
function updateGameArea() {
if (myGamePiece.crashWith(myObstacle)) {
myGameArea.stop();
} else {
myGameArea.clear();
myGameArea.frameNo += 1;
myObstacle.speedX = -1;
myObstacle.newPos();
myObstacle.update();
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
if (myGameArea.key && myGameArea.key == 37) {myGamePiece.speedX = -1; }
if (myGameArea.key && myGameArea.key == 39) {myGamePiece.speedX = 1; }
if (myGameArea.key && myGameArea.key == 38) {myGamePiece.speedY = -1; }
if (myGameArea.key && myGameArea.key == 40) {myGamePiece.speedY = 1; }
myGamePiece.newPos();
myGamePiece.update();
myScore.text = "점수: " + myGameArea.frameNo;
myScore.update();
myHighScore.text = "최고 점수: " + highScore;
myHighScore.update();
}
}
function restartGame() {
if (!gameRunning) {
startGame();
}
}
startGame();
</script>

localStorage를 사용하여 최고 점수를 브라우저에 저장한다. 게임이 끝날 때 현재 점수가 최고 점수보다 높으면 갱신된다.

실시간 점수 계산

다양한 요소를 고려한 복합적인 점수 계산 시스템을 만들어보자.

<canvas id="myCanvas6" width="480" height="270" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var myGamePiece;
var myObstacles = [];
var myBonuses = [];
var myScore;
var myMultiplier;
var baseScore = 0;
var bonusScore = 0;
var multiplier = 1;
var myGameArea = {
canvas: document.getElementById("myCanvas6"),
start: function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
myGameArea.key = e.keyCode;
})
window.addEventListener('keyup', function (e) {
myGameArea.key = false;
})
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
if (this.type == "text") {
ctx.font = this.width + " " + this.height;
ctx.fillStyle = color;
ctx.fillText(this.text, this.x, this.y);
} else if (this.type == "bonus") {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width/2, 0, 2 * Math.PI);
ctx.fill();
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
crash = false;
}
return crash;
}
}
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myScore = new component("18px", "Arial", "black", 280, 25, "text");
myMultiplier = new component("16px", "Arial", "orange", 280, 45, "text");
myGameArea.start();
}
function updateGameArea() {
for (i = 0; i < myObstacles.length; i += 1) { if (myGamePiece.crashWith(myObstacles[i])) { myGameArea.stop(); return; } } for (i = myBonuses.length - 1; i >= 0; i -= 1) {
if (myGamePiece.crashWith(myBonuses[i])) {
bonusScore += 50 * multiplier;
multiplier = Math.min(multiplier + 0.1, 3);
myBonuses.splice(i, 1);
}
}
myGameArea.clear();
myGameArea.frameNo += 1;
baseScore = Math.floor(myGameArea.frameNo / 10);
if (myGameArea.frameNo == 1 || everyinterval(120)) {
var x = myGameArea.canvas.width;
var y = Math.floor(Math.random() * (myGameArea.canvas.height - 100));
var width = Math.floor(Math.random() * 20 + 10);
var height = Math.floor(Math.random() * 80 + 40);
myObstacles.push(new component(width, height, "green", x, y));
}
if (everyinterval(200)) {
var x = myGameArea.canvas.width;
var y = Math.floor(Math.random() * (myGameArea.canvas.height - 30));
myBonuses.push(new component(20, 20, "gold", x, y, "bonus"));
}
if (myGameArea.frameNo % 300 == 0) {
multiplier = Math.max(multiplier - 0.2, 1);
}
for (i = myObstacles.length - 1; i >= 0; i -= 1) {
myObstacles[i].speedX = -2;
myObstacles[i].newPos();
if (myObstacles[i].x + myObstacles[i].width < 0) { myObstacles.splice(i, 1); } else { myObstacles[i].update(); } } for (i = myBonuses.length - 1; i >= 0; i -= 1) {
myBonuses[i].speedX = -2;
myBonuses[i].newPos();
if (myBonuses[i].x + myBonuses[i].width < 0) { myBonuses.splice(i, 1); } else { myBonuses[i].update(); } } myGamePiece.speedX = 0; myGamePiece.speedY = 0; if (myGameArea.key && myGameArea.key == 37) {myGamePiece.speedX = -2; } if (myGameArea.key && myGameArea.key == 39) {myGamePiece.speedX = 2; } if (myGameArea.key && myGameArea.key == 38) {myGamePiece.speedY = -2; } if (myGameArea.key && myGameArea.key == 40) {myGamePiece.speedY = 2; } myGamePiece.newPos(); myGamePiece.update(); var totalScore = Math.floor((baseScore + bonusScore) * multiplier); myScore.text = "점수: " + totalScore; myScore.update(); myMultiplier.text = "배수: x" + multiplier.toFixed(1); myMultiplier.update(); } function everyinterval(n) { if ((myGameArea.frameNo / n) % 1 == 0) {return true;} return false; } startGame(); </script>[/code]

기본 점수, 보너스 점수, 배수 시스템을 조합한 복합적인 점수 계산을 구현했다. 보너스 아이템을 수집하면 배수가 증가하고, 시간이 지나면 배수가 감소한다.

점수 애니메이션 효과

점수가 증가할 때 시각적 효과를 추가해보자.

<canvas id="myCanvas7" width="480" height="270" style="border:1px solid #d3d3d3;">
브라우저가 HTML5 Canvas를 지원하지 않습니다.
</canvas>
<script>
var myGamePiece;
var myObstacles = [];
var myBonuses = [];
var myScore;
var scoreEffects = [];
var totalScore = 0;
var myGameArea = {
canvas: document.getElementById("myCanvas7"),
start: function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
myGameArea.key = e.keyCode;
})
window.addEventListener('keyup', function (e) {
myGameArea.key = false;
})
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.alpha = 1;
this.update = function() {
ctx = myGameArea.context;
if (this.type == "text") {
ctx.font = this.width + " " + this.height;
ctx.fillStyle = color;
ctx.fillText(this.text, this.x, this.y);
} else if (this.type == "effect") {
ctx.font = this.width + " " + this.height;
ctx.fillStyle = "rgba(255, 215, 0, " + this.alpha + ")";
ctx.fillText(this.text, this.x, this.y);
} else if (this.type == "bonus") {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width/2, 0, 2 * Math.PI);
ctx.fill();
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
if (this.type == "effect") {
this.alpha -= 0.02;
this.speedY = -1;
}
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
crash = false;
}
return crash;
}
}
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myScore = new component("20px", "Arial", "black", 280, 30, "text");
myGameArea.start();
}
function updateGameArea() {
for (i = 0; i < myObstacles.length; i += 1) { if (myGamePiece.crashWith(myObstacles[i])) { myGameArea.stop(); return; } } for (i = myBonuses.length - 1; i >= 0; i -= 1) {
if (myGamePiece.crashWith(myBonuses[i])) {
totalScore += 100;
var effect = new component("20px", "Arial", "gold", myBonuses[i].x, myBonuses[i].y, "effect");
effect.text = "+100";
scoreEffects.push(effect);
myBonuses.splice(i, 1);
}
}
myGameArea.clear();
myGameArea.frameNo += 1;
totalScore += 1;
if (myGameArea.frameNo == 1 || everyinterval(150)) {
var x = myGameArea.canvas.width;
var y = Math.floor(Math.random() * (myGameArea.canvas.height - 100));
var width = Math.floor(Math.random() * 20 + 10);
var height = Math.floor(Math.random() * 80 + 40);
myObstacles.push(new component(width, height, "green", x, y));
}
if (everyinterval(250)) {
var x = myGameArea.canvas.width;
var y = Math.floor(Math.random() * (myGameArea.canvas.height - 30));
myBonuses.push(new component(20, 20, "gold", x, y, "bonus"));
}
for (i = myObstacles.length - 1; i >= 0; i -= 1) {
myObstacles[i].speedX = -2;
myObstacles[i].newPos();
if (myObstacles[i].x + myObstacles[i].width < 0) { myObstacles.splice(i, 1); } else { myObstacles[i].update(); } } for (i = myBonuses.length - 1; i >= 0; i -= 1) {
myBonuses[i].speedX = -2;
myBonuses[i].newPos();
if (myBonuses[i].x + myBonuses[i].width < 0) { myBonuses.splice(i, 1); } else { myBonuses[i].update(); } } for (i = scoreEffects.length - 1; i >= 0; i -= 1) {
scoreEffects[i].newPos();
if (scoreEffects[i].alpha <= 0) { scoreEffects.splice(i, 1); } else { scoreEffects[i].update(); } } myGamePiece.speedX = 0; myGamePiece.speedY = 0; if (myGameArea.key && myGameArea.key == 37) {myGamePiece.speedX = -2; } if (myGameArea.key && myGameArea.key == 39) {myGamePiece.speedX = 2; } if (myGameArea.key && myGameArea.key == 38) {myGamePiece.speedY = -2; } if (myGameArea.key && myGameArea.key == 40) {myGamePiece.speedY = 2; } myGamePiece.newPos(); myGamePiece.update(); myScore.text = "점수: " + totalScore; myScore.update(); } function everyinterval(n) { if ((myGameArea.frameNo / n) % 1 == 0) {return true;} return false; } startGame(); </script>[/code]

보너스 아이템을 수집할 때 "+100" 텍스트가 나타나서 위로 올라가면서 사라지는 애니메이션 효과를 구현했다. alpha 값을 조절하여 페이드아웃 효과를 만든다.

💡 게임 점수 시스템 설계 팁:
• 점수는 플레이어의 성취감을 높이는 중요한 요소이다. 적절한 증가 폭을 설정하자
• 다양한 점수 획득 방법을 제공하면 게임이 더 흥미로워진다
• 최고 점수 기록은 플레이어의 재도전 의욕을 높인다
• 시각적 효과를 추가하면 점수 획득의 만족감이 증가한다

게임 점수 시스템은 플레이어의 몰입도와 재미를 크게 좌우하는 중요한 요소이다. 기본적인 점수 표시부터 복합적인 계산 시스템, 시각적 효과까지 다양한 기법을 활용하여 매력적인 게임을 만들 수 있다.

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