canvas fingting game (3) 角色的攻擊

角色攻擊

為了使角色能攻擊,我們需要在 class 加上 attack box 的值,來決定攻擊敵人的範圍。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Sprite {
constructor({ position, velocity, color = 'red', offset }) {
this.position = position;
this.velocity = velocity;
this.height = 150;
this.width = 50;
this.lastKey;
this.attackBox = {
position: {
x: this.position.x,
y: this.position.y,
},
width: 100,
height: 50,
offset
},
this.color = color;
this.isAttacking;
};

attack() {
this.isAttacking = true;
setTimeout(() => {
this.isAttacking = false;
}, 100)
}
}

如上,我們在 sprite 裡加上 attackbox ,並設定 position 跟 寬高。 isAttacking 則用來決定角色是否處於攻擊狀態,在attack()函式中,會先設定 isAttacking 為true,再用setTimeout 於 100 ms後 設訂為 false;

確認攻擊範圍

為了確認攻擊是否擊中敵人,可以建立一個確認物體碰撞的函式,來確認 attackbox是否在敵人身上。

1
2
3
4
5
6
7
8
function rectangularCollision({ rectangle1, rectangle2 }) {
return (
rectangle1.attackBox.position.x + rectangle1.attackBox.width >= rectangle2.position.x &&
rectangle1.attackBox.position.x <= rectangle2.position.x + rectangle2.width &&
rectangle1.attackBox.position.y + rectangle1.attackBox.height >= rectangle2.position.y &&
rectangle1.attackBox.position.y <= rectangle2.position.y + rectangle2.height
);
}

在 animate 的函式中,就可來確認是否攻擊成功

1
2
3
4
5
6
7
8
9
10
// 確認攻擊範圍是在敵人身上
if (
rectangularCollision({
rectangle1: player,
rectangle2: enemy,
}) &&
player.isAttacking
) {
player.isAttacking = false;
}

事件偵聽

最後就是將 攻擊的動作加入鍵盤事件偵聽, player 我們設為空白鑑攻擊, enemy 則設為↓ 攻擊。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
window.addEventListener('keydown', (e) => {
switch(e.key) {
case 'd':
keys.d.pressd = true;
player.lastKey = 'd';
break;
case 'a':
keys.a.pressd = true;
player.lastKey = 'a';
break;
case 'w':
player.velocity.y = -20;
break;
case ' ':
player.attack();
break;
case 'ArrowRight':
keys.ArrowRight.pressd = true;
enemy.lastKey = 'ArrowRight';
break;
case 'ArrowLeft':
keys.ArrowLeft.pressd = true;
enemy.lastKey = 'ArrowLeft';
break;
case 'ArrowUp':
enemy.velocity.y = -20;
break;
case 'ArrowDown':
enemy.attack();
break;
}
});