Open22

Java取得者が行うUnityでゲーム制作

NekoNeko

Java取得者が行うUnityでゲーム制作

#1

最初に触れた感想
System.out.printin(xxx)ではなく、Debug.log(xxx)を使用する。
ほとんど文法も同じっぽい。
Unityのプロジェクトウィンドウの「#」アイコンを押すことによって、Visual Studioが起動する。
サインインは必要によって行う。
基本的な構造は以下のようになる。

using System.Collection;
using System.Collection.Generic;
using UnityEngin;     // ここら辺のimportはほとんど書き換えることはないそうです。

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

    }

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

    }
}
NekoNeko

#2

フレームと実行タイミング
ゲーム画面は、漫画と同じように、パラパラ漫画方式で表示している。
1コマ1コマは、フレームと呼ばれる。1秒間に表示される枚数は「FPS(Frame Per Second)」という単位になる。
実際に、前のフレームから何秒たったのかは、Time.delta.Timeという仕組みで知ることができる。

NekoNeko

#3

メソッド
Startメソッドに書くことが基本的だが、処理が長くなってしまうと可読性が落ちてしまったり、デバッグが大変になってしまう。
→そのため、意味のある処理ブロックごとに分解してメソッドを作る仕組みがあり、この別メソッドを使用することが重要になる。(これもJavaと同様でした。また、基本的な文法も微妙には異なりますがほとんど同じです。)

using System.Collection;
using System.Collection.Generic;
using UnityEngin;     // ここら辺のimportはほとんど書き換えることはないそうです。

public class Test  :  MonoBehaviour  {
    // start is called before the first frame update
    void SayHello () {  // Startメソッド内で、このSayHelloが呼ばれる。
        Debug.log("Hello");
    }

    // Update is called once per frame
    void Start () {
        SayHello ();  // ここで、メソッドの呼び出しを行う。
    }
}

メソッドの指定方法

    void SayHello ()

void・・戻り値なし(という意味)
SayHello・・メソッド名
( )・・引数を入れる場所(今の時点では、引数なしとみなされる)

引数ありの場合のコードでは、

using System.Collection;
using System.Collection.Generic;
using UnityEngin;     // ここら辺のimportはほとんど書き換えることはないそうです。

public class Test  :  MonoBehaviour  {

    void CallName (String name) {  // Startメソッド内で、このSayHelloが呼ばれる。
        Debug.log("Hello" + name);
    }

    void Start () {
        CallName("Tom");
    }
}
NekoNeko

#4

クラス
クラスは、メソッドと変数をまとめたもの。
メソッドは、「方法」なのでゲーム内の処理ごとにまとめることができます。
Unityでは、それ以外の「物」をまとめる必要があるので、そのためにクラスが必要になってきます。

using System.Collection;
using System.Collection.Generic;
using UnityEngin; 

public class Player  {

    private int hp = 100;
    private int power = 50;

    public void Attack() {
        Debug.log(this.power + "のダメージを与えた。");  // this.メンバ変数で、
    }

    public void Damage(int damage) {
        this.hp -= damage;
        Debug.log(damage + "のダメージを受けた。");
    }

    public class Test  :  MonoBehaviour {
        void Start () {
            Player myPlayer = new Player();
            myPlayer.Attack();
            myPlayer.Damage(30);
        }   
}

Javaと異なる部分としては、「: MonoBehaviour」がある。これは、継承で、
Unityが事前に用意してるMonoBehaiviourクラスの機能をTestクラスに取り込むことを宣言している。

また、大きく異なる部分として、作成したクラスはintやStringなどと同様に型のように使える。

NekoNeko

#5

Vectorクラス
Vectorクラスは、キャラクターなどを動かす場合によく使う。
3Dゲームであれば、オブジェクトをどこに置くのか、どの方向に移動するのか、どちらに力を加えるかなどを決めるため、float型(x,y,z)の3つの値を使用する。

これらを、ひとまとまりにするVetctor 3クラス(構造体)が用意されている。
構造体は、クラスと同じく、変数とメソッドをひとまとまりにする仕組みのこと。クラスよりも自由度は低くなるものの、クラスよりも高速に動く。

基本構造として、

class Vector {
    public float x;
    public float y;
    public float z;
}

これを使用する場合、

using System.Collection;
using System.Collection.Generic;
using UnityEngin; 

public class Test  :  MonoBehaviour  {
    void Start() {
        Vector2 playerPos = new Vector2(3.0f, 4.0f);
        playerPos.x += 8.0f;
        playerPos.y += 5.0f;
        Debug.Log(playPods);
    }
}

new 演算子を使用することで、インスタンスを生成できる。

        Vector2 playerPos = new Vectour2(3.0f, 4.0f);

各点の長さを調べるためには、Vector2クラスが持っている、magnitude(マグニチュード)メンバ変数を使用し、長さ(= dir)の長さを求めます。

using System.Collection;
using System.Collection.Generic;
using UnityEngin; 

public class Test  :  MonoBehaviour  {
    void Start() {
        Vector2 a = new Vectour2(2.0f, 1.0f);
        Vector2 b = new Vectour2(8.0f, 5.0f);
        Vector2 dir = endPos  -  startPos;
        Debug.Log(dir);

        float len  =  dir.magnitude;
        Debug.Log(len);
    }
}

数字を変えても、同じようになる。

応用

        Vector2 speed = new Vectour2(1.0f, 2.0f);

を生成した場合、これらを毎フレーム(繰り返し文×インクリメントなどで)で加算することによって物体を動かすことができる。

NekoNeko

#6

ゲーム制作における設計をしてみる
ゲームは、タイトル画面、プレイ画面、エンディング画面があれば、いいんだそう。
しかし、実際にはユーザーはプレイ画面、つまりプレイをする必要がある。ユーザーが操作ができるものを作る必要がある。占いアプリを制作する。

企画
ユーザーの入力があってこそのゲーム。
最もシンプルな操作・・・・→画面のタッチタップ)によって、操作できるようにしてみようと思う。

タップをする→なんかルーレットが回る→ルーレットが止まる→占いができる(吉)

部品設計(基本設計)
次の5ステップで設計をする。
1. 画面上のオブジェクトを全て書き出す。
2. オブジェクトを動かすためのコントローラースクリプトを決める。
3. オブジェクトを自動生成するためのジェネレータスクリプトを決める。
4. UIを更新するための監督スクリプトを用意。
5. スクリプトを作る流れを決める。

NekoNeko

#7

1. 画面上のオブジェクトを全て書き出す。
・ルーレット
・針

以上。

NekoNeko

#8

2. オブジェクトを動かすためのコントローラースクリプトを決める。
コントローラー(動作)するものを決める。
この中だったら、ルーレット。

C#スクリプトに、「回れ」という命令文を書く。それを、ルーレットにセット。そうすれば、ルーレットが動くはず。

NekoNeko

#9

3. オブジェクトを自動生成するためのジェネレータスクリプトを決める。
ゲームプレイ時に生成されるオブジェクトをさがす。
敵キャラやステージの足場などプレイヤの移動や自動経過によって出現(ジェネレート)するものがある。これを、ジェネレータスクリプトを書くことによって、自動生成する。

今回の占いでは不要。

NekoNeko

#10

4. UIを更新するための監督スクリプトを用意。
ゲームのUI(ユーザーインターフェース)を操作したり、進行状況を判断するためにゲーム全体を見渡せるスクリプトが必要。(監督スクリプト

今回は不要。

NekoNeko

#11

5. スクリプトを作る流れを決める。
基本ステップとして、
「コントローラスクリプト」→「ジェネレータースクリプト」→「監督スクリプト」である。

なので、ルーレットコントローラー(MVCの中でのC)を作成する必要がある。

以上で考えると、
「コントローラスクリプト」→「ジェネレータースクリプト」→「監督スクリプト」は、今回の占いアプリ内では、
「コントローラスクリプト」→「ジェネレータースクリプト」→「監督スクリプト」
「ルーレットの動き制御文」→     「不要」      →   「不要」
となる。

NekoNeko

#12

ゲーム作成の流れ
①プロジェクトの作成
②オブジェクトの配置
③スクリプトの作成
④スクリプトのアタッチ

の①〜④で作成をする

NekoNeko

#13

プロジェクトの生成
UnityHub→プロジェクトを作成を押下
1. 画面上のオブジェクト


今回必要なものをCanvaにて作成しました。ご自由にお使いください。

2. オブジェクトを動かすためのコントローラースクリプトを決める。
この中で動くオブジェクトは、ルーレットです。確かに、針が回ったら、「お前が回るんかい!!」というツッコミがきそうです・・。

そうすると、ルーレットの動作的には
タップするとルーレットが回る→止まる
の動作。この中をもう少し細分化していくなら・・・。

タップ→ルーレットを回す(タップ操作の初期動作?)→数秒かけてスピードを減速させる→0で止まる

NekoNeko

#14

プロジェクト追加直後の設定
先ほどの素材を、プロジェクト内に追加していきます。
その後、実行時の描画設定を変更します。これは、実行したときのフレームの描画速度をモニターの描画速度と合わせるためです。
左上のGam→Acceptのドロップダウンリストを開く。→VSyncをオンにしておくこと。
File→Bulid Settingで、スマホ用のゲームを制作するためにPlatform欄からIOSを選択する。
画面サイズを設定する。

NekoNeko

#15

オブジェクトの配置
rouletteを配置する。画像を、シーンビューにドラッグ&ドロップをする。

NekoNeko

#2-1

チキンゲーム制作(基本の考え)
まず何が必要か考える
車、フラッグ、道路、あと何メートルの文字(UI)

作成した図(ご自由にどうぞ)

以上を用意。ただし、残りのメートルに関しては、UIなので実際には不要でも良い。(テキストで用意すればOK)

次に、
動くオブジェクトは何か考える。→今回は、車が動く。→よって、車のコントローラが必要。→C#スクリプトで、車Controllerを用意する。
その後、オブジェクトを自動生成するジェネレータスクリプトは必要かを考えると、今回は不要となる。
その後UIを更新するための監督スクリプトを用意する。→ゲーム全体に目を通して、UIの書き換えを行ったり、ゲームオーバーを判定することができる。
→dirを計算し、その距離の値を、出力するようにすれば、フラッグと車との距離を計算することができるようになるはず・・・!

要するに監督スクリプトとは、UIを書き換えるための監督と考える。

NekoNeko

#2-2

ゲームを作る流れ
前回と同じで、コントローラ(動くやつ)→ジェネレートするやつ→監督スクリプトの生成の流れで、
プロジェクトの生成→オブジェクトの配置→車を動かす→UIを作る→監督の作成をしていく。

NekoNeko

#2-3

C#スクリプトで、車のコントローラを作成する。
Create→C#Scriptを選択。

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

public class CarController : MonoBehaviour
{

    float speed = 0;

    // Start is called before the first frame update
    void Start()
    {
        
    }

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

        if (Input.GetMouseButtonDown(0))
        {
            this.speed = 0.2f;  //  if you push button of mouse, car speed is 0.2f.
        }

        transform.Translate(this.speed, 0, 0);  //  move
        this.speed *= 0.98f;  // down

    }
}

を記述する。

Input.GetMouseButtonDown(0))

は、ユーザーの入力を操作するメソッドで、Input変数に、GetMouseButtonDown()メソッドを付与することで実現する。ここで、注意するのは、引数である。
実際は、ユーザーはクリックをするだけなのだが、何を入力するかというと、そのクリックの種類を表している。
(0)を指定する場合は、左クリックを示している。
この引数を変えることで、右クリック、左クリックなどの入力の種類を変更することができる。

NekoNeko

Create → C# Scriptを開こうとすると、cruserが開いてしまう。よって、visual studioをデフォルトに開くようにする。

macOS Venturaから、
UnityのPreferences Windowを開くメニューが、
「Unity > Preferences」から「Unity > Settings」に変わった

その後、External Toolsを押して、External Script EditorでUnity2022の場合はVisual Studio 2022が選択されているか確認する。”Open by file extension”だと違うエディタが立ち上がる可能性がある(自分の場合は、cruserが自動的に立ち上がってしまっていた。)


これを、指定するEditorに変更しておく。

NekoNeko

#2-4

プレイヤを左右に移動させる

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

public class NewBehaviourScript1 : MonoBehaviour
{
    Rigidbody2D rigid2D;
    float jumpForce = 680.0f;
    float walkForce = 30.0f;
    float maxWalkSpeed = 2.0f;

    void Start()
    {
        this.rigid2D = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            this.rigid2D.AddForce(transform.up * this.jumpForce);
        }

        int key = 0;
        if (Input.GetKey(KeyCode.RightArrow)) key = 1;
        if (Input.GetKey(KeyCode.LeftArrow)) key = -1;

        float speedx = Mathf.Abs(this.rigid2D.velocity.x);

        if (speedx < this.maxWalkSpeed)
        {
            this.rigid2D.AddForce(transform.right * key * this.walkForce);
        }
    }
}

スペースを押した場合、ジャンプする

        if (Input.GetKeyDown(KeyCode.Space))
        {
            this.rigid2D.AddForce(transform.up * this.jumpForce);
        }

右矢印を押したら、変数keyの数字を変える。

        int key = 0;
        if (Input.GetKey(KeyCode.RightArrow)) key = 1;
        if (Input.GetKey(KeyCode.LeftArrow)) key = -1;

これによって、0、1、-1という3つの状態を作ることができるようになった。

スピード制限がないと、常にAddForceをすることになるため加速していってしまう。
このために、if文でスピード制限を設ける。

        if (speedx < this.maxWalkSpeed)
        {
            this.rigid2D.AddForce(transform.right * key * this.walkForce);
        }

変数keyが、このスクリプト(this)のrigid2Dに力を加える。
この方向はkeyでプラスかマイナスに変わるようになった!

NekoNeko

#2-5

プレイヤの向きを変える

        if (key != 0)
        {
            transform.localScale = new Vector3(key, 1, 1);
        }

lacalScaleは、スクリプトでスプライトの拡大率を変えることができる。
TransformコンポーネントのlocalScale変数の値を変更することによって、プレイヤが右や左と向きを変えることができる。

NekoNeko

#2-6

主人公の動きに合わせて、カメラを動かす
カメラをスクリプトで移動させる
まず、カメラもGameObjectであるため、Controllerスクリプトで移動させることができる。

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

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

    // Update is called once per frame
    void Update()
    {
        // フレームごとに、このプレイヤの座標(position)を調べる
        Vector3 playerPos = this.player.transform.position;
        // 
        transform.position = new Vector3(transform.position.x, playerPos.y, transform.position.z);
    }
}