竜太のテクニカルメモ

物理やへっぽこなゲーム作りについて易しく解説するよ

Unityでゲームを作ってみる(4)

前回はbarとballの当たり判定をしてballがbarに当たったらballを消去しました.今回はさらにballがbarに当たった時にスコアが増えるようにしたいと思います.さらにはボールを取り逃がしたらゲームオーバーという表示が出るようにもしましょう.今回で2Dのボールキャッチゲーム制作は終了です.しっかり身につけましょう.

さて,スコアを表示するにはテキストを表示する必要があります.そのためにはHierarchyビューの+マークをクリックして[UI]→[Text]を選択します.するとHierarchyにCanvasとEventSystemができ,Canvasの下にTextができます:

f:id:lagrangian:20210119075638p:plain
ゲームにテキストを追加する

ただし,このままだとテキストを表示するCanvasがMain Cameraの表示領域を大きくはみ出していますのでまずこれを調整します.

HierarchyビューでCanvasを選択し,InspectorのCanvasでRender ModeをScreen Space - Cameraを選択し,HierarchyビューのMain CameraをInspectorのCanvasにあるRender Cameraにドロップします:

f:id:lagrangian:20210119162457p:plain
CanvasにRender ModeとRender Cameraを設定する
次にHierarchyビューでCanvasの矢印をクリックして下の階層から出てきたTextを選択します.Inspectorの中からTextを見て「New Text」と書かれたテキストエリアをクリックして「スコア」を入力します:
f:id:lagrangian:20210119163640p:plain
Textに文字「スコア」を入力する

次にこのままだと背景色と一緒で文字が見えませんのでColorの右側の色の表示窓をクリックして色を変えます.外側の円で色相を変え内側の正方形でその色相の色の明るさや彩度の異なる色を最終的に選択します.今回はスコアを赤色に設定してみました.正確に決めたい場合はRGBの値をそれぞれ調節して入力します.なおAは透過の設定になります.決まったらウィンドウの×ボタンをクリックしてください:

f:id:lagrangian:20210119164558p:plain
テキストの色を変える

Sceneビューで正方形の領域の左下側の横長の長方形内に小さくスコアと表示されるので,この長方形の四つの辺のどれかの上でカーソルが↔や↕に変わったところでその辺をドラッグして表示領域を大きくします.また表示領域の内側をドラッグすると位置を移動できますので画面右上に移動してください.それから再びInspectorでCharacterからFont Sizeを大きくします.今回は30に設定することにします.なお文字が表示領域に収まらない場合,全く表示されなくなってしまう場合がありますので,何も表示されない場合は,

  • 表示領域を大きくするかFont Sizeを小さくする
  • 文字色が背景の色と似ている場合は変える
  • Font Sizeが極端に小さくて実際には表示されているが見落としていないか確認する

のいずれかの場合が考えられますのでご注意ください.またInspctor直下のTextと表示されているテキストオブジェクトの名前をScoreにします.このオブジェクト名が,スコアを更新したときに表示するテキストオブジェクトの名前になりますので,入力ミスには気を付けてください.以上が終わると次のような画面になります:

f:id:lagrangian:20210119172753p:plain
テキストオブジェクト”Score”の設定

さらにゲームオーバーのときのテキストも追加しましょう.HierarchyビューのCanvasを右クリックして,[UI]→[Text]を選択します.Canvasの下に新たにTextが現れますのでクリックしてInspectorでオブジェクト名をEndingとし先ほどと同じようにして画面中央に大きな表示領域を作り,テキストの内容にゲームオーバーと書いてFont Sizeを大きく設定し,文字色も再び赤にしましょう:

f:id:lagrangian:20210119175935p:plain
ゲームオーバー時に表示するテキストのチェック

ただし,Textとして表示させている「ゲームオーバー」の文字はいったん全部削除して消してしまいましょう.というのもこのままPlayボタンを押してみればわかるのですが,このままではゲーム開始直後からゲームオーバーの文字が表示されてしまうからです.そのため,表示するのはボールをキャッチし損ねた時にスクリプトで表示するためです.それでは何のために一度入力したかというと正常に表示されるかどうかの確認の為に一度入力してみました.

今度はこれらのテキストの表示に使ったCanvasに得点を加算するスクリプトとゲームオーバーの文字を表示するスクリプトを追加しましょう.ProjectビューのAsssetsフォルダ内を右クリックし,[Create]→[C# Script]を選択し,できたファイルをTextControllerに変えます.そして次のコードを入力してください:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextController : MonoBehaviour
{
    int score = 0;
    GameObject scoreText;
    GameObject endingText;
    public void Ending()
    {
        this.endingText.GetComponent<Text>().text = "ゲームオーバー";
    }
    public void AddScore()
    {
        this.score += 8;
    }
    // Start is called before the first frame update
    void Start()
    {
        this.scoreText = GameObject.Find("Score");
        this.endingText = GameObject.Find("Ending");
    }

    // Update is called once per frame
    void Update()
    {
        scoreText.GetComponent<Text>().text = "スコア:" + score.ToString();
    }
}

このスクリプトはフィールドで整数スコアを0で初期化し,フィールドで定義したscoreTextとendingTextという空のGameObjectにそれぞれScoreとEndingという名前で登録したCanvasの下のTextObjectをスタート時に代入しています.なお,Findメソッドはかなり処理が重いので,なるべくスタート時に設定し,Update()メソッド内には記述しない方が良いでしょう.また,scoreはAddScoreメソッドが実行されるたびに8点づつ加算されますので,このメソッドは衝突判定の中で衝突するたびに1回ずつ実行してやる必要があります.そしてこのスコアが,Updateメソッド内でscoreTextの表示内容に先頭の文字を"スコア:"として数字で表されることになります.またEndingメソッドは衝突せずに画面外に出たballができた時に実行され,endingTextに"ゲームオーバー"と表示されます. そこでこのスクリプトを保存したら,今度はProjectビューのAssetsフォルダからbarControllerのスクリプトをダブルクリックし以下のように追加します:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class barController : MonoBehaviour
{
    GameObject canvas;
    // Start is called before the first frame update
    void Start()
    {
        this.canvas = GameObject.Find("Canvas");
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.LeftArrow) && transform.position.x > -4)
        {
            transform.Translate(-0.1f, 0, 0);
        }
        if (Input.GetKey(KeyCode.RightArrow) && transform.position.x < 4)
        {
            transform.Translate(0.1f, 0, 0);
        }

    }
    void OnTriggerEnter2D(Collider2D collider)
    {
        canvas.GetComponent<TextController>().AddScore();
        Destroy(collider.gameObject);
    }
}

これも保存したら,先ほど作成したTextControllerをcanvasにアタッチします.Hierarchyビューのcanvasをクリックした状態で,ProjectビューのAssetsフォルダ内のTextControllerスクリプトをドラッグしてcanvasにドロップします.するとcanvasにTextControllerがアタッチされますので,早速Playボタンを押してゲームを実行してみましょう:

f:id:lagrangian:20210119194011g:plain
barにballが当たるとスコアが加算される

最後にbarがballをキャッチし損ねた時,ゲームオーバーと表示してbarを消してみましょう.

ProjectビューのAssetsフォルダでballControllerスクリプトをダブルクリックして以下のコードを追加します:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ballController : MonoBehaviour
{
    GameObject bar;
    GameObject canvas;
    // Start is called before the first frame update
    void Start()
    {
        bar = GameObject.Find("bar");
        canvas = GameObject.Find("Canvas");
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, -0.1f, 0);
        if (transform.position.y < -5)
        {
            canvas.GetComponent<TextController>().Ending();
            Destroy(bar);
            Destroy(gameObject);
        }
        
    }
}

これでボールをバーがキャッチし損ねるとゲームオーバーの文字が表示されバーが画面から消えるようになりました!

f:id:lagrangian:20210119203543g:plain
バーがボールをキャッチし損ねるとゲームオーバーを表示する

これで2Dのボールキャッチゲームが完成しました.やったね!

4回にわたって2Dのボールキャッチゲームを製作しましたが今回で完成しました.途中画面の外にテキストがはみ出たり,Unityのレイアウトが環境によって各ビューの配置が異なったりするかもしれません.その際は適宜見た目を基準にして調整してください.細かく数字を調整して合わせる技術も画面全体にタイルを敷き詰めたりする際には重要ですが,ここでは比較的"ユルく"見た目の感じを大事にしてやりました.いろいろ微調整をやりながら一番うまくいくやり方でやってみてください.応援しています!

次回からはいよいよ3Dのゲーム制作の話に入ります.3Dは2Dと違ってずっと難しいんじゃないの?と思われた方も多いと思いますが,大丈夫.カメラの操作が複雑になる以外は2Dとほとんど一緒です.逆にカメラが難しいので先に2Dから説明しました.次回から制作するのは今度は3D版のボールキャッチゲームです.でも3Dになるだけでなんかワクワクしませんか?

こうご期待!


ゲーム制作ランキング

やっぱりUnityでゲームを作ってみる(3)

前回はballのPrefabを使って一定間隔でランダムにボールを出現させました. 今回はボールとバーの当たり判定を作成したいと思います.

UnityにはPhysics(日本語では物理)という機能が標準で実装されており,ゲーム内のオブジェクトは物理的性質をアタッチすると現実の物体のように振る舞います.中でも標準で実装されているのがgravity(重力)でスーパーマリオのジャンプなどはこのような機能で簡単に実現します.また,物体が衝突して跳ね返るなども同じように実装できます.

さて,今回のゲームでは物理的に衝突する判定だけで,跳ね返ったり,重力の影響を受けたりしません.一般にPhysicsを使って当たり判定をするとき衝突する物体同士には次の設定が必要です:

  • 少なくとも片方にRigidbody(剛体)を設定する.
  • 両方にCollider(衝突する物体)を設定する.

今回は2DなのでPhysics 2Dの中から長方形をしたbarにはRigidbody 2DとBox Collider 2D,丸いballにはCircle Collider 2Dを設定します.今回の場合,Rigidbody 2Dはball側にしてもいいんじゃないの?と思われるかもしれませんが,ballは沢山表れてきますので,衝突する相手がbarだけの場合はbarにRigidbody 2Dを設定する方が自然だし,若干処理も軽くなるでしょう.あとはbarにballが衝突したときに実行するメソッドが必要ですが,これは後程ご説明します.

まず,Hierarchyビューからbarを選択し,Inspectorから一番下のAdd Componentをクリックして選択肢の中から[Physics 2D]→[Rigidbody 2D]を選択します.今回は力学的な挙動は考えず,あると困るのでInspectorのRigidbody 2DのBody TypeからKinematic(重さや加速度、力を考えない)を選択します:

f:id:lagrangian:20210118193152p:plain
barにRigidbody 2DをアタッチしKinematicを選択する

次に再びbarを選択し,InspectorからAdd Componentをクリックして選択肢の中から[Physics 2D]→[Box Collider 2D]を選択します.そののち,InspectorのBox Collider 2Dの中でIs Triggerにチェックを入れます:

f:id:lagrangian:20210118193600p:plain
barにBox Collider 2DをアタッチしIs Triggerにチェックを入れる

このIs Triggerにチェックを入れると当たり判定だけしてその後の物理的挙動は無視します.物理的挙動とは例えばボールがバーに当たった時,バーが反動を受けて運動するなどです. このため,当たり判定のトリガーとしてだけ機能するようになるわけです.

次に今度はballに対してもCollider 2Dを設定しなくてはなりません.今度は円形なのでCircle Collider 2Dを使用します. 今の場合ballはballPrefabというPrefabに登録されていますのでballPrefabをProjectビューのAssetsから選択し,先ほどと同じように今度はCircle Collider 2Dをアタッチします.Inspectorから一番下のAdd Componentをクリックし,出てきた選択肢の中から[Physics 2D]→[Circle Collider 2D]を選択し,Inspectorに現れたCircle Collider 2DのIs Triggerにチェックを入れます:

f:id:lagrangian:20210118194620p:plain
ballPrefabにCircle Collider 2DをアタッチしIs Triggerにチェックを入れる

あとは衝突したときに実行されるスクリプトC#で作る必要がありますね.barにRigidbodyを設定したのでbarControllerに書いていきましょう.衝突した際のトリガーとなるメソッドはUnityでは決められていて2Dの場合,OnTriggerEnter2D(collider)となります.ここで引数となるcolliderは文字は何でもよいのですが,Collider2D型のオブジェクトになります.イメージで言うとbarにballが衝突したときの引数のオブジェクトがballになります.今回はbarにballが衝突したら消えてほしいのでDestroyしておきましょう.ProjectビューのAssetsでbarControllerをダブルクリックして,visual studioで編集状態にし,次のコードを追加してください:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class barController : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.LeftArrow) && transform.position.x > -4)
        {
            transform.Translate(-0.1f, 0, 0);
        }
        if (Input.GetKey(KeyCode.RightArrow) && transform.position.x < 4)
        {
            transform.Translate(0.1f, 0, 0);
        }

    }
    void OnTriggerEnter2D(Collider2D collider)
    {
        Destroy(collider.gameObject);
    }
}

あとはこれを保存してPlayボタンを押して実行してみましょう.ちょっとわかりづらいですが,バーにボールが衝突するとボールが消えていますね.

f:id:lagrangian:20210118200153g:plain
バーにボールが衝突すると消える

今回はここまでです.今回は苦労して当たり判定までやったのにバーにボールが当たるとボールが消えるだけでした.次回はいよいよこの当たり判定を使ってスコアを付けていきます.

こうご期待!


ゲーム制作ランキング

やっぱりUnityでゲームを作ってみる(2)

前回はbarが左右の矢印キーで左右に移動できるようにしました.今回は落ちてくるボールを製作します.

例によってProjectビューのAssetsに登録したballをSceneビューの四角い枠内にドロップします. それからProjectビューのAssetsを右クリックして[Create]→[C# Script]を選択します.できたNewBehaviourScriptと書かれたファイルを右クリックでballControllerにリネームしてダブルクリックしてvisual studioで開きます.そこに次のようにコードを書いてください:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, -0.2f, 0);
        if (transform.position.y < -5)
        {
            Destroy(gameObject);
        }
        
    }
}

このコードはbarのbarControllerよりシンプルです.というのもballはまっすぐ落下するだけなのでy軸方向の座標を毎回一定値減らすだけで良いからです.ただし,このままでは画面の外に行っても永久に計算し続けてしまってメモリが無駄に使用されますのでDestroy(gameObject)で画面外に出たらすぐgameObjectであるballを消滅させています.またStart()で開始位置を指定しておりませんので開始する位置は最初にballを設置した位置からになります.これを保存したらballにアタッチします.アタッチがうまくいくと次の画面になります:

f:id:lagrangian:20210117072057p:plain
ballにスクリプトをアタッチした後
これで取りあえずボールが動くようになりました.Playボタンをクリックするとballが1個だけ真下に落ちるのが分かると思います.なお,ここで注意してほしいのが,Unityではゲーム実行中にもプロジェクトの編集が可能のため,実行中に即座に動作がどう変わるかを確認できるのですが,あいにく実行中に行った編集は保存されません.このため編集内容を保存するにはplayボタンをクリックするなどしてゲームの実行を止めてから行う必要があります.デフォルトではゲーム実行中は少し画面全体が暗く表示されるので一応区別がつくのですが,余りにもわずかな違いなので見落とすかもしれません.そういう時はUnityの配色のスタイルを変更するなどするとよいでしょう.

さて,ここまではballが一個だけ落ちてくるようにしましたが,本当にやりたいのはballが一定間隔で何度でもランダムな位置から落ちてくることです.つまりballをたくさん出したいわけですね.

こういう時に力を発揮するのがPrefab(プレハブ)という機能です.・・・プレハブ?家でも建てるのか?いいえ違います.プレハブ住宅は工場で建築部品をすべて作ってから現地で組み立てる工法ですが,UnityのPrefabもそれに似てPrefabからいくつでも同じ種類のgameObjectを作ることができるのです.これは大量に似たようなものを作る際大変重宝します.実際やってみましょう.

HierarchyからballControllerをアタッチしたオブジェクトをドラッグしてProjectのAssetsの中にドロップします.するとHierarchyビューのballが青くて四角いアイコンに変わりました.またAssetsの方はballのアイコンができているのでballPrefabとリネームします.これでballのPrefabができました:

f:id:lagrangian:20210117114123p:plain
ballのPrefabを生成
Hierarchyビューの方のballはもういらないので右クリックでdelateしておきましょう.

次にballを次々に生成するスクリプトのballGenを作ります.例によってProjectビューのAssetsで右クリックして[Create]→[C# Script]を選択してできたファイルをballGeneratorにリネームします.それからこのファイルをダブルクリックしてvisual studioを立ち上げそこに次のコードを書き込みます:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ballGenerator : MonoBehaviour
{
    public GameObject ballPrefab;
    // Start is called before the first frame update
    void Start()
    {
        InvokeRepeating("GenBall", 2, 1);
    }

    void GenBall()
    {
        Instantiate(ballPrefab, new Vector3(-5f + 10 * Random.value, 6, 0), Quaternion.identity);
    }
}

InvokeRepeatingメソッドは第一引数のメソッドを第二引数の秒数だけ待って第三引数の間隔で実行するというものです. この場合,メソッドGenBall()を最初に2秒待ってそれからは1秒間隔で実行します.

一定間隔で実行されるGenBall()メソッドの中身は第一引数のgameObjectを第二引数の三次元ベクトルの座標に第三引数の回転で生成するものです.この場合だとballPrefabをy座標が6,つまり画面の上側の外側で,x座標が0を中心として左右に±5の位置でz座標が0の位置に回転ゼロで生成しています.Quaternion.identityのidentityは恒等の意味があり,回転させないときに書きます.またC#では通常System名前空間にRandomメソッドが定義されていますが,Unityでは独自のRandomメソッドを持っているためこちらを使います.両者の違いはSystemの方はNext()メソッドを使用するのに対し,UnityではRandom.valueで0から1までの単精度実数値乱数を生成します.このため-5f + 10 * Random.valueの部分は計算すると-5から+5の間のランダムな値になるわけです.

さてこのスクリプトを保存したら,このスクリプトをGameObjectに登録しなければなりません.といっても画面上にあるオブジェクトに登録するわけにもいかないので空っぽのGameObjectを作ります.

UnityのHierarchyビューの+マークをクリックしてCreate Emptyを選択するとHierarchyビューにGameObjectができますので,先ほど作ったballGeneratorスクリプトドラッグアンドドロップでGameObjectにアタッチします.そののち,GameObjectのInspectorが右側に表示された状態でAssetsからballPrefabをBallGenerator(Script)の下にあるballPrefabの右側の領域にドロップしてアタッチします:

f:id:lagrangian:20210117130128p:plain
ballPrefabをGameObjectのBallGeneratorにアタッチする

これでランダムに画面上方から落ちてくるボールができました.実行するとこんな感じになります:

f:id:lagrangian:20210117142133g:plain
ランダムにボールが落ちてくる
例によって大変遅いですね^^;とはいえ決して処理が重くなって遅くなっているわけではないのでご安心を.最後にパラメータを調節してゲームらしくなるようにします.

次回はボールとバーの当たり判定をします.


ゲーム制作ランキング

やっぱりUnityでゲームを作ってみる(1)

Unityでのゲーム作りは当面しない予定だったのですが,訳あってやっぱり始めて見ることにしました(察してください...).

インストール方法は比較的簡単ですし,詳しく解説しているサイトが沢山ありますので,そちらを参考にしてください. こことか:

https://create.unity3d.com/jp-howto-install-win

さて,今回作るゲームはこんな感じのゲームです:

f:id:lagrangian:20210116175805g:plain
ボールキャッチゲーム

地味ですね.ええ地味ですorz... でも最初にUnityで作るにはこのくらい簡単な方が分かりやすいかもしれません. 今回は4回に分けてUnityでこのボールキャッチゲームを作ってみます.

まず今回作成するゲームの紹介をします. 横長のバーがあって落ちてくるボールを1つづつキャッチするたびに得点が入り,キャッチし損ねるとゲームオーバーというものです.シンプルですね. このゲームを作るにはまず横長のバーとボールの画像を用意する必要があります.またボールは周りの背景が見えるようにボールの周囲の背景を透過する画像が是非とも使いたいので,透過したpngファイルを使用しました.画像作りは簡単ですので他にゆずるとして,簡単に素材をここに貼り付けておきます: 横長のバーがこれです:

f:id:lagrangian:20210116181830p:plain
バー
ボールがこれです.
f:id:lagrangian:20210116181946p:plain
ボール
素材を作るのが面倒な人はこれらをファイル保存して使ってください. 今回はバーのファイル名はbar.png,ボールのファイル名はball.pngで保存しておいてください.

それでは早速ボールキャッチゲームの開発を始めてみましょう. まずUnityを立ち上げます.

プロジェクトの新規作成からテンプレートの2Dを選択し,プロジェクト名を「BallCatchGame」とし,保存先も同じ名前のフォルダを作成して[作成]をクリックします:

f:id:lagrangian:20210116183312p:plain
プロジェクト作成画面
Unityのメイン画面が出てきますので下のProjectのAssetsが選択されていることを確認の上,上の二つのpng画像をAssetsタブのウィンドウにドロップして画像を取り込みます. 取り込みが終わると下の画面になります:
f:id:lagrangian:20210116190500p:plain
プロジェクトに画像を追加する

次に中央のウィンドウでSceneが選択されていると思いますが,Gameタブをクリックして10:10 Aspectを選択します.選択肢の一つにFree Aspectがあるので正方形以外の縦横比にしたいときはそれを選んで設定してください.

次に再びSceneタブをクリックして,そこにProjectのAssetsの中からバーの画像を選択して四角い領域内にドロップします:

f:id:lagrangian:20210116192400p:plain
バー登録
簡単に画面に登録できました! ・・・でもこれだけでは画像を配置しただけですので,何も動かすことはできません. そこでこの物体に取り付けるプログラムが必要ですね. ちなみにゲーム上に登場するこのような物体をgameObject,gameObjectに取り付けることをアタッチ,取り付けるプログラムのことを特にスクリプトと言います. 今回やることはやや専門的な言い方にすればgameObject"bar"にC#スクリプトをアタッチするということになります. そこでProjectの中のAssetsのタブのウィンドウを右クリックして[Create]→[C# Script]を選択してください. 同じ表示領域に"NewBehaviourScript"という名前でシャープマークのアイコンができているはずです(ちなみに名前全体は画面に表示しきれていません). これを右クリックでリネームして"barController"という名前で保存してください.
f:id:lagrangian:20210116194841p:plain
barControllerスクリプトを作成

次にスクリプトの編集です.barControllerのアイコンをダブルクリックするとvisual studioがインストールされた環境ではvisual studioが立ち上がり次のように表示されているはずです:

f:id:lagrangian:20210116195645p:plain
visual studio C#スクリプト編集画面
コードの方がこの画像だとみにくいのでコード部分だけ取り出してみます:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class barController : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

このコードはまだ何も実行しないコードなのですが,注目してほしいのが,void Start(){}の部分です. この{}内に書かれたことはスクリプトが実行されたときに最初に実行される部分です. 例えばbarにアタッチした場合barの初期状態などがこれに対応します.

一方,void Update(){}の部分は{}内に書かれたことがフレームレートである一般的に1秒間に60回程度は毎回実行される部分です. 仮に「→」キーを2秒間押し続けたとすると,この部分にbarが1回あたり1ピクセル右に移動するように記述してあれば,2秒かけてbarは右に合計120ピクセル移動することになります. 120回実行されるからです.ただしフレームレートは1秒間に60回ではない場合もありますのでここでの話は一応の目安と思っておいてください.今回の制作ではフレームレートを気にするようなシビアな話は全く出てこないです. さて今回の目玉はこのUpdate(){}の中に「→」を押したら右に,「←」を押したら左にbarが動くようにすることです.次のように書きます:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class barController : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.LeftArrow) && transform.position.x > -4)
        {
            transform.Translate(-0.01f, 0, 0);
        }
        if (Input.GetKey(KeyCode.RightArrow) && transform.position.x < 4)
        {
            transform.Translate(0.01f, 0, 0);
        }

    }
}

このコードですが,1フレーム当り単精度実数でそれぞれ左右に0.01だけx座標が移動するようになってます. また画面の端まで行くとif文が実行されず,移動しなくなることに注意してください. これをbarにアタッチします. barControllerのアイコンをProjectビューのAssetsの中からドラッグし画面のHierarchyビューの中のbarの上にドロップします. barまで持っていく途中は禁止マークのカーソルですがbarまで持っていくとちゃんと図のように+マークが出てアタッチできます.

f:id:lagrangian:20210116203120p:plain
barにbarControllerをアタッチする

アタッチができたら.早速画面中央上部のPlayマークをクリックして実行してみましょう. 問題なければ次のようになるはずです:

f:id:lagrangian:20210116210035g:plain
動かせるバー
お,動く動く!やったね初めてUnityで自分で動かせるGameObjectを作れたね! ・・・とはいえ,むー,動きが速すぎるとイクナイと思いゆっくり目にしたが,やはりこれでは遅すぎたか.

こういう時はコードの0.01fを0.1fなどに変えれば早くなります.ちなみにfは単精度浮動小数を表すfloatを意味します.動きの速さは数字を変えれば簡単にできるので今回はここまでとします. お疲れさまでした.

次回はボールを生成します.


ゲーム制作ランキング

C#でダンジョンRPGを作ってみる(2)~フォームエディタでメインウィンドウを作ろう!~

さて,今回からやっとC#でのコーディングに移るわけですが,その前にC#の開発環境を構築しなければなりません. これは案外簡単でマイクロソフトから出ているvisual studioと呼ばれるIDE(統合開発環境)をインストールするだけです.やり方は次を参照:

qiita.com

インストールが終わったら早速Visual Studioを立ち上げます. 新しいプロジェクトの作成を選択します. Windowsフォームアプリケーション(.NET Framework)を選択して次へをクリックします:

f:id:lagrangian:20210115073839p:plain
ダンジョンゲーム制作(2)1

次の画面ではプロジェクト名を例えばDungeonExplorerなどとします. このとき自動でソリューション名も同じ名前が入ります.またフレームワーク.NET Framework 4.8を選んでください(新しいものなら多少バージョンが違っていても恐らく大丈夫です).

f:id:lagrangian:20210115074715p:plain
ダンジョンゲーム制作(2)2

作成をクリックすると次の画面になります:

f:id:lagrangian:20210115075331p:plain
ダンジョンゲーム制作(2)3

画面に表れているのはこれから作成するメインウィンドウになります.ここでボタンやラベルなどを配置して外観を作ってゆきます.こうしてビジュアル的に作っていったものがコードとしてForm1.Designer.csに保存されて利用できるようになります.

しかし今回はコードを一本化したいのでまず最初に左のソリューションエクスプローラーからProgram.csをクリックしメインのコードを書き換えます.

f:id:lagrangian:20210115080952p:plain
ダンジョンゲーム制作(2)4

ここでエディタ画面の7行目から23行目までを次のように書き換えます:

class DungeonGame : Form
{
    public static void Main()
    {
        Application.Run(new DungeonGame());
    }

    public DungeonGame()
    {

    }
}

こうして開始ボタンをクリックすると,

f:id:lagrangian:20210115090056p:plain
ダンジョンゲーム制作(2)5

↑のようなアプリケーションウィンドウが立ち上がりました! ・・・ただ,これだけだと先ほど見えていたForm1と外観が違いますね. そこでこれからこのアプリケーションウィンドウの中身のボタンやラベルを作成していきたいと思います. アプリケーションウィンドウを閉じて,左側のソリューションエクスプローラーからForm1.csをクリックします. 画面にForm1ウィンドウが立ち上がるのでウィンドウ内で右クリックしてプロパティを選択します:

f:id:lagrangian:20210115092159p:plain
ダンジョンゲーム制作(2)6

プロパティでTextをダンジョンエクスプローラーとして確定すると,プレビューされているForm1のタイトルバーの表示がダンジョンエクスプローラーに変わります. さて,今回のゲームで使用する画像はタイトル画面も含めて全て600×600ピクセルにしたいのですが,あいにくフォームエディタからはフォームのクライアント領域を正確に決定する指定はプロパティとして用意されていません.細かいとこまでビシッっと決めたい方は

johobase.com

を参考にしてください.ここでは大雑把にプロパティでSizeのところの+マークをクリックして,Widthを610,Heightを630にします. 次のような表示になっていればOKです:

f:id:lagrangian:20210115093103p:plain
ダンジョンゲーム制作(2)7

今度はスタートボタンを配置してみましょう. [表示]→[ツールボックス]を選択すると,コントロールと呼ばれるボタン類を配置するためのウィンドウが立ち上がりますので,その中から[コモンコントロール]→[button]を選択します:

f:id:lagrangian:20210115094202p:plain
ダンジョンゲーム制作(2)8

ボタンをフォームの真ん中あたりに配置します.button1が配置されますのでbutton1をクリックしてからプロパティでTextを「ゲームを始める」に変えます. またボタンの四隅を引っ張って大きさを調節したり位置を微調整します.完成するとこんな感じです:

f:id:lagrangian:20210115094955p:plain
ダンジョンゲーム制作(2)9

これで取りあえずタイトル画面のベースはできました.あとは画像とBGMを指定したり,ボタンイベントを設定すればよいですね. そこでまず,[ファイル]→[Form1.csの保存]をして,ソリューションエクスプローラーからForm1.Designer.csをクリックして,このフォームのソースコードを表示します:

するとエディタ画面に「Windows フォーム デザイナーで生成されたコード」という行が見えると思いますので,折りたたまれている24行から58行あたりの以下の部分をクリップボードにコピーします:

        #region Windows フォーム デザイナーで生成されたコード

        /// <summary>
        /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディターで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(226, 261);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(125, 53);
            this.button1.TabIndex = 0;
            this.button1.Text = "ゲームを始める";
            this.button1.UseVisualStyleBackColor = true;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(594, 591);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "ダンジョンエクスプローラー";
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Button button1;
    }

これをProgram.csの一番下あたりに貼ります:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

class DungeonGame : Form
{
    public static void Main()
    {
        Application.Run(new DungeonGame());
    }

    public DungeonGame()
    {

    }
    #region Windows フォーム デザイナーで生成されたコード

    /// <summary>
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
        this.button1 = new System.Windows.Forms.Button();
        this.SuspendLayout();
        // 
        // button1
        // 
        this.button1.Location = new System.Drawing.Point(226, 261);
        this.button1.Name = "button1";
        this.button1.Size = new System.Drawing.Size(125, 53);
        this.button1.TabIndex = 0;
        this.button1.Text = "ゲームを始める";
        this.button1.UseVisualStyleBackColor = true;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(594, 591);
        this.Controls.Add(this.button1);
        this.Name = "Form1";
        this.Text = "ダンジョンエクスプローラー";
        this.ResumeLayout(false);

    }

    #endregion

    private System.Windows.Forms.Button button1;
}

ここで「#region Windows フォーム デザイナーで生成されたコード」と「#endregion」の行は今回は余計な行なので削除してください. また,開きカッコ「{」・閉じカッコ「}」の位置や数が正しいかどうか確認してください.もし間違っていると正常に動作しなくなるのですが,恐らく赤い色などで修正してね!という注意の色がついているはずです.さて先ほどフォームエディタで作成したフォームはまだどこからも呼び出されていません. このフォームを使用するにはInitializeComponent()メソッドを実行する必要があります.そこでInitializeComponent();をpublic DungeonGame()の中にコピペして最後にセミコロンをつけましょう. 実行するとこうなります:

f:id:lagrangian:20210115102059p:plain
ダンジョンゲーム制作(2)10

おめでとう!フォームエディタって作成したフォームが立ち上がりました.最後に今回のコードを全部まとめて張っておきますね:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

class DungeonGame : Form
{
    public static void Main()
    {
        Application.Run(new DungeonGame());
    }

    public DungeonGame()
    {
        InitializeComponent();
    }

    /// <summary>
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
        this.button1 = new System.Windows.Forms.Button();
        this.SuspendLayout();
        // 
        // button1
        // 
        this.button1.Location = new System.Drawing.Point(226, 261);
        this.button1.Name = "button1";
        this.button1.Size = new System.Drawing.Size(125, 53);
        this.button1.TabIndex = 0;
        this.button1.Text = "ゲームを始める";
        this.button1.UseVisualStyleBackColor = true;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(594, 591);
        this.Controls.Add(this.button1);
        this.Name = "Form1";
        this.Text = "ダンジョンエクスプローラー";
        this.ResumeLayout(false);

    }

    private System.Windows.Forms.Button button1;
}

次回はウィンドウアプリケーションで特に重要なイベント処理について書きます.


ゲーム制作ランキング

PhotoShopでダンジョンの壁画像を作成する(2)

竜太です,ども.

 

前回は壁画像の基本的な部分だけPhotoShopで作ったわけですが,今回はより突っ込んだところまでやりたいと思います.

 

そのためにまず最初に「プレイヤーキャラが立っている位置から周りの景色はどう見えるべきなのか」という根本的な部分から考えてみたいと思います.

 

プレイヤーキャラは当然後方は見えません.ということは作る必要があるのは左側と右側と前方の風景になります.より詳しく言うと左側,右側と前方左側,前方中央,前方右側・・・となります・・・の部分は前前方などの部分です.勘の良い方はお気づきでしょうがこれだと実は無限のパターンの風景を作る必要が出てきてしまいます.

 

困りましたね.

そこで次の仮定を導入します.ずっと前方は暗くて見えないことにして黒く塗りつぶし,左右と前方,前方左右中央のみ描くというものです.これで用意する画像が大幅に減らせそうです.次に大事なのがそれらの画像のファイル名です.例えば左側と前方左側にのみ壁がある場合はどういうファイル名にしたらよいでしょうか?合理的で一貫性のあるファイル名としては例えば左をL,右をR,中央をCとして,さっきの場合,wallL_L.pngなどとすることです.ここで左に最初に現れるLは手前の左側に壁があることを示し,アンダースコアの右側のLは前方左側に壁があることを示します.つまりアンダースコアは前方を表すものとします.さて,この流儀でwallLR_Cはどんな風景でしょうか?答えは左右に壁があり,前方にも壁があってふさがっている状態ですね.

図で書くとこんな感じです:

f:id:lagrangian:20210114085257p:plain

wallLR_Cの風景

pの位置にプレイヤーキャラが居て,周りを壁が取り囲んでいます.

ここでもしかしたらおや?っと思った方がいらっしゃるかもしれません.

wallLR_Cは前方左側と前方右側には壁がなかったんじゃないのか?と.

実は上から見ればwallLR_CとwallLR_LCRは区別がつくのですが,プレイヤーキャラの視点では壁でふさがっているので両者は区別できないのです.つまり,wallLR_LCRとwallLR_LCとwallLR_CRはみんなプレイヤーキャラの視点ではwallLR_Cで書いてしまって良いということになります.これでさらに用意するべき壁画像ファイルが減らせました.あとはこれを全パターン用意するだけです.

 

さて,前回のPhotoShopの画面を開きましょう:

f:id:lagrangian:20210114092423p:plain

ダンジョン壁画像(2)1

これがwallLR_Cになりますのでこれをpng形式でwallLR_C.pngとして保存します.

次に各レイヤーの名前が分かりづらいのでリネームします.例えば左壁のレイヤーは左壁などとします.また,一番下の壁の元画像は壁マスターとでもしときましょう.

そして壁マスター以外をまとめてグループ化してグループ名を「手前」としておきます.こんな感じになります:

f:id:lagrangian:20210114093527p:plain

ダンジョン壁画像(2)2

次にグループ「手前」を複製して「奥」という名前を付けておきます.

このとき天井と床は大きく引き伸ばして作ってありますのでキャンバスの外側にも余計な画像がありますので,切り抜きツールで画面の内部だけを切り抜いておきます.

それからグループ「奥」を選択し,自動選択をグループにします.

f:id:lagrangian:20210114100536p:plain

ダンジョン壁画像(2)3

ctrl + Tで選択して奥の風景になるように小さくします.このとき画面中央の正方形領域にぴったりはまるようにします:

f:id:lagrangian:20210114100945p:plain

ダンジョン壁画像(2)4

これで長いトンネルみたいな通路ができましたね!

ただし,壁を全部取ってしまうと下の図のように変なことが起きてしまいます:

f:id:lagrangian:20210114101637p:plain

ダンジョン壁画像(2)5

これを改善するには中央奥のグループを左奥と右奥にコピペすればよさそうですね.

そこで試してみると

f:id:lagrangian:20210114110735p:plain

ダンジョン壁画像(2)6

となり,さっきよりはだいぶ改善しましたが,なんか床の模様が変です.

これは何故かというと漫画を描かれる方ならご存知でしょうが,床の集中線が左右それぞれが中央に向いていないというのも大きな理由です.そこで苦し紛れではありますが,手前の床と天井を延長した先の床と天井の位置まで引き延ばしてみます.

そして左奥,奥,右奥の天井と床を全部削除します:

f:id:lagrangian:20210114111720p:plain

ダンジョン壁画像(2)7

大分いい感じになってきました.

しかしここでまだ問題が残ってます.

グループ手前に入っている奥の壁を表示するとおかしなことに右壁と左壁があるのに天井と床の模様は正面の壁の模様になってしまい正しく表示されません.これを解決するには正面の壁を左から右に3等分することです:

f:id:lagrangian:20210114113015p:plain

ダンジョン壁画像(2)8

これで上のような画像が作れるようになりました.

最後に奥の奥の壁は暗くてよく見えないことにして黒で全面塗りつぶしたレイヤーを表示させるとこんな感じになります:

f:id:lagrangian:20210114113419p:plain

ダンジョン壁画像(2)9

お疲れさまでした^^

後はこれらのうち必要な画像を壁を出したり消したりしながらwall**_***.pngの形式でどんどん保存してゆくだけです.大量な量になりますので最初にご説明したように同じ見え方になるのは全部一本化して保存するようにしてください.

 

次回はいよいよC#でコードを書いてゆきます.

 


ゲーム制作ランキング

PhotoShopでダンジョンの壁画像を作成する(1)

ども,竜太です.

 

今回から早速ダンジョンRPGの製作を開始したいと思います.

まず最初にダンジョンの壁画像を作成したいと思います.

考えているのは昔懐かしいウィザードリーのような画面です.

この作成にはPhotoShopを使います.

まず,PhotoShopを立ち上げます.

メニューの[ファイル]→[新規]から立ち上がったウィンドウで今回は縦横600ピクセルのキャンバスを指定して作成をクリックします:

f:id:lagrangian:20210113073523p:plain

ダンジョン壁画像作成その1

次に[フィルタ]→[描画]→[雲模様1]を選択します:

f:id:lagrangian:20210113075135p:plain

ダンジョン壁画像作成その2

キャンバス全体に雲模様が表示されます.お好みにより描画色と背景色を変えてから雲模様を作成すると,色付きの雲模様も作れます.

f:id:lagrangian:20210113075638p:plain

ダンジョン壁画像作成その3

[フィルター]→[フィルターギャラリー]を選び出てきた画面でテクスチャを選択します.

次にテクスチャからステンドグラスを選択しセルの大きさを10ぐらいに設定してOKをクリックします:

f:id:lagrangian:20210113080414p:plain

ダンジョン壁画像作成その4


ステンドグラス模様でできた床の模様ができました.

次に床の模様の中をクリックしてctrl + Tで選択状態にし,右クリックで出るコンテキストメニューから遠近法を選択します:

f:id:lagrangian:20210113081201p:plain

ダンジョン壁画像作成その5

右下の頂点をクリックしてドラッグすると左右に伸ばせることが分かりますので画面右まで限界まで伸ばしてください:

f:id:lagrangian:20210113081728p:plain

ダンジョン壁画像作成その6

↑こんな感じです.

次に領域内で右クリックし自由な形にを選択します:

上の辺の中央部をクリックしてまっすぐ真下へドラッグします.

f:id:lagrangian:20210113082257p:plain

ダンジョン壁画像作成その7

これで床面は完成です.お疲れさまでした~^^

新しいレイヤーを作成し,同じことを今度はステンドグラスじゃなくてテクスチャの中からクラッキングを選んで上下逆でやると天井もできます:

f:id:lagrangian:20210113083135p:plain

ダンジョン壁画像作成その8

次にいよいよ壁を作ってみます.

まず,これらのレイヤーの下にまた新しいレイヤーを作って雲模様を描きテクスチャの中からモザイクタイルを選びます:

 

f:id:lagrangian:20210113085932p:plain

ダンジョン壁画像作成その9

次にこの壁のレイヤーを選択した状態で長方形選択ツールで見えている部分の壁だけを選択します:

f:id:lagrangian:20210113090429p:plain

ダンジョン壁画像作成その10

次に選択領域内で右クリックし選択領域をコピーしたレイヤーを選択します:

f:id:lagrangian:20210113090808p:plain

ダンジョン壁画像作成その11

新しいレイヤーができます.これは奥の壁用のレイヤーです.

次の子のレイヤーを複製し,一番上のレイヤーにします.

次にこのレイヤーの壁画像をctrl + Tで選択し,右クリックで遠近法を選び,下の図のようにドラッグします:

f:id:lagrangian:20210113091623p:plain

ダンジョン壁画像作成その12

今度は右クリックから自由な形にを選択し右の辺の中央を左側にドラッグします:

f:id:lagrangian:20210113091949p:plain

ダンジョン壁画像作成その13

これで左壁は完成です.大分ダンジョンらしくなってきました!

次に左壁のレイヤーを選択した状態でAltキーを押しながら左壁を右の方にドラッグすると新しいレイヤーができてそこに左壁の複製ができます:

f:id:lagrangian:20210113092806p:plain

ダンジョン壁画像作成その14

今度はこのレイヤーで[編集]→[変形]→[水平方向に反転]を選択して右壁を作ります:

f:id:lagrangian:20210113093124p:plain

ダンジョン壁画像作成その15

そしてできた右壁を正しい位置に移動します:

f:id:lagrangian:20210113093348p:plain

ダンジョン壁画像作成その16

これでダンジョンの基本的な構成要素ができました.

後はこの応用です.

どうでしょうか?初めてだと少し難しかったでしょうか?

でも慣れてくると楽しいし割と簡単にできるようになるのですよ.

あきらめずに頑張りましょう^^

 

次回はゲーム中で使用されるpng形式の画像を作るところまでお話しします.


ゲーム制作ランキング