今回は敵の攻撃を実装します。
ただ、かなり難しいと思います。
sketch.js
// プレイヤーの座標
let x, y;
// 四角のサイズ
let gridSize = 40;
let bullets = [];
let enemy_bullets = [];//今回書き加えたところです
// 今回書き加えたところです
let enemies = [];
let rows = 5; // 行
let cols = 10; // 列
let enemyWidth = 40; // 敵の幅
let enemyHeight = 20; // 敵の高さ
let spacing = 10; // 敵と敵のスペース
let enemySpeed = 0.5;
let direction = 1; // 移動の方向(1: 右、-1: 左)
// スコア変数
let score = 0;
// 最初に一回だけ読み込む
function setup() {
createCanvas(800, 400);
x = width / 2;
y = height - 40;
// 敵を初期化
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
// 敵それぞれの列
let x = col * (enemyWidth + spacing) + 50;
// 敵それぞれの行
let y = row * (enemyHeight + spacing) + 50;
// 敵オブジェクトを動的配列に追加
enemies.push(new Enemy(x, y, enemyWidth, enemyHeight, enemySpeed));
}
}
}
// 描画
function draw() {
background(220);
let shouldReverse = false;
// 弾の表示と移動
for (let i = bullets.length - 1; i >= 0; i--) {
bullets[i].display();
bullets[i].move();
// 弾が見えなくなったら削除
if (!bullets[i].isVisible) {
bullets.splice(i, 1);
}
}
// 敵の弾の表示と移動 今回書き加えたところです
for (let i = enemy_bullets.length - 1; i >= 0; i--) {
enemy_bullets[i].display();
enemy_bullets[i].move();
// 弾が見えなくなったら削除
if (!enemy_bullets[i].isVisible) {
enemy_bullets.splice(i, 1);
}
}
// キャラクター描画関数
drawCharacter();
// 敵の表示と移動
for (let i = enemies.length - 1; i >= 0; i--) {
enemies[i].show();
enemies[i].move(direction);
// 各敵が発射を試みる 今回書き加えたところです
enemies[i].tryShoot();
// もし端に達していたら反転フラグを立てる
if (enemies[i].x > width - enemies[i].w || enemies[i].x < 0) {
shouldReverse = true;
}
// 弾と敵の当たり判定
for (let j = bullets.length - 1; j >= 0; j--) {
if (hitTest(bullets[j], enemies[i])) {
// 当たったら両方とも削除
bullets.splice(j, 1);
enemies.splice(i, 1);
score += 10; // スコアを10点加算
break; // 敵が消えたのでループから抜ける
}
}
}
// 端に到達したら方向を反転し、隊列を下に移動させる
if (shouldReverse) {
direction *= -1; // 方向を反転
for (let i = 0; i < enemies.length; i++) {
enemies[i].shiftDown(); // 敵を下に移動
}
}
// スコアを左上に表示
fill(0);
textSize(24);
text("Score: " + score, 10, 30);
}
// 弾と敵の当たり判定
function hitTest(bullet, enemy) {
// 弾が敵の矩形内にあるかを確認
return (
bullet.x > enemy.x &&
bullet.x < enemy.x + enemy.w &&
bullet.y > enemy.y &&
bullet.y < enemy.y + enemy.h
);
}
// キャラクター描画関数
function drawCharacter() {
fill('red');
square(x, y, gridSize);
}
// キーボードイベントを処理する関数
function keyPressed() {
switch (keyCode) {
// 左に移動
case LEFT_ARROW:
x = max(x - gridSize, 0);
break;
// 右に移動
case RIGHT_ARROW:
x = min(x + gridSize, width - gridSize);
break;
// 上に移動
case UP_ARROW:
y = max(y - gridSize, 0);
break;
// 下に移動
case DOWN_ARROW:
y = min(y + gridSize, height - gridSize);
break;
}
if (key == ' ') {
let bullet = new Bullet(x + 20, y);
bullets.push(bullet);
}
redraw(); // 描画を更新
}
sprite.js
//今回書き加えたところです
class Enemy_Bullet{
constructor(x,y){
this.x =x;
this.y =y;
this.speedY = 5;
this.isVisible = true;
}
move(){
this.y += this.speedY;
if (this.y < 0) {
this.isVisible = false;
}
}
display(){
if (this.isVisible){
fill('blue');
ellipse(this.x, this.y, 10, 10);
}
}
}
// 敵クラス
class Enemy {
constructor(x, y, w, h, speed) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.speed = speed;
//今回書き加えたところです
this.lastShotTime = floor(random(0, 480));; // 各敵ごとの最後の発射時間
this.shootInterval = random(60, 480);
}
// 敵を描画
show() {
fill(255, 0, 0);
rect(this.x, this.y, this.w, this.h);
}
// 敵を移動させる
move(direction) {
this.x += direction * enemySpeed;
}
// 敵を下に移動させる
shiftDown() {
this.y += 20;
}
//今回書き加えたところです
tryShoot() {
// 各敵ごとの発射タイミングを判定
if (frameCount - this.lastShotTime > this.shootInterval) {
let e_bullet = new Enemy_Bullet(this.x + this.w / 2, this.y);
enemy_bullets.push(e_bullet);
this.lastShotTime = frameCount;
this.shootInterval = random(60, 480); // 次の発射間隔をランダムに再設定
}
}
}
主な処理はtryShootです。
発射自体は自機の弾を発射するのと同じです。(方向が違いますが)
問題は発射タイミングです。
ここではframeCountを使っています。
frameCountはシステム変数と呼ばれているもので、プログラムの開始以降に表示されたフレームの数が格納されています。
これと、前回の値を格納したlastShotTimeの引いた数がshootIntervalの値が大きかったら敵は弾を発射します。
lastShotTimeとshootIntervalは初期化、shootIntervalは弾発射の最後にある値を入れていますが、これはp5.jsで使うランダム変数です。
以前勉強したものとは違うもので、これは前者の値に最小値、後者に最大値を設定することで、最小値と最大値の間でランダムの数字を出します。
なので、この数字をいじることで敵の弾を出す頻度を調整することができます。
コメント