今日のエッセイ
気まぐれなゲーム作りをしました。
JavaScriptのプログラムです。
ブラウザで開くだけで、オンラインでなくてもプレイできます。
ゲームタイトル:「Delta and Square」
三角形の宇宙戦闘機っぽいのが、四角形を撃つというシューティング・パズルゲームです。
カーソルキーで操作してスペースキーを押すと、緑の三角形が移動して、ピンクのショットを撃ちます。
オレンジの四角形に当たると、スコアがアップします。
Eはエネルギー数値。
四角形が画面にいる間、その数だけどんどんと減っていきます。
1つの場合は1つずつ、2つの場合は2つずつです。
画面に四角形が無い間は減りません。
四角形にショットを当てると20回復します。
スコアが2000になると100、
4000になると200回復します。
エネルギーが0になるとゲームオーバーです。
表示が出てゲームが止まります。
○プログラム
HTML(shooting.html):
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>シューティングゲーム</title>
<style>
canvas {
display: block;
margin: auto;
background-color: #222;
}
</style>
</head>
<body>
<canvas id="gameScreen" width="730" height="550"></canvas>
<script src="shooting.js"></script>
</body>
</html>
<script src="shooting.js"></script>でJavaScriptを呼び出しています。
この場合、スクリプトのファイル名はshooting.jsです。
HTMLと同じフォルダに置きます。
別の所に置く場合はその場所を指定します。
例えば、Homeのgameフォルダの場合は
<script src="/Home/user-name/game/shooting.js"></script>
となります。
画面のサイズはcanvasタグで設定します。
<canvas id="gameScreen" width="730" height="550"></canvas>
JavaScript(shooting.js):
const canvas = document.getElementById('gameScreen');
const ctx = canvas.getContext('2d');
// プレイヤーの設定
const player = {
x: canvas.width / 2,
y: canvas.height - 50,
width: 50,
height: 50,
speed: 5,
bullets: []
};
// 敵の設定
const enemies = [];
// 弾丸の設定
const bulletSpeed = 10;
const bulletSize = 9;
// 敵を追加する関数
function addEnemy() {
const enemy = {
x: Math.random() * (canvas.width - 50),
y: 0,
width: 50,
height: 50,
speed: 2
};
enemies.push(enemy);
}
function addEnemyb() {
const enemy = {
x: Math.random() * (canvas.width - 100),
y: 0,
width: 100,
height: 100,
speed: 3
};
enemies.push(enemy);
}
// キー入力の処理
const keys = {};
document.addEventListener('keydown', (e) => {
keys[e.code] = true;
});
document.addEventListener('keyup', (e) => {
keys[e.code] = false;
});
// プレイヤーの描画 fillRect:塗りつぶし四角
function drawPlayer() {
ctx.fillStyle = '#00FF33';
//ctx.fillRect(player.x, player.y, player.width, player.height);
ctx.beginPath();
ctx.moveTo(player.x, player.y);
ctx.lineTo(player.x-25, player.y+50);
ctx.lineTo(player.x+25, player.y+50);
ctx.fill();
ctx.closePath();
}
// 敵の描画
function drawEnemies() {
ctx.fillStyle = '#FF9900';
for (let enemy of enemies) {
ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
}
}
// 弾丸の描画
function drawBullets() {
ctx.fillStyle = '#FFAAAA';
for (let bullet of player.bullets) {
ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
}
}
function drawScore() {
ctx.font = "25px Arial";
ctx.fillStyle = "#00DDff";
ctx.fillText("Score:" + score.toFixed(), 550, 40);
}
function drawHp() {
ctx.font = "25px Arial";
ctx.fillStyle = "#00DD00";
ctx.fillText("E:" + hp.toFixed(), 50, 40);
}
function drawGameover() {
ctx.font = "50px Arial";
ctx.fillStyle = "#00FF99";
ctx.fillText("Game Over. Try again.", 100, 350);
}
let score=0;
let hp=2000;
var er=0;
let gameover=false;
// ゲームの更新
function update() {
er=Math.floor(Math.random()*3);
// プレイヤーの移動
if (keys['ArrowLeft'] && player.x-25 > 0) {
player.x -= player.speed;
}
if (keys['ArrowRight'] && player.x-25 < canvas.width - player.width) {
player.x += player.speed;
}
if (keys['ArrowUp'] && player.y > 0) {
player.y -= player.speed;
}
if (keys['ArrowDown'] && player.y < canvas.height - player.height) {
player.y += player.speed;
}
// 弾丸の発射
if (keys['Space']) {
const bullet = {
x: player.x-25 + player.width / 2 - bulletSize / 2,
y: player.y,
width: bulletSize,
height: bulletSize,
speed: bulletSpeed
};
player.bullets.push(bullet);
keys['Space'] = false;
}
// 弾丸の移動
for (let bullet of player.bullets) {
bullet.y -= bullet.speed;
}
// 敵の移動
for (let enemy of enemies) {
enemy.y += enemy.speed;
if(enemy.y > canvas.height){
enemies.splice(0,1);
}
}
// 弾丸と敵の衝突判定
for (let i = 0; i < player.bullets.length; i++) {
for (let j = 0; j < enemies.length; j++) {
const bullet = player.bullets[i];
const enemy = enemies[j];
if (bullet.x < enemy.x + enemy.width &&
bullet.x + bullet.width > enemy.x &&
bullet.y < enemy.y + enemy.height &&
bullet.y + bullet.height > enemy.y) {
player.bullets.splice(i, 1);
enemies.splice(j, 1);
score+=100;
if(score==2000){hp+=100;}
if(score==4000){hp+=200;}
hp+=20;
break;
}
}
}
// 敵の生成
if (Math.random() < 0.02 && er!=1) {
addEnemy();
}
if (Math.random() < 0.02 && er==1) {
addEnemyb();
}
hp-=enemies.length;
if(hp < 1){
hp=0;
gameover=true;
}
// 画面のクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
// オブジェクトの描画
drawPlayer();
drawEnemies();
drawBullets();
drawScore();
drawHp();
if(gameover==true){
drawGameover();
}
// ループ
if(gameover==false){
requestAnimationFrame(update);
}
}
// ゲームの開始
update();
描画には画像を用意することなく、図形を描くことで表示します。
// プレイヤーの描画 fillRect:塗りつぶし四角
function drawPlayer() {
ctx.fillStyle = '#00FF33';
//ctx.fillRect(player.x, player.y, player.width, player.height);
ctx.beginPath();
ctx.moveTo(player.x, player.y);
ctx.lineTo(player.x-25, player.y+50);
ctx.lineTo(player.x+25, player.y+50);
ctx.fill();
ctx.closePath();
}
ctx.fillRect()は四角形を描く場合の関数です。
この場合は使わないので、「//」でコメントアウトしています。
ctx.beginPath()以下が三角形を描く関数になっています。
function drawScore() {
ctx.font = "25px Arial";
ctx.fillStyle = "#00DDff";
ctx.fillText("Score:" + score.toFixed(), 550, 40);
}
drawScore()は、スコア表示用関数です。
ctx.fillText()の「score.toTixed」が変数です。
変数scoreに値を入れることで画面に表示されます。
数値の「550,40」は表示位置を表します。
for (let enemy of enemies) {
enemy.y += enemy.speed;
if(enemy.y > canvas.height){
enemies.splice(0,1);
}
}
四角形の敵の移動を表示する部分です。
敵は配列enemiesに格納されます。
配列・・・箱のような入れ物で一つずつ入ります。
enemies.lengthで配列の長さを見ることができます。
格納された敵は消えない限りそのままなので、
画面の外に消えた場合は消去します。
enemies.splice()関数を使います。
player.bullets.splice(i, 1);
enemies.splice(j, 1);
ショットが当たった時も弾丸と敵が消えるように設定しています。
if(gameover==false){
requestAnimationFrame(update);
}
requestAnimationFrame()関数でゲームをループしています。
この場合は、ゲームオーバーのフラグの変数「gameover」がfalseである限りループします。
フラグがtrueになると、ゲームは止まります。