ゲーム画面の背景は事前にグラフィックソフト等を使って画像ファイル化して読み込むという手法もありますが、模様の類であればプログラムでリアルタイムで描画するほうが通信量が大幅に減り、試行錯誤の調整もやりやすくメンテナンスがかなり楽になります。
以下が実際にゲーム内で使用されている背景です。
HMG大富豪
https://hasemonmon.net/df5/
フエルト地のようなテーブル表面
canvasにベースとなる色を塗ります。
// キャンバス
var w = 320, h = 320; // キャンバスのサイズ
var cv = document.createElement("canvas");
cv.setAttribute("width", w);
cv.setAttribute("height", h);
var ctx = cv.getContext('2d');
ctx.fillStyle = "#45cc82"; // 単色塗り
ctx.fillRect(0, 0, w, h);
加工のためにcanvasからピクセルデータ配列を取得します。
1ピクセル毎にR,G,B,Aの4データが有りますので、配列サイズはピクセル数*4になります。
// キャンバスからピクセルデータ配列を取得
var imageData = ctx.getImageData(0, 0, w, h);
var arrRGBA = imageData.data;
ピクセル単位でノイズを加えていきます。
ノイズは元の画像の色に対し色の濃さを%で変化させたものになります。
1ピクセル毎に4つのデータですのでforループは4カウントアップしていきます。
// ピクセルデータ配列を加工
for (var i = 0, l = arrRGBA.length; i < l; i += 4) {
var per = 0;
// 色を変化させる%を乱数で決定(実際の出力を見ながらここで微調整を加えていく)
var rnd = Math.random();
if (rnd < 0.2) {
per = Math.random() * 5 + 3;
} else if (rnd > 0.8) {
per = Math.random() * -2 - 1;
}
// 色を%変化させる
arrRGBA[i + 0] = colorPer(arrRGBA[i + 0], per);
arrRGBA[i + 1] = colorPer(arrRGBA[i + 1], per);
arrRGBA[i + 2] = colorPer(arrRGBA[i + 2], per);
arrRGBA[i + 3] = arrRGBA[i + 3];
}
// 色を%で変化させる関数
function colorPer(value, per) {
if (per === 0) return value;
var newValue = value + Math.floor(value * per / 100);
newValue = (newValue > 255) ? 255 : newValue;
newValue = (newValue < 0) ? 0 : newValue;
return newValue;
}
キャンバスへピクセルデータを書き戻します。
ctx.putImageData(imageData, 0, 0);
これでフエルト地の立体的な表面が表現できました。
ライティングによる明暗
先ほどの処理ループ部分にライティングによる明暗処理を追加します。
var iy = 4 * 320; // y毎の配列要素数
var cx = 160; // グラデーションの中心x座標
var cy = 160; // グラデーションの中心y座標
for (var i = 0, l = arrRGBA.length; i < l; i += 4) {
var per = 0;
var rnd = Math.random();
if (rnd < 0.2) {
per = Math.random() * 5 + 3;
} else if (rnd > 0.8) {
per = Math.random() * -2 - 1;
}
// 円グラデーション
var x = (i % iy) / 4; // iからピクセル座標xを計算
var y = Math.floor(i / iy); // iからピクセル座標yを計算
var r = Math.sqrt(Math.pow(cx - x, 2) + Math.pow(cy - y, 2)); // グラデーションの中心からの距離を計算
per += -((r - 40) / 5); // 距離により色を変化させる%を変化させる
arrRGBA[i + 0] = colorPer(arrRGBA[i + 0], per);
arrRGBA[i + 1] = colorPer(arrRGBA[i + 1], per);
arrRGBA[i + 2] = colorPer(arrRGBA[i + 2], per);
arrRGBA[i + 3] = arrRGBA[i + 3];
}
これでライティングの明暗が表現できました。