async関数とawaitを用いて画像ファイルを読み込んだあとにゲーム画面を描画するようにしている。
クリックしたセル位置に読み込んだ画像をランダムで表示させている。
ソースコード
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OTIMONO(04スプライトをステージに描画する)</title>
<style>
*{
margin: 0;
padding: 0;
}
body{
margin: 0 50px;
}
</style>
<script src="main.js" type="text/javascript"></script>
</head>
<body>
<canvas id="canvas" width="512" height="512"></canvas>
</body>
</html>
main.js
// キャンバスでのマウスイベントの状態を表示する
let canvas = null;
let g = null;
let pos = {x:0, y:0}; // キャンバス上のマウス座標
let cpos = {x:0, y:0}; // マウス座標から得られるセル位置
let isMouseDown = false; // マウスを押しているか?
const CELL_SIZE = 64; // パズルキャラのサイズ(64x64ピクセル)
const ROW_SIZE = COLUMN_SIZE = 512 / CELL_SIZE; // 行と列に何個並べるか?
const CELL_LENGTH = ROW_SIZE * COLUMN_SIZE; // パズルキャラの数
// ゲームに使う画像ファイル
const image_files = ["null.png", "alien.png", "apple.png", "dog.png", "obake.png", "ultra.png", "usi.png"];
// 画像オブジェクト(画像ファイルをゲームで利用するため)
let images = [];
// ステージ情報配列
let stage = new Array(CELL_LENGTH);
/*
* マウスを動かしている時の処理
*/
const mouseMoveListener = (e) => {
// オフセット位置:キャンバスがブラウザの左上からどれくらいの位置にあるか?(rect.left, rect.top)
const rect = e.target.getBoundingClientRect();
// e.clientXとe.clientYはブラウザ左上からのキャンバスクリック位置なのでオフセット分を引くとキャンバス上の座標が分かる
pos.x = e.clientX - rect.left;
pos.y = e.clientY - rect.top;
// マウス座標からセル位置を求める
cpos.x = Math.floor(pos.x / CELL_SIZE);
cpos.y = Math.floor(pos.y / CELL_SIZE);
};
/*
* マウスボタンを押した時の処理
*/
const mouseDownListener = () => {
isMouseDown = true;
// ステージのクリック位置に画像を設定
const index = Math.floor(Math.random() * (images.length-1)) + 1; // ランダム
stage[cpos.x + cpos.y * COLUMN_SIZE] = index;
console.log(cpos);
};
/*
* マウスボタンを離した時の処理
*/
const mouseUpListener = () => {
isMouseDown = false;
};
/*
* キャンバスにマウス情報を表示(利用していない)
*/
const drawMouseInfo = ()=> {
// 表示する文字列を設定
const mouseDownString = isMouseDown ? "押した!" : "離した!";
const txtPos = `x: ${pos.x} y:${pos.y} ${mouseDownString}`;
// マウス情報を表示する
g.fillStyle = "#555";
g.fillText(txtPos, 150, canvas.height/2);
}
/*
* 背景を表示
*/
const drawBackground = ()=> {
let x = 0, y = 0; // 描画するセル位置
let color1 = "pink", color2 = "skyblue"; // 市松模様のステージ色
for(i=0; i<CELL_LENGTH; i++){
// 1段下がると先頭の色を入れ替える
if(i % 8 == 0) [color1, color2] = [color2, color1];
// 格子状にブロックを表示
x = i % COLUMN_SIZE; // x方向セル位置
y = Math.floor(i / ROW_SIZE); // Y方向セル位置
// 色を交互に設定
bgColor = (i % 2 == 0) ? color1: color2;
g.fillStyle = bgColor;
g.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
}
}
/*
* カーソルを表示
*/
const drawCursor = ()=> {
g.fillStyle = "rgba(128, 128, 128, 0.5)"; // グレー色で透過
g.fillRect(cpos.x * CELL_SIZE, cpos.y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
}
/*
* ステージを表示
*/
const drawStage = ()=> {
for(let i=0; i<CELL_LENGTH; i++){
x = i % COLUMN_SIZE; // x方向セル位置
y = Math.floor(i / ROW_SIZE); // Y方向セル位置
g.drawImage(images[stage[i]], x*CELL_SIZE, y*CELL_SIZE);
}
}
/*
* 画像ファイル読み込み
*/
const loadImages = async ()=> {
const images = [];
const promises = [];
image_files.forEach((url) =>{
const promise = new Promise((resolve)=>{
const img = new Image();
img.addEventListener("load", ()=>{
console.log("loaded " + url);
resolve(); // 読み込み完了通知
});
img.src = "./asset/" + url; // 画像ファイル読み込み開始
images.push(img); // 画像オブジェクト配列に格納
});
promises.push(promise);
});
await Promise.all(promises);
return images;
}
/*
* ゲームのメイン処理(まだゲームではない)
*/
const GameMain = () =>{
// キャンバスクリア
g.clearRect(0, 0, canvas.width, canvas.height);
// ステージ描画
drawBackground();
// カーソル描画
drawCursor();
// ステージ表示
drawStage();
// マウス情報表示
//drawMouseInfo();
// フレーム再描画
requestAnimationFrame(GameMain);
}
/*
* 起動時の処理
*/
window.addEventListener("load", async ()=>{
canvas = document.getElementById("canvas");
g = canvas.getContext("2d");
g.font = "bold 24px System"; // フォントサイズ・フォント種類 設定
// マウスイベント設定
canvas.addEventListener("mousemove", mouseMoveListener, false);
canvas.addEventListener("mousedown", mouseDownListener, false);
canvas.addEventListener("mouseup", mouseUpListener, false);
// 画像ファイルを読み込む
images = await loadImages(image_files);
console.log(images);
// ステージ情報を空にする
stage.fill(0);
// ゲームのメイン処理呼び出し(ゲーム開始)
GameMain();
});
コメント