const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');
const statuscanvas = document.getElementById('statusCanvas');
const ctx = statuscanvas.getContext('2d');
document.addEventListener('keydown', keyPush);
let gameState = 0; // 0 플레이 가능 / 1 전투모드 / 2 클리어
const fieldWidth = 40;
const fieldHeight = 40;
const fieldColumn = 10;
const fieldRow = 10;
const fields = [];
const charRadius = 20;
let charPosX = charRadius;
let charPosY = canvas.height - charRadius;
let charMoveDirX = -1;
let charMoveDirY = -1;
let charMoveSpd = 2;
let fieldColor = ["lightpink", "lightsalmon", "gold", "lightgreen", "mediumslateblue", "powderblue", "violet"];
// class Field {
// constructor(left, top, right, bottom) {
// this.left = left;
// this.top = top;
// this.right = right;
// this.bottom = bottom;
// }
// }
class Field {
constructor(left, top, right, bottom, column, row, color, type, ismob) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
this.column = column;
this.row = row;
this.color = color;
this.type = type;
this.ismob = ismob;
}
draw() {
context.beginPath();
context.rect(this.left, this.top, fieldWidth, fieldHeight);
context.fillStyle = fieldColor[this.color%7];
context.fill();
context.closePath();
}
}
let mobname = ["slime", "goblin", "kobold", "orc", "golem", "spider", "gnoll"]
class Mob {
constructor(left, top, right, bottom, ismob, money, name) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
this.ismob = ismob;
this.money = money;
this.name = name;
}
}
class Exit extends Field {
}
let exit = new Exit(
380 - (fieldWidth) / 2 , // left 380 - 20 360
20 - (fieldHeight) / 2, // top 20 - 20 0
380 + (fieldWidth) / 2, // right 380 + 20 400
20 + (fieldHeight) / 2, // bottom 20 + 20 40
1,
1,
)
class Shop extends Field {
}
let shop = new Shop(
220 - (fieldWidth) / 2 , // left 380 - 20 360
220 - (fieldHeight) / 2, // top 20 - 20 0
380 + (fieldWidth) / 2, // right 380 + 20 400
20 + (fieldHeight) / 2, // bottom 20 + 20 40
1,
1,
)
class Char extends Field{
constructor(left, top, right, bottom, hp, money) {
super(left, top, right, bottom)
this.hp = hp;
this.money = money;
}
drawChar()
{
let img_char = new Image();
img_char.src = "char.png";
img_char.onload = function()
{
context.drawImage(img_char, char.left, char.top, fieldWidth, fieldHeight)
}
}
}
let char = new Char(
charPosX-20, // left: ; 20 -20
charPosY-20, // top: ; 400 - 20 - 20
charPosX+20, // right 20 + 20
charPosY+20, // bottom 400 - 20 + 20
100, // hp
0, // money
)
function keyPush(evt){
switch(evt.keyCode) {
case 37: // 왼쪽
if(charPosX - 20 > 0) {
charPosX += -40;
charPosY += 0;
char.left = charPosX - charRadius;
char.right = charPosX + charRadius ;
}
break;
case 38: // 윗키
if(charPosY - 20 > 0) {
charPosX += 0;
charPosY += -40;
char.top = charPosY - charRadius;
char.bottom = charPosY + charRadius;
}
break;
case 39: // 오른쪽
if(charPosX + 20 < canvas.width){
charPosX += 40;
charPosY += 0;
char.left = charPosX - charRadius;
char.right = charPosX + charRadius;
}
break;
case 40: // 아래
if(charPosY + 20 < canvas.height){
charPosX += 0;
charPosY += 40;
char.top = charPosY - charRadius;
char.bottom = charPosY + charRadius;
}
break;
default:
break;
}
}
function charStat()
{
ctx.font = '18px serif'
ctx.clearRect(0, 0, statuscanvas.width, statuscanvas.height);
ctx.fillText("HP", 10, 30)
ctx.fillText(`${char.hp}`, 10, 55)
ctx.fillText("CowNow", 10, 150)
ctx.fillText(`${char.money}`, 10, 125)
}
function draw()
{
// // 화면 클리어
context.clearRect(0, 0, canvas.width-40, canvas.height);
context.clearRect(360, 40, 40, canvas.height-40);
// drawCanavs();
// 그리기
drawFields();
char.drawChar();
charStat();
}
function drawExit(){
let img_exit = new Image();
img_exit.src = "exit.png";
img_exit.onload = function()
{
context.drawImage(img_exit, exit.left, exit.top, fieldWidth, fieldHeight)
}
}
function drawShop(){
let img_shop = new Image();
img_shop.src = "shop.png";
img_shop.onload = function()
{
context.drawImage(img_shop, shop.left, shop.top, fieldWidth, fieldHeight)
}
}
function drawFields()
{
// let gaming = false;
for(let i = 0; i < fieldRow; i++)
{
for(let j = 0; j < fieldColumn; j++)
{
if((i != 9 || j != 0) && (i != 5 || j != 5)) fields[i][j].draw();
// if(fields[i][j].charstat > 0) gaming = true;
}
}
// if(!gaming){
// /* clear(); */
// }
}
function update()
{
meetMob();
// 충돌확인 어떤경우에도 안부딪히는 상황
if(isCollisionExitToChar(char, exit)) // right left top bottom
{
console.log("충돌!")
gameState = 2;
setTimeout(() => {
window.location.reload();
alert("clear")
}, 300);
}
if(isCollisionShopToChar(char, shop)) // right left top bottom
{
console.log("상점")
gameState = 2;
setTimeout(() => {
alert("회복완료")
}, 300);
}
}
function isCollisionExitToChar(charA, exitB)
{
// a의 완쪽과 b의 오른쪽
// a의 오른쪽과 b의 왼쪽
// a의 아래쪽과 b의 위쪽
// a의 위쪽과 b의 아래쪽
if (charA.left >= exitB.right || // a의 왼쪽이 더 클때
charA.right <= exitB.left || // b의 왼쪽이 더 클때
charA.top >= exitB.bottom || // a의 탑이 더 클때
charA.bottom <= exitB.top ) // b의 탑이 더 클때
{
return false;
}
return true;
}
function isCollisionShopToChar(charA, shopB)
{
// a의 완쪽과 b의 오른쪽
// a의 오른쪽과 b의 왼쪽
// a의 아래쪽과 b의 위쪽
// a의 위쪽과 b의 아래쪽
if (charA.left >= shopB.right || // a의 왼쪽이 더 클때
charA.right <= shopB.left || // b의 왼쪽이 더 클때
charA.top >= shopB.bottom || // a의 탑이 더 클때
charA.bottom <= shopB.top ) // b의 탑이 더 클때
{
return false;
}
return true;
}
function setFields()
{
for(let i = 0; i < fieldRow; i++)
{
fields[i] = [];
for(let j = 0; j < fieldColumn; j++)
{
fields[i][j] = new Field(
0 + i * 40,
0 + j * 40,
0 + (1+i) * 40,
0 + (1+j) * 40,
i,
j,
Math.floor((Math.random()*7)+1),
Math.round(Math.random()),
Math.round(Math.random())
)
// console.log(fields[i][j].ismob)
}
}
}
setFields();
let mobs = [];
function setMob() {
for(let i = 0; i < fieldRow; i++)
{
for(let j = 0; j < fieldColumn; j++)
{
// console.log(fields[i][j].ismob)
if(fields[i][j].ismob == 1 && (i != 0 && j !=0)) {
mobs.push(new Mob(
fields[i][j].left,
fields[i][j].top,
fields[i][j].right,
fields[i][j].bottom,
true,
Math.floor(Math.random()*100),
mobname[fields[i][j].color%7]))
console.log(fields[i][j].ismob)
}
}
}
}
setMob();
function meetMob() {
for(let i = 0; i < mobs.length; i++) {
// console.log(mobs[i])
if(mobs[i].left == char.left
&& mobs[i].top == char.top
/* && mobs[i].right == char.right
&& mobs[i].bottom == char.bottom */
&& mobs[i].ismob == true
) {
console.log(mobs[i].ismob)
console.log("몹 만남");
console.log(mobs[i].name);
gameState = 1;
alert(`${mobs[i].name} 과 전투!!`)
}
}
}
function setExit()
{
for(let i = 0; i < fieldRow; i++)
{
exit[i] = [];
for(let j = 0; j < fieldColumn; j++)
{
exit[i][j] = new Exit(
0 + i * 30,
0 + j * 30,
0 + (1+i) * 30,
0 + (1+j) * 30,
i,
j,
)
}
}
}
function setShop()
{
for(let i = 0; i < fieldRow; i++)
{
shop[i] = [];
for(let j = 0; j < fieldColumn; j++)
{
shop[i][j] = new Shop(
0 + i * 30,
0 + j * 30,
0 + (1+i) * 30,
0 + (1+j) * 30,
i,
j,
)
}
}
}
function battle(i)
{
let mobVal = Math.round(Math.random()*2)
let charVal = i
if(((charVal - mobVal)+3)%3 == 0){
alert("비김")
for(let i = 0; i < mobs.length; i++)
{
if(char.left == mobs[i].left && char.top == mobs[i].top){
mobs[i].ismob = false;
}
}
} else if(((charVal - mobVal)+3)%3 == 1){
alert("이김")
for(let i = 0; i < mobs.length; i++)
{
if(char.left == mobs[i].left && char.top == mobs[i].top){
char.money += mobs[i].money;
mobs[i].ismob = false;
}
}
}else {
alert("짐")
for(let i = 0; i < mobs.length; i++)
{
if(char.left == mobs[i].left && char.top == mobs[i].top){
mobs[i].ismob = false;
char.hp--;
}
}
}
gameState = 0;
}
// 몹이 012 중 값 하나를 낸다 // 내 값을 낸다 012
// 두 값의 빼서 기영+1(양수) 하고 %3 한다 0무승부 , 1이김 , 2짐
// 결과 이기면 골드 + , 지면 HP -
// 0 1 2
// 0 1 2
setInterval(()=>{if(gameState==0){draw()}}, 150);
setInterval(()=>{if(gameState==0){update()}}, 30);
setInterval(()=>{if(gameState==0){
drawShop()}}, 30);
setExit();
drawExit();
setShop();
drawShop();
// setInterval(draw, 150);
// setInterval(update, 30);
1차 버전
1. 맵 제작 - 이차원 배열 10 X 10
2. 맵타일 - 오브젝트 or 클래스
3. 플레이어, 탈출구 - 오브젝트 - 클래스
4. 키 입력 처리 - 상하좌우 1칸씩 이동 가능
5. 플레이어가 탈출구에 도착하면 게임 클리어
2차 버전
1. 몬스터 등장 - 플레이어가 이동할 때 마다 일정 확률로 만날 수 있다.
2. 전투 - 몬스터와 만나면 가위, 바위, 보 버튼이 생기고 가위, 바위, 보 시스템을 사용해서 전투가 벌어진다.
3. 전투 - 이기면 0 ~ 100골드 사이에서 랜덤하게 보상 획득
4. 전투 - 지면 HP 1감소
3차 버전
1. 맵타일 종류 추가 - 땅, 숲, 늪 등등
2. 맵타일 종류에 따라 다른 표현 (색, 모양)
3. 몬스터 종류 추가 - 맵타일 종류에 따라 등장하는 몬스터 변경
4. 상점 추가 - 맵에 상점 1개 존재
5. 상점 기능 - 골드를 소모해서 HP회복
4차 버전
1. 맵 표현 추가(시야 개념)
1-1. 안가본 영역 - 검은색
1-2. 기본 영역 - 회색 (탈출구, 상점 표시)
1-3. 현재 시야 - 밝은 회색 (탈출구, 상점 표시)
2. 전투시 몬스터 프로필 추가 - 몬스터 종류에 따라 이미지 출력