はじめに
2020年8月に開催されたUnity1week(お題:ふえる)で、私はDSのグラフィック(主にポケ〇ン)を再現したアクションゲーム【がんばれ!ソラコくん】を制作しました。本記事では、再現までの過程(?)を備忘録的な意味も少し込めてまとめています。
こんな感じのゲームです
がんばれ!ソラコくん | フリーゲーム投稿サイト #unityroomhttps://t.co/nAMC54lTYd#unity1week#がんばれソラコくん
— フィズ🐬(Yoshi3110) (@FizDv) August 16, 2020
Unityを使って、一週間でDSのポケ〇ンのグラフィックを再現したゲームを作ってみました!!!!!!!!!!!!!!! pic.twitter.com/kiCbeueY8I
たのしい!!!!!!
目次
1.素材の準備
┣ 1-1 主人公
┣ 1-2 マップチップ、他
┗ 1-3 木
2.画面仕様の再現
┣ 2-1 解像度
┣ 2-2 BG面(Canvas)
┗ 2-3 色数
3.ゲーム本編の実装
┣ 3-1 ステージ制作
┣ 3-2 2Dキャラの配置
┗ 3-3 カメラの再現
4.音楽
1.素材の準備
ゲームを作り始める前に、まずは素材を作っていきます。(気分が乗るため)
1-1 主人公
DSのポケ〇ンを見るとわかるように、マップ上にあるオブジェクトの多くはドット絵で描画されています。それらのオブジェクトは斜め上から見下ろした俯瞰で表現されており、”DSのポケ〇ンらしさ”の大半はその表現から感じられるものだと思います。(適当に言っています)
例:DP主人公のドット絵 http://hikochans.com/pixelart/trainer/011
スプライトのサイズは32*32で、停止・歩き(必要なら走り・ジャンプ)のアニメーションを4方向制作します。(キャラクターが左右対称の場合、右向きと左向きは反転で流用できるため3方向)
がんばれ!ソラコくんでは、待機5枚+歩き12枚+ジャンプ6枚の計23枚を使用しています。(ダブり有り)今回は32*32ぴったりに描きましたが、Unityで配置してから少し大きいことに気が付いたので、上下それぞれ4pxほど余白を開けて描くのがおすすめです。
1-2 マップチップ、他
ひとマス16*16を基準にマップチップを描きます。ここは2Dゲーム用のフリー素材マップチップで代用しても問題ないです。
...がんばれ!ソラコくんでは時間の都合で16枚しかマップチップを用意していません(この素材は商用利用でなければ使用してもOKです)

橋や看板など、フィールドに置くものも16px単位で作りましょう。
1-3 木
ここまでポケ〇ン(ダイパ)風で進めてきましたが、木はポケ〇ン(BW)風で制作しました。
DPPtの木は画像1枚ですが、BWの木は画像5枚で構成されていて立体感があります。今回のゲームはアクションゲームだったので、遊びやすさのためにも立体感がわかりやすいBW風の木を採用しました。
※実際に使用しているのは、左から1,4,6,7番目です。
木の画像の組み方は下記ツイートを参考にしてください。
DSっぽい木 pic.twitter.com/Aj0n88KwrU
— フィズ🐬(Yoshi3110) (@FizDv) August 12, 2020
2.画面仕様の再現
DSの画面のスペックはこのようになっています。
画面:3インチ(対角)半透過反射型バックライトつきTFTカラー液晶ディスプレイ×2枚
解像度:256×192、26万色表示
下画面に抵抗膜方式透明アナログタッチパネルつき
(https://ja.wikipedia.org/wiki/%E3%83%8B%E3%83%B3%E3%83%86%E3%83%B3%E3%83%89%E3%83%BCDSより引用)
今回はどちらか片方の画面のみの再現とします。(全く同じものを複製すれば二画面も可能)
2-1 解像度
DSの解像度である256*192をそのままゲームの解像度にしてしまうと、現代のPC画面ではめっっっっちゃ小さくなって見れたものではありません。そこで、2D Pixel Perfect Cameraを使って画面を大きくしつつシャギシャギ感を出します。「3Dゲームなのに”2D”って書いてあるヤツ使えるのかよ!!」と思うかもしれませんが、普通に使えます。
導入についてこの記事で書くと長くなってしまうので、参考になる記事のリンクを貼ります。
http://tsubakit1.hateblo.jp/entry/2018/05/29/003530

Pixel Perfect Camera の設定はこのようにします。
2-2 BG面(Canvas)
2-1を実行すると、UnityのCanvasが初期設定のままではうまく使えない状態になります。これはCanvasをワールド空間に配置することによって解決することが可能です。
Canvas設定の過程
1.ワールド空間にUIを配置するため、2-1で作ったカメラを複製しキャラが写らない場所に移動します。
2.複製したカメラは、クリアフラグを「クリアしない」カリングマスクを「UI」に設定します。
また、Pixel Perfect Camera の Run In Edit Modeを有効にしておきます。
3.ヒエラルキーで右クリック→UI→Canvas を選択し、新しいキャンバスを作成します。(位置ずれ対策のため、UI用カメラとCanvasは同一のオブジェクトの子に設定することをおすすめします。)
4.canvasを「スクリーンスペース - カメラ」に設定し、レンダーカメラに1で複製したカメラを登録、「平面の距離」を10に設定します。
5.ゲームビューの画面を小さくしていき、canvasのrect transformが256:192に近くなったら止めます。
6.canvasのレンダーモードをワールド空間に変更します。
7.お好みで「ユニット毎の動的ピクセル数」を2にします。
(おまけ)解像度合わせに便利なテスト画像を配布します。
canvasの調整時、この画像をPanelにしておくと確認が楽です。
2-3 色数
ネット上にはDSの発色数は26万色という記載が多くありますが、その数字はRGB各64色(18ビットカラー?)の262144色から来ていると考えられます。Unityの標準はRGB各256色の24ビットカラーなので、画面全体に減色処理(ポスタライズ)をすることが必要です。
※どう考えても自己満足の世界です。
エフェクトをかけるうえで参考になるページ
http://cyario.hateblo.jp/entry/2016/04/08/104225
18ビット風に減色するシェーダー(ほぼコピペです...ゆるして...)
Shader"Custom/Posterize"{Properties{_MainTex("Texture",2D)="white"{}_Posterize("階調",int)=256}SubShader{CullOffZWriteOffZTestAlwaysPass{CGPROGRAM#pragmavertexvert#pragmafragmentfrag#include"UnityCG.cginc"structappdata{float4vertex:POSITION;float2uv:TEXCOORD0;};structv2f{float2uv:TEXCOORD0;float4vertex:SV_POSITION;};v2fvert(appdatav){v2fo;o.vertex=UnityObjectToClipPos(v.vertex);o.uv=v.uv;returno;}inlinefloat3transferColor(infloat3srcCol){// test srcCol if the two of r,g,b are 0.floatr=(int(srcCol.r*64))/64.0;floatg=(int(srcCol.g*64))/64.0;floatb=(int(srcCol.b*64))/64.0;fixed3rgb=fixed3(r,g,b);returnfloat3(rgb);}sampler2D_MainTex;float3frag(v2fi):SV_Target{float3color=tex2D(_MainTex,i.uv).rgb;color=transferColor(color);returncolor;}ENDCG}}}3.ゲーム本編の実装
3-1 ステージ制作
UnityTile3Dを使うことで、2Dゲームのマップを作る感覚で立体的なマップを作ることができます。
べんり!!!!!!!!!!!!!!!!
※使い方については配布ページをご覧ください。(投げやり)
3-2 2Dキャラの配置
下の画像のように、実はプレイヤーとオーブは斜めに(常にカメラの方向を向いて)配置されています。
これは「ビルボード」と呼ばれる板ポリなどの平面オブジェクトを常にカメラの方に向ける技術で、今よりも性能の制約がきびしかった時代に多用されていました。(現在でもパーティクルなどに用いられています。)
アタッチするだけでいいかんじにビルボードできるスクリプト
usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassBillBoard:MonoBehaviour{[SerializeField]boolbillDebug;publicboolspin180=true;publicboolDirectionFix=false;[SerializeField]boolx=true;[SerializeField]booly=true;[SerializeField]boolz=true;voidUpdate(){Vector3p=Camera.main.transform.position;//p.y = transform.position.y;transform.LookAt(p);if(billDebug){Debug.Log("local:"+transform.localEulerAngles.y);}if(spin180){if(transform.localEulerAngles.y>90&&transform.localEulerAngles.y<270||DirectionFix==false){transform.Rotate(newVector3(0,180,0));}}else{if(transform.localEulerAngles.y>270&&transform.localEulerAngles.y<90||DirectionFix==false){transform.Rotate(newVector3(0,180,0));}}if(!x)transform.localRotation=Quaternion.Euler(0,transform.localEulerAngles.y,transform.localEulerAngles.z);if(!y)transform.rotation=Quaternion.Euler(transform.localEulerAngles.x,0,transform.localEulerAngles.z);if(!z)transform.rotation=Quaternion.Euler(transform.localEulerAngles.x,transform.localEulerAngles.z,0);}}3-4 カメラの再現
これは完全に主観ですが、デフォルトのカメラから有効視野を狭めた方がポケ〇ンらしさが増すように感じます。(デフォルトは60、がんばれ!ソラコくんは24です)
4.音楽
NintendoDSの同時発音数は16音です...が、今回は完全に無視しました。
多分音源の方が”らしさ”を出すために重要です。「DPPt Soundfont」などで検索するとそれっぽい音源が出てくるのでうまく使いましょう。
※今回、Domino+VirtualMIDIsynth+Pokemon_DPPt_Soundfont.sf2の組み合わせでBGMを作りましたが、エラーとかを無理やりねじ伏せたので解説はなしです。
5.あとがき?
...ここまでつらつら書いてみましたが、いつまでたっても書き切れる気がしないので一旦〆ます。それでも、以上のことを実践すればきっと輝かしいDS風Unityライフが待っているはず!!!!!!!!!!!
なお、筆者は技術記事を書くのが初めてのひよっこぴよぴよなのでいじめないで...
他に知りたいことがあれば追記するので、Twitter(@FizDv)までリプライorDMをください!





