生成した絵の色を3色に減らす:ゲーム素材に合わせる
遊びをつくる執筆にClaudeを使用しています。

生成した絵をゲームに入れようとすると、絵だけが画面から浮くことがあります。細かなグラデーションや微妙な中間色が、小さく表示したときにノイズに見えたり、背景に溶けたりするためです。色数を3色まで減らすと、素材の統一感を出しやすくなります。一方で、減らし方を間違えると、主役の形まで潰れてしまいます。 この記事で確かめるのは、色数を減らす操作そのものではありません。「どの3色を残すか」の決め方で、ゲームの実寸表示での読み取りやすさが変わるかです。同じ1枚の絵に3通りの選び方を当てはめ、同じ条件で見比べる設計書として書いています。結果は載せていません。手順を踏めば、手元の素材について答えが出ます。 たとえば、生成した宝箱の絵を32ピクセル四方ほどのアイテムとして使う場面を考えてみます。茶色の箱、金の留め具、影の3色なら成立しそうです。ただ、絵の中で面積が大きい色を機械的に拾うと、茶色の濃淡ばかりが選ばれ、金の留め具が消えるかもしれません。確かめたいのはこの違いです。
問いを「3色の選び方」に絞る
減色には、変えられる要素がいくつもあります。色の数、縮小サイズ、色の距離の測り方、ディザ(点の散らし)の有無、残す色の選び方などです。一度に動かすと原因が分からなくなるので、今回は次のように固定します。
- 色数は3色に固定します。透過部分は色に数えません。
- 縮小サイズは素材ごとに決めて固定します(例:アイテムは32×32、キャラクターは64×64)。
- ディザはかけません。
- 各ピクセルは、RGB空間で最も近い色に割り当てます。
動かすのは「3色の選び方」だけです。次の3方式を比べます。
- A:明度3分位、3色の決め方:画素を明るさ順に並べ、3等分した各グループの平均色、想定される強み:手間がなく、暗・中・明の段差が自動でできる、想定される弱み:平均で彩度が落ち、くすんだ色になりやすい
- B:役割で手選び、3色の決め方:「輪郭・影」「本体」「ハイライト・差し色」を人が選ぶ、想定される強み:主役の特徴色を残せる、想定される弱み:人の好みが入り、再現しにくい
- C:ゲームの背景色から逆算、3色の決め方:背景と十分に離れた明度の3色を先に決め、絵を寄せる、想定される強み:背景との分離を最優先できる、想定される弱み:元の絵の雰囲気から離れることがある
強みと弱みは予想です。どれが優れているかは、この後の手順で記録して判断します。
準備するもの
- 素材を3種類。キャラクター、背景タイル、アイテムのように、役割の違うものを選びます。生成した絵なら何でも構いません。透過PNGがあれば、透過の扱いも確認できます。
- ゲームの実際の背景色を2種類。昼の明るい面と夜の暗い面のように、明度が離れたものを選びます。作成中のゲームがなければ、作りたい画面の色を仮に決めておきます。
- ゲームでの実寸。何ピクセルで表示するかを先に決めます。表示は最近傍補間(ぼかさずに拡大する方法)に統一します。ぼかして拡大すると、減色の差が見えにくくなります。
- 記録用のシート。後述の表を、紙でも表計算でも用意します。
- 下のHTMLファイル。保存して、ブラウザで開くだけで動きます。
素材の権利や利用条件は、使っている生成サービスの規約に左右されます。公開前に、そのサービスの公式案内で確認してください。
手順:3つの選び方で減色する
次の最小ツールは、画像を読み込んで64ピクセル幅に縮小し、指定した3色で最近傍に割り当てます。「明度3分位で自動」を押すと方式Aの3色が入ります。色の入力欄を直接変えると、方式BやCを試せます。外部ライブラリもサーバーも使いません。
<input type="file" id="f" accept="image/*">
<input type="color" id="c0" value="#1b2a41">
<input type="color" id="c1" value="#c9a227">
<input type="color" id="c2" value="#f4efe6">
<button id="auto">明度3分位で自動</button><br>
<canvas id="cv" style="image-rendering:pixelated;width:256px;background:#456"></canvas>
<script>
const $=i=>document.getElementById(i), cx=$('cv').getContext('2d',{willReadFrequently:true});
const W=64; let base=null;
const rgb=h=>[1,3,5].map(i=>parseInt(h.substr(i,2),16));
const hex=a=>'#'+a.map(v=>Math.round(v).toString(16).padStart(2,'0')).join('');
const lum=p=>0.299*p[0]+0.587*p[1]+0.114*p[2];
$('f').onchange=async e=>{
const b=await createImageBitmap(e.target.files[0]), H=Math.round(W*b.height/b.width);
$('cv').width=W; $('cv').height=H;
cx.imageSmoothingEnabled=false; cx.drawImage(b,0,0,W,H);
base=cx.getImageData(0,0,W,H); render();
};
function px(){ const l=[]; for(let i=0;i<base.data.length;i+=4)
if(base.data[i+3]>=128) l.push(Array.from(base.data.slice(i,i+3))); return l; }
$('auto').onclick=()=>{
if(!base) return;
const l=px().sort((a,b)=>lum(a)-lum(b)), n=Math.floor(l.length/3);
[0,1,2].forEach(k=>{
const g=l.slice(k*n,k===2?l.length:(k+1)*n);
$('c'+k).value=hex([0,1,2].map(j=>g.reduce((s,p)=>s+p[j],0)/g.length));
});
render();
};
['c0','c1','c2'].forEach(i=>$(i).oninput=render);
function render(){
if(!base) return;
const pal=['c0','c1','c2'].map(i=>rgb($(i).value)), out=new ImageData(base.width,base.height);
for(let i=0;i<base.data.length;i+=4){
if(base.data[i+3]<128) continue;
let best=0,bd=1e9;
pal.forEach((c,k)=>{const d=[0,1,2].reduce((s,j)=>s+(c[j]-base.data[i+j])**2,0); if(d<bd){bd=d;best=k;}});
out.data.set([...pal[best],255],i);
}
cx.putImageData(out,0,0);
}
</script>アルファ値が128未満の画素は色の集計にも描画にも含めていません。透過部分が黒や白の色として数えられるのを避けるためです。
3方式の作り方
方式A(明度3分位):素材を読み込み、ボタンを押します。出た3色の値を記録し、画面を保存します。
方式B(役割で手選び):元の絵を見て、次の順に決めます。
- 輪郭や影になる最も暗い色を1つ選びます。
- 面積が最も大きい本体の色を1つ選びます。
- その素材を見分ける決め手になる色を1つ選びます(宝箱なら金の留め具、キャラクターなら髪や目の色)。
決め手の色は、面積が小さくても入れます。ここが方式Aと最も違う点です。
方式C(背景から逆算):ゲームの背景色を先に決め、その背景と明度が離れた3色を選びます。明るい背景なら暗めの3色、暗い背景なら明るめの3色が候補になります。色相は元の絵に近づけます。
どの方式も、3色が決まったら16進の値を必ず記録します。後から同じ結果を再現するためです。
記録の取り方
評価は、拡大した状態ではなく、ゲームでの実寸で行います。減色の良し悪しは、拡大すれば見分けがつくのに、実寸では潰れる、という形で現れやすいからです。
組み合わせは「素材3種 × 方式3つ × 背景2種」で18通りです。それぞれを実寸で並べ、次の3項目を「はい/いいえ」で記録します。
- 形の判別、問い:2秒見て、何が描かれているか言えますか
- 背景との分離、問い:背景の上で、輪郭が途切れず追えますか
- 素材どうしの区別、問い:同じ方式の別素材と並べたとき、役割(敵か、床か)を取り違えませんか
1人で行う場合は、並べる順番をシャッフルし、時間を置いて判定します。作った本人は元の絵を知っているため、見えていなくても「見えた」と判断しがちです。可能なら3人以上に、どの方式かを伏せたまま見せ、何が描かれているかを口頭で答えてもらいます。
もう一つ、グレースケール確認を入れます。画像をグレースケールに変換して同じ3項目を見ます。色相の差に頼らず、明度の差だけで形が読めるかが分かります。色の見え方には個人差があるため、明度差で読める素材のほうが、多くの人にとって読みやすいと考えられます。
結果の読み方と起こりやすい誤り
判断の目安
- Aだけ「形の判別」がいいえ:平均化で特徴色が失われています。Bの「決め手の色」を足すか、3分位の境界を調整します。
- Bが全項目で良く、Cが「形の判別」でだけ落ちる:背景に寄せた結果、絵の個性が薄れています。背景との分離は残したまま、色相を元の絵に近づけます。
- 背景の2種類で結果が逆転する:素材単体では決められません。背景ごとに2パターン用意するか、素材に暗い縁取り(輪郭色)を入れる方向を検討します。
- グレースケールで3項目が落ちる:3色の明度が近すぎます。色相を変えるより、明度の差を広げます。
- どの方式でも落ちる素材がある:色数ではなく、絵の複雑さが原因の可能性が高いです。縮小サイズを上げるか、描き直しを検討します。
差は「どの方式が全体として優れているか」ではなく、素材の役割ごとに合う方式が違うかに注目して読みます。たとえば背景タイルは方式Aで足り、アイテムは方式Bが必要、という分かれ方が出るかもしれません。
起こりやすい誤り
- 拡大して判断する:ここまでの評価は実寸前提です。拡大画面で良く見えても、実寸で評価が変わることがあります。
- 縮小サイズを途中で変える:方式間の差か、縮小の差か分からなくなります。サイズは最初に固定します。
- ぼかして拡大する:輪郭がにじみ、3色の境界が見えなくなります。表示側も最近傍に統一します。
- 透過部分を色として数える:背景の透明画素が黒や白として集計されると、3色のうち1色が無駄になります。サンプルコードのようにアルファで除外します。
- 記録を取らず目分量で調整する:どの3色で良かったかを後から再現できません。16進の値を残します。
- 平均色だけで決める:平均は中間色に寄り、暗部と明部の差が縮みます。自動で出した3色は、出発点として使います。
次の行動
まず、手元の生成画像から素材を1つ選び、上のHTMLで方式Aと方式Bの2通りだけ作って、ゲームの実寸に並べてみてください。そのうえで18通りに広げるかを決めると、無理なく進められます。
3色化した素材を使ったゲームを作ったら、アソバースへ投稿して、他の人の画面でも読み取れるか確かめられます。投稿は、入力、表示の確認、公開の3段階です。素材は相対パスで同梱してください。
