오늘은 황금 고블린이 클라이언트에서 생성 돼
정해진 맵 안에서 방향만을 바꿔가며 이동 하는 로직을 작성했다.
(코드에도 주석문으로 설명을 적어 놨고, 아래에도 설명이 존재합니다^^)
export class SpecialMonster {
constructor(path, specialMonster, specialMonsterImage, level) {
// 생성자 안에서 몬스터의 속성을 정의한다고 생각하시면 됩니다!
if (!path) {
throw new Error('몬스터가 이동할 경로가 필요합니다.');
}
this.specialMonsterInfo = specialMonster;
this.monsterId = this.specialMonsterInfo.monsterId;
this.path = path; // 몬스터가 이동할 경로
this.currentIndex = 0; // 몬스터가 이동 중인 경로의 인덱스
this.x = path.x; // 몬스터의 x 좌표 (최초 위치는 경로의 첫 번째 지점)
this.y = path.y; // 몬스터의 y 좌표 (최초 위치는 경로의 첫 번째 지점)
this.width = this.specialMonsterInfo.width; // 몬스터 이미지 가로 길이
this.height = this.specialMonsterInfo.height; // 몬스터 이미지 세로 길이
this.speed = this.specialMonsterInfo.speed; // 몬스터의 이동 속도
this.image = specialMonsterImage; // 몬스터 이미지
this.level = level; // 몬스터 레벨
// 초기 랜덤 방향 결정
this.moveX = Math.random() * this.speed;
this.moveY = Math.random() * this.speed;
this.init(level);
}
init(level) {
this.maxHp = this.specialMonsterInfo.maxHp + 10 * level; // 몬스터의 현재 HP
this.hp = this.maxHp; // 몬스터의 현재 HP
this.attackPower = this.specialMonsterInfo.attackPower + 5 * level; // 몬스터의 공격력 (기지에 가해지는 데미지)
}
move(canvas) {
let canvasWidth = canvas.width;
let canvasHeight = canvas.height;
this.x += this.moveX;
this.y += this.moveY;
if (this.x <= 0 || this.x + this.width >= canvasWidth) {
this.moveX *= -1;
// x축 반대 방향으로 변경
}
if (this.y <= 0 || this.y + this.height >= canvasHeight) {
this.moveY *= -1;
// y축 반대 방향으로 변경
}
}
draw(ctx) {
ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
ctx.font = '12px Arial';
ctx.fillStyle = 'white';
ctx.fillText(`(레벨 ${this.level}) ${this.hp}/${this.maxHp}`, this.x, this.y - 5);
}
}
먼저 황금 고블린이 생성되면,
// 초기 랜덤 방향 결정
this.moveX = Math.random() * this.speed;
this.moveY = Math.random() * this.speed;
으로 황금 고블린이 매 프래임 마다 이동할 X 축 거리와 Y축 거리를 결정해줍니다.
move(canvas) {
let canvasWidth = canvas.width;
let canvasHeight = canvas.height;
canvas는 맵의 크기 정보로
canvas.width에서 가로 크기 정보와,
canvas.height에서 세로 크기 정보를 가져 옵니다.
if (this.x <= 0 || this.x + this.width >= canvasWidth) {
this.moveX *= -1;
// x축 반대 방향으로 변경
}
if (this.y <= 0 || this.y + this.height >= canvasHeight) {
this.moveY *= -1;
// y축 반대 방향으로 변경
}
this.x가 0 이하일 경우, X 축 기준 맵 왼쪽 모서리에 닿거나 왼쪽 맵을 벗어나는 상황 입니다.
this.x + this.width가 canvasWidth 일 경우, X 축 기준 맵 오른쪽 모서리에 닿거나 오른쪽 맵을 벗어나는 상황 입니다.
(Y 축 또한 동일하게 작동합니다)
그 경우 맵을 벗어나지 않도록 하기 위해 -1을 곱해줍니다.
위와 같은 처리로 초반에 결정된 X축 이동 속도, Y축 이동 속도로 황금 고블린이 맵 전체에서 랜덤하게 이동시킬 수 있습니다.
15일은 발표 준비만 해서 딱히 한 내용이 없다
변경 점 발생 : 삼각함수 사용
발표 15일 발표 준비 중 황금 고블린에 문제가 있다는 사실을 파악하고 문제 해결을 진행했다. 어떤 문제였냐면,
기존 코드를 바탕으로 황금 고블린이 이동을 하면 최대 8 * root(2) 만큼의 속도로 이동하거나, 최소 0으로
황금 고블린 마다 속도가 달라지는 문제가 발생했다.
따라서, 위의 문제를 해결하기 위해 삼각 함수를 사용했다.
(전체 코드 밑에 설명 있음)
export class SpecialMonster {
constructor(path, specialMonster, specialMonsterImage, level) {
// 생성자 안에서 몬스터의 속성을 정의한다고 생각하시면 됩니다!
if (!path) {
throw new Error('몬스터가 이동할 경로가 필요합니다.');
}
this.specialMonsterInfo = specialMonster;
this.monsterId = this.specialMonsterInfo.monsterId;
this.path = path; // 몬스터가 이동할 경로
this.currentIndex = 0; // 몬스터가 이동 중인 경로의 인덱스
this.x = path.x; // 몬스터의 x 좌표 (최초 위치는 경로의 첫 번째 지점)
this.y = path.y; // 몬스터의 y 좌표 (최초 위치는 경로의 첫 번째 지점)
this.width = this.specialMonsterInfo.width; // 몬스터 이미지 가로 길이
this.height = this.specialMonsterInfo.height; // 몬스터 이미지 세로 길이
this.speed = this.specialMonsterInfo.speed; // 몬스터의 이동 속도
this.image = specialMonsterImage; // 몬스터 이미지
this.level = level; // 몬스터 레벨
this.setRandomDirection();
this.init(level);
}
init(level) {
this.maxHp = this.specialMonsterInfo.maxHp + 10 * level; // 몬스터의 현재 HP
this.hp = this.maxHp; // 몬스터의 현재 HP
this.attackPower = this.specialMonsterInfo.attackPower + 5 * level; // 몬스터의 공격력 (기지에 가해지는 데미지)
}
setRandomDirection() {
let randomAngle = Math.random() * 2 * Math.PI;
this.moveX = Math.cos(randomAngle);
this.moveY = Math.sin(randomAngle);
// 속도의 일관성을 위해 방향 벡터의 크기를 speed로 조정
let magnitude = Math.sqrt(this.moveX * this.moveX + this.moveY * this.moveY);
this.moveX = (this.moveX / magnitude) * this.speed;
this.moveY = (this.moveY / magnitude) * this.speed;
}
move(canvas) {
let canvasWidth = canvas.width;
let canvasHeight = canvas.height;
this.x += this.moveX;
this.y += this.moveY;
if (this.x <= 0 || this.x + this.width >= canvasWidth) {
this.moveX *= -1;
// x축 반대 방향으로 변경
}
if (this.y <= 0 || this.y + this.height >= canvasHeight) {
this.moveY *= -1;
// y축 반대 방향으로 변경
}
}
draw(ctx) {
ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
ctx.font = '12px Arial';
ctx.fillStyle = 'white';
ctx.fillText(`(레벨 ${this.level}) ${this.hp}/${this.maxHp}`, this.x, this.y - 5);
}
}
생성자에서 호출된 setRandomDirection으로
setRandomDirection() {
let randomAngle = Math.random() * 2 * Math.PI;
this.moveX = Math.cos(randomAngle);
this.moveY = Math.sin(randomAngle);
// 속도의 일관성을 위해 방향 벡터의 크기를 speed로 조정
let magnitude = Math.sqrt(this.moveX * this.moveX + this.moveY * this.moveY);
this.moveX = (this.moveX / magnitude) * this.speed;
this.moveY = (this.moveY / magnitude) * this.speed;
}
0 ~ 360도 사이의 랜덤한 각도를 만든 후
Math.cos()으로 X 축 이동 방향을 결정하고,
Math.sin()으로 Y 축 이동 방향을 결정해줬다.
그후, root((X축 이동 방향)^2 + (Y축 이동 방향)^2)로 XY 축 이동에 따른 방향 백터의 크기를 계산하고,
this.moveX = (this.moveX / magnitude) * this.speed;
this.moveY = (this.moveY / magnitude) * this.speed;
(this.moveX / mangnitude)와 (this.moveY / mangnitude)로 이동 방향 백터를 정규화 해준 후,
* this.speed로 속도를 일정하게 만들어줍니다.