htmlでRPGのマップ作成サイトを作る時にchatGPTと奮闘した話

## htmlでRPGのマップ作成サイトを作る時にchatGPTと奮闘した話
先日、私が作成しているhtmlのRPGで、マップの追加をするとき、それまではドット絵エディターである、『Pixel Studio[(アップルストアの方](https://apps.apple.com/jp/app/pixel-studio-for-pixel-art/id1477015249?mt=12)　[グーグルプレイの方)](https://play.google.com/store/apps/details?id=com.pixelnetwork&hl=ja&gl=US)というものを使ってマップを描いていたのですが、面倒になってきました。なのでhtmlで、マップの画像と、当たり判定用のリストを作るコードを書こうと思ったのですが、技術が足りないのでchatGPTにお願いしました。でも、「画像をペイントできるドット絵メーカーを作ってください」「画像"が"ペイントされるのではなくて、画像"を"ペイントできるようにしてください」など...
ちなみに以下が初号機です。
![スクリーンショット 2024-02-10 5.31.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690869/e3ab6ce5-37d1-53a2-9ab5-c32e0ac0d0f9.png)
なんか違う...と思い、１時間近く奮闘していたところ、ようやくいい感じのものができたのでソースコードを紹介します。
因みに以下が完成図です。
![スクリーンショット 2024-02-10 5.35.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690869/a9f67c42-7a59-7167-cafb-16f1dd299e9a.png)
というわけで早速コード紹介〜
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pixel Art Editor</title>
<style>
  canvas {
    border: 1px solid black;
    cursor: crosshair;
  }
</style>
</head>
<body>
<input type="file" id="fileInput0" accept="image/*">
<br>
<canvas id="canvas" width="640" height="640"></canvas>
<br>
<button onclick="downloadImage()">Download Image</button>
<button onclick="showList()">Show List</button>
<div id="listContainer"></div>

<script>
var paintList = []; // ペイントされた情報を格納する配列
var gridSize = 20; // リストのサイズ
var pixelSize = 32; // 1つのピクセルのサイズ

window.onload = function() {
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    var fileInput0 = document.getElementById('fileInput0');
    var img1 = new Image();
    var img0 = new Image();
    var isPainting = false; // ペイント中かどうかを示すフラグ
    
    // 2つの画像アップローダーにイベントリスナーを追加
    
    fileInput0.addEventListener('change', function(e) {
        handleFileUpload(e, img0);
    });
    
    function handleFileUpload(e, img) {
        var file = e.target.files[0];
        var reader = new FileReader();
        
        reader.onload = function(event) {
            img.onload = function() {
                drawGrid();
            }
            img.src = event.target.result;
        }
        reader.readAsDataURL(file);
    }
    
    function drawGrid() {
        for (var x = 0; x < canvas.width; x += pixelSize) {
            for (var y = 0; y < canvas.height; y += pixelSize) {
                ctx.strokeStyle = '#ccc';
                ctx.strokeRect(x, y, pixelSize, pixelSize);
            }
        }
    }
    
    // キャンバスにペイントする機能を追加
    canvas.addEventListener('mousedown', function(e) {
        isPainting = true;
        drawPixel(e);
    });
    
    canvas.addEventListener('mousemove', function(e) {
        if (isPainting) {
            drawPixel(e);
        }
    });
    
    canvas.addEventListener('mouseup', function() {
        isPainting = false;
    });
    
    function drawPixel(e) {
        var gridX = Math.floor((e.clientX - canvas.offsetLeft) / pixelSize) * pixelSize;
        var gridY = Math.floor((e.clientY - canvas.offsetTop) / pixelSize) * pixelSize;
        ctx.imageSmoothingEnabled = false; // 画像の拡大時に品質を維持
        if (img1.complete) {
            ctx.drawImage(img1, gridX, gridY, pixelSize, pixelSize);
            paintList.push({ x: gridX, y: gridY, id: 1 }); // ペイントされた情報をリストに追加
        }
        if (img0.complete) {
            ctx.drawImage(img0, gridX, gridY, pixelSize, pixelSize);
            paintList.push({ x: gridX, y: gridY, id: 0 }); // ペイントされた情報をリストに追加
        }
    }
};

function showList() {
    var listContainer = document.getElementById('listContainer');
    listContainer.innerHTML = ''; // 一旦リストをクリア
    
    // 初期状態のリストを作成
    var initialList = [];
    for (var i = 0; i < gridSize; i++) {
        var row = [];
        for (var j = 0; j < gridSize; j++) {
            row.push(0);
        }
        initialList.push(row);
    }
    
    // ペイントされた情報を元にリストを更新
    paintList.forEach(function(item) {
        var x = Math.floor(item.x / pixelSize);
        var y = Math.floor(item.y / pixelSize);
        initialList[y][x] = 1;
    });
    
    // リストを表示
    initialList.forEach(function(row) {
        var listItem = document.createElement('div');
        listItem.textContent = row.join(', ');
        listContainer.appendChild(listItem);
    });
}

function downloadImage() {
    var canvas = document.getElementById('canvas');
    var link = document.createElement('a');
    link.download = 'pixel_art.png';
    link.href = canvas.toDataURL('image/png');
    link.click();
}
</script>
</body>
</html>
```
技術的な解説は...面倒なのでGPTニキにでも聞いてください。とにかくこれでいい感じになります。
## 使い方(初心者用)
上に書いたコードをコピーしてメモ張やテキストエディタ、VScodeなど、お好きなアプリに貼り付け、保存します。windowsの方は、エクスプローラー → 表示(上のタブ) → 「拡張子を表示」に、チェックを入れてください。テキストエディタに戻って、任意の方法で保存します。保存されたファイルの拡張子を、.htmlに置き換えます。
完了したら、ファイルを開いてください。
### ツールの使い方
まず、画像をアップロードします。そしたら、canvasにグリッドが表示されます。好きなようにペイントしてください。描いたところを1としたリストを生成する機能もついています。（デフォルトでは0で埋め尽くされています）
描き終わったら、画面下部の、showlistと書かれたところをクリックするとリストが表示され、downloadと書かれたところを押すとダウンロードされます。
## カスタマイズについて
こちらのコードは、
画面サイズ　640px * 640px
ペイントとする画像のサイズ 32px四方
グリッド　20 * 20
となっていますが、お使いの環境・目的に合わせてカスタマイズできます。
#### 画面サイズの変更
17行目の、
```
<canvas id="canvas" width="640" height="640"></canvas>
```
を変更します。widthとheightの値を変更するとエディターのサイズを変更できます。※どちらも同じ値にしてください。
#### ペイントする画像のサイズ
26行目の、
```
var pixelSize = 32; // 1つの画像のサイズ
```
を編集してください。一つのセルサイズが変更されます。
#### グリッドサイズ(リストのサイズ)
25行目の
```
var gridSize = 20; // リストのサイズ
```
ここを編集してください。画面サイズ÷画像サイズの値になるように設定しないとバグります。

#### 質問はこちら
著者のXのDMにて質問していただければと思います。