Unity3D+シューティングゲームのオブジェクトプールのチュートリアル

Blogをいつもご覧いただきありがとうございます。

シューティングゲームを作った時に、武器の弾のシステムは様々な書き方がありますが、一番シンプルな書き方は、恐らく弾のオブジェクトをインスタンスして、敵にヒットしたら(コード側ではコライダーやポジションでどちらでも可能です。)、敵と弾一緒に消滅すると思います。

弾を生成する場合の例:

using UnityEngine;
using System.Collections;

public class BulletInstance : MonoBehaviour {
public GameObject BulletPrefab;
// Update is called once per frame
void Update () {                                                                                                            
 GameObject bullet = Instantiate(BulletPrefab, Vector3.zero, Quaternion.identity) as GameObject;   //弾をインスタンス 
}

弾と敵を消滅する場合の例:

using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour {

void OnTriggerEnter(Collider other)
 {
   if (other.tag.CompareTo("Bullet") == 0)
    {
       Destroy(other.gameObject);//弾が消される
       Destroy(this.gameObject);//敵自分が消される
    }
 }
}

この書き方は普通に動くはずですが、でも、常に弾のPrefabをインスタンスしたり、Destroyしたりしたら、メモリー上にとってあまり優しいとはいえません。正直に言うとPC用としてはまだしも、スマートフォンゲームの場合はかなりきびしいものになると思います。
オブジェクトをずっと増やし続けるとゲームのFPSが落ちたり、重くなったり、スマートフォンが熱くなったりするのもおかしくないです。

それをさける為に、考えを逆にするのはどうでしょうか?

プログラム側では、オブジェクトのInstanceやDestroyの場合にリソースを消費しているとしたら、なら、常にInstanceやDestroyしないシステムを作ればいいじゃんないか?

それでは、オブジェクトプールを勉強しましょう!

·オブジェクトプールの概念

オブジェクトプールとは、この先使えるオブジェクトを溜めておく用の倉庫のような存在で、オブジェクトが必要になったら取り出し、使い終わったら戻すことで、なるべく少数のオブジェクト使い回してオブジェクト数及び生成・消滅のコストを抑えるものです。

それでは、実際にUnity3D側で作っていきましょう。

·実装

Step1 Unityの環境作り

Step2 弾のプールシステム

ここで二つのスクリプトが必要です。

  • BulletPool.cs  このスクリプトはオブジェクトプールで、オブジェクトにドラッグドロップする必要はありません。
  • Bullets.cs     このスクリプトは弾のPrefabにドラッグドロップするスクリプトです,弾の方向やスピードをコントロールしています。
実装コード:

BulletPool.cs

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

public class BulletPool : MonoBehaviour {
    //オブジェクトのプールとしてのリストを作る
    List pools = new List();
    // start pos
    Vector3 firstPosition;
    //シングルトン
    private static BulletPool instance;
    private BulletPool() { }
    public static BulletPool GetInstance()
    {
        if (instance == null)
        {
          
            instance = new GameObject("BulletPool").AddComponent();
           
        }
        return instance;

    }
   
    //オブジェクトプールからオブジェクトを取得する
    public GameObject MyInstantiate(GameObject name)
    {
        //オブジェクトプールは空だから、インスタンスする
        if (pools.Count == 0)
        {
            return Instantiate(name, Vector3.zero, Quaternion.identity) as GameObject;
        }
        else 
        {
           
            //もしプールでは空じゃない場合は「0」を取る
            GameObject go = pools[0];
           
            go.SetActive(true);
            //オブジェクトプールから消される
            pools.Remove(go);
            return go;

        }
    }
    //オブジェクトプールを作成
    public void DelayInstantiate(GameObject name)
    {
        //オブジェクトを隠す
        name.SetActive(false);
        //オブジェクトプールに入れる
        pools.Add(name);
    }
}

Bullets.cs

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

public class Bullets : MonoBehaviour
{
    Transform target;
    private void OnEnable()
    {
        //ポジションを初期化する
        target = GameObject.Find("Hero").transform;
        transform.position = target.position;
        //二秒の後でCoroutineを実行する
        StartCoroutine(DelayObject(2f));
    }
    private void Update()
    {
        //弾の移動
        transform.Translate(Vector3.up * Time.deltaTime * 100);
    }
   
    IEnumerator DelayObject(float time)
    {
        yield return new WaitForSeconds(time);
        //弾のプールリストに入れる
        BulletPool.GetInstance().DelayInstantiate(gameObject);
    }

}

 

Step3 Playerのコントロール

弾のプールを実装完了したら、次は発砲の機能や移動の機能が入ってる”PlayerControlManager.cs”を「Hero」のオブジェクトにドラッグドロップしてください。

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

public class PlayerControlManager : MonoBehaviour {

    float _hor_Speed = 1f;    //水平移動の速度
    float _ver_Speed = 1f;  //垂直移動の速度 
    float _topMax = 300f;//Player移動制御の変数
    float _bottomMax = -300f;//Player移動制御の変数
    float _sideMax =177f;//Player移動制御の変数
    float _turnAngle = 45;//回転の角度
    GameObject bulletPrefab;
    void Awake(){
        bulletPrefab = Resources.Load("Prefabs/Bullet") as GameObject;

    }
    void Update()
    {
        Move();
        TurnBody();
        Limit();
        Fire();
    }

    void Fire()//発砲
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            BulletPool.GetInstance().MyInstantiate(bulletPrefab);
        }
    }
    
    void Limit()//移動制御
    {
        if (transform.localPosition.x > _sideMax)
        {
            transform.localPosition = new Vector2(_sideMax, transform.localPosition.y);
        }
        if (transform.localPosition.x <  -_sideMax)
        { 
            transform.localPosition = new Vector2(-_sideMax, transform.localPosition.y); 
        } 
        if (transform.localPosition.y > _topMax)
        {
            transform.localPosition = new Vector2(transform.localPosition.x, _topMax);
        }
        if (transform.localPosition.y < _bottomMax)
        {
        transform.localPosition = new Vector2(transform.localPosition.x, _bottomMax);
        }
    }

    void TurnBody()//機体を回転する
    {
        if (Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.LeftArrow))
        {
            transform.Rotate(new Vector3(0, _turnAngle, 0));
        }
        if (Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.RightArrow))
        {
            transform.Rotate(new Vector3(0, -_turnAngle, 0));
        }
        if (Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.LeftArrow))
        {
            transform.Rotate(new Vector3(0, -_turnAngle, 0));
        }
        if (Input.GetKeyUp(KeyCode.D) || Input.GetKeyUp(KeyCode.RightArrow))
        {
            transform.Rotate(new Vector3(0, _turnAngle, 0));
        }
    }
    void Move()//Playerの移動
    {
        float ver = Input.GetAxis("Vertical");
        float hor = Input.GetAxis("Horizontal");
        transform.position +=new Vector3(hor * _hor_Speed, ver * _ver_Speed, 0);
    }

 }

   

上記の流れに沿って実装ができたら、プロジェクトをPlayしてください。

こんな感じですね

·注意点:

  • オブジェクトプールは非常に便利です。使う場面として繰り返し利用するオブジェクトを生成する場合に有効です。今回の場合は弾や敵などです。
  • 使う場合によっては逆効果が出る可能性もあります。実際にゲームのジャンルやシステム、オブジェクトの特徴などによって、どのような形式のオブジェクトプールを使うのか考える必要があると思います。
  • オブジェクトを破棄する代わりに隠す(表示しないようにする)ことで、表示的には破棄と同等の効果実現してます。そのおかげでオブジェクトをインスタンス化する際のリソースの無駄な消費を抑えられると思います。

※補足情報としてオブジェクトプールを利用することで、オブジェクトのインスタンス化をできるだけ削減しましたが、既にインスタンスされたオブジェクトはSetActive(false)になっても、まだメモリーの中に存在し、メモリーの容量を占有しています。メモリの占有が完全になくなるわけではありません。

ご覧いただきありがとうございました。

カスタムビルド解像度設定がリビルドで変更されない場合の対処

Unityでカスタム解像度を使ってビルドするとき、選択された会社名とアプリ名にリンクされたその解像度でプレーヤー設定ファイル を作ります。 問題は、その後そのカスタム解像度を変更してプロジェクトを再構築したい場合でも、古いプレーヤー設定ファイルがあるコンピューターに表示されるものが一度設定した解像度になることです。

たとえば、解像度を800×600のカスタムサイズに設定してビルドした場合は、このようになります:

後でカスタム解像度を1920×1080に変更して再ビルドしても、同じ800×600の解像度が表示されます。

その解像度を適切な解像度に設定するには、2つの方法があります:

最初の方法は、ビルドプレイヤー設定に新しい会社名を設定することです。 その後、その名前であなたのシステムに新しいプレイヤー設定フォルダを作成します。

二番目の方法は、レジストリファイル内の設定フォルダを見つけて削除することです。 そのようにあなたの新しい解像度設定のファイルを作成します。 そのファイルはレジストリエディタのHKCU / softwareの中にあります。

Unity HubでインストールしたUnityのVuforiaプラグインをアップデートする方法

Unity Hubはとても便利で新しい機能ですが、Vuforiaをアップデートする場合、少し面倒な手順が必要になります。

最新のUnityのバージョンを既にインストールしていて、そのUnityと共にインストールされたVuforiaのバージョンよりも更に最新のVuforiaがリリースされている場合、下記の手順でVuforiaをアップデートできます。

Unityを起動するときにVuforiaは無効の状態になっています。(Image1)。

とりあえず、Vuforiaを使用するため、
File>Build Settings>Player Settigsボタン
または
Edit>Project Settings>PlayerからPlayer Settingsを開き、
(Image2)
Player settingsのVuforia Augmented Realityオプションをチェックする必要があります。

(Image3)
Vuforia Configurration Pannelの出し方
すると Vuforia Configuration Panel Vuforia Update のリンクをクリックできるようになります。(Image4)。

Image1

Image2

Image3

Image4

ここで一旦Unityを閉じてください。

ダウンロードが終わったら、

VuforiaSupportInstaller-Windowsの圧縮ファイルを解凍し、UnitySetup-Vuforia-AR-Support-for-Editorのイントラーをダブルクリックします。

UnitySetupアイコンを選択してください(Image5)。

インストールを続いて、Destination Folderのページを見えたらBrowseボタンをクリックしてください(Image6)。
ここで、Vuforiaの最新を適用したいUnityのバージョンの実行ファイルが置かれているパスを指定します。

Image5

Image6

 

Program FilesフォルダーにあるUnityフォルダーを選択してください(Image7)。(注意:Unity Hubのフォルダーではありません。Unity自体の実行ファイルがあるフォルダを指定する必要があります。

Image7

それでUnityをアップデートするバージョンを選択し、OKボタンを選択してください(Image8)。
Image8

次のウインドで選んだフォルダーを確認できます(Image9)。それでインストールを最後まで続けてください。

Image9

 

Unityを起動するとVuforiaがアップデートされていることが確認できます(Image10)。

Image10

Large SQL imports in phpMyAdmin (LINUX server)

PhpMyAdmin is a very popular graphic interface for SQL servers. One of the problems I encountered when I was starting to work with it, was the (Max: 2,048KiB) file size restriction for choosing a file to import.  

私がphpMyAdminを使い始めたころにインポートできるファイルサイズの制限で困ったため今回はその解決方法についてポストします。

Of course there are multiple ways to import a large SQL file into your server, but on this tutorial, we are going to be doing it with phpMyAdmin’s upload directory.   

制限より大きなファイルをサーバーにインポートするやり方がいくつかありますが、このチュートリアルはphpMyAdminのアプロードディレクトリを使った方法を利用します。

Prerequisites 

  • This tutorial assumes you have phpMyAdmin already installed on your server. 
  • We are going to be working on an Ubuntu 14 server so the directory paths might differ from your server but the premise doesn’t change. 
  • You are going to need ssh access into the server, and super user privileges to modify files and directories. 
  • Please try this on a local or test environment before you go and do it on the production server.

前提条件

  •  phpMyAdminはすでにインストールされている
  • このチュートリアルでUbuntu14のサーバーを使っているのでディレクトリのパスが皆さんのと違うかもしれませんがやることが変わりありません。
  • サーバーにSSHアクセスとスーパーユーザーの権利が必要です。
  • プロダクションサーバーで実装する前にテスト環境で試してみてください。

Step 1 

Create an upload folder in the phpmyadmin directory. In our case its /etc/phpmyadmin 

phpmyadminのダイレクトリーにuploadフォルダを作りましょう

$sudo mkdir /etc/phpmyadmin/upload 

 

Step 2  

Give write permissions to the necessary users. We are going to be giving permission to all users but some people might want to be more specific here. 

書き込む権利を必要なユーザーにあげましょう。この場合は全員に権利を付与しておりますがセキュリティの責任者に聞いてください。

$sudo chmod a+w /etc/phpmyadmin/upload 

 

Step 3 

Open the configuration file on a text editor. (We are using nano, but any editor should be fine) 

テキストエディタでコンフィグレーションファイルを開きましょう。(サンプルコードではnanoを使っていますがお好みのテキストエディタで問題ありません)

$sudo nano /etc/phpmyadmin/config.inc.php 

Navigate the file until you find the following line

次の行を探しましょう

$cfg['UploadDir'] = '';   

and edit it to  the following

見つかったら、編集しましょう

$cfg['UploadDir'] = '/etc/phpmyadmin/upload';

Save and exit the editor. 

保存して閉じてください。

 

And that’s all the setup you are going to need. To make sure everything is working correctly, you can log in to phpMyAdmin ad go to the Import tab. Under the Browse your computer option the new Select from the web server upload directory /etc/phpmyadmin/upload/: option should be available to you now.  

これで準備が整いました。正しく出来たことを確認するためにはphpMyAdminにログインして、インポートのタブにクリックします。参照オプションの下にサーバーアプロードダイレクトリーから選択のオプションが選べられるようになったはずです。

Now all you have to do is place the SQL file you want to import inside that upload directory and the file will show up in the drop-down for you to select. 

インポートしたいSQLファイルを先ほど作ったuploadダイレクトリーに入れることでドロップダウンから選択できるようになったはずです。

Unity3D+IK(Inverse Kinematics)のAnima2Dチュートリアル

Blogをいつもご覧いただきありがとうございます。

前回は「Unity3D+Anima2Dチュートリアル」というテーマの記事を投稿しました。

今回はAnima2dのInverse Kinematicsについて説明したいと思います。

Inverse Kinematicsとは何ですか?

Anima2Dには、Inverse Kinematicsのコンポーネントがあります。これを使い、親関係のボーンオブジェクトの子供を動かすと、親も連動し動きます。

例を挙げると、腕と肩の関係のようなものです。(以下省略”IK”です)。

シンプルなアニメーションは、ボーンをいじるだけで充分ですが、もしアニメーションが複雑な場合はかなり時間がかかると思います。

そういう場合は「IK」が便利です。移動させたいボーンを「IK」と繋げればこのボーンのチェーンを丸ごと動かすことができとても便利です。

 

IKの種類は?

 

Anima2DのIKには,IK CCDIK Limb という2種類のIKがあります。

IL Limbは骨を2本しかコントロールできません、余弦定理ですので、今回の場合手足に利用します。

IK CCD は設定に応じて、最大コントロールできる本数がルートボーンまでの全部の骨をコントロールすることができます。今回の場合頭と尻尾に使います。

 

では、前回の引継き、IKの使い方を説明します。
IKをの使い方を説明する前に、先ずAnima2Dの効率をアップでさせる機能を紹介したいと思います。

「PoseManager」というものです。

使い方はとても簡単です。下記の画像のように、前回の「牛」のオブジェクトに「Pose Manager」を入れれば、使えるようになるはずです。

そして、「Create new pose」をクリックしたら、今のスプライトのポジションとローテーションがセーブできます。

一つの「Idle」のポーズを「Save」をクリックしてから、後はどんな調整しても、ただ「Load」ボタンをクリックしたら、最初設定のポーズに戻れます。(ちなみに、「Save」はオーバライドしますので、ご注意ください。)

「Pose Manager」の使い方はここまでです。

それでは、「IK」の使い方の説明に入りましょう。

Step 1: IKをクリエイトします

「牛」のオブジェクトの中に、もう一個の空のオブジェクトを作って、名付け「IK」です。

下記の画像のようにそのオブジェクトに右クリックして、「2D Object」→「IK Limb」をクリックしたら、「IK」が出ます。

では、「IK」のパラメータを説明しましょう。

  • Record:アニメーションモードの間,ボーンのキーフレームを記録します。
  • Target: IKが適用されるボーン。
  • Weight:​IKのポーズに対する影響度。
  • Restore Default Pose: 計算を実行する前に最初のポーズを設定します。
  • Orient Child:ターゲットの子ボーン(使用可能な場合)をIKローテーションに回転させます。
  • Num bonesIKの影響を受けるボーンの数.最大はルートボーンまで。
  • Iterations solverの反復回数。
  • Dampingソルバのステップ速度を制御する.値が小さいと変化が見やすい,大きいと変化が見にくいです。Dampingの値が大きければ、もっと自然に見えるかもしれません。

 

Step 2:「IK」をコントロールしたい関節に配置します

下記の画像のように、三つの「IK」をクリエイトして、分かりやすい名前を付けてから、それぞれにコントロールしたいところに置いてください。

上記の説明の通り、「頭」の部分には、使っているのはIK CCDです。

お気付きだとおもいますが、このグレーのリングを自分が望んでいる所に配置しても、スプライトはまだコントロールできません。

なぜかというと、下記の画像表示の通りに、右側の「Inspector」の「Target」はまだ「None」になっていますので、コントロールできるオブジェクトはまだありません。

では、「Target」に相応の「Bone」オブジェクトに入れてみてください。

設定が終了したら、グレーのリングは青のリングに変わります。

では、下記の画像の手順通りにすれば、左側のコントロールしたい「IK」のオブジェクトをクリックして、右側のリングを移動したら、「牛」全身が一緒に動きます。

注意点:偶にリングを移動しても、欲しい角度に合わせられない場合があったら、下記の画像の状態で「IK」の「Inspector」の「Filp」のチェックを入れてから、もう一度調整すれば、合わせられると思います。

適用後の図:

これで、「IK」のリングを弄れば、簡単に関節が調整できるようになりました。

複雑なボーンが入っているスプライトでは、「IK」はとても役に立ちます。

今回のインバース キネマティクス(IK)の使い方はここまでになります。

では皆さん、次回の内容をご期待ください!

Unity3D+Anima2Dチュートリアル

Blogをいつもご覧いただきありがとうございます。
先日、「Unity+Myo(ジェスチャーを活用して牛乳を搾るゲームを作りました)」というテーマのブログを発表しました。

下記のURLはゲームの映像です。
https://www.youtube.com/watch?v=4Jz7y1n3Iec

その中の「牛」はAnima2Dプラグインを利用して制作しました。Anima2Dの使い方のチュートリアルとして今回はAnima2Dを利用して「牛」を動かしてみましょう!

Anima2Dのメリットは?
  • Unity3Dのアニメーションと同じ感覚で2Dキャラクターが動かせます。
    • スキニングとBoneが付くアニメーションを作ることができます。
    • Spriteの各頂点編集することができます。
    • 全部アニメーション(Unity3Dの標準機能)でコントロールすることができます
Step1 Anima2Dをインストール
  • AssetStoreからAnima2Dを検索し、ダウンロードしてから、インポートをしてください。
Step2 「牛」の画像を分割

上記の画像はまだ分割していない状態です。

ゲームでは「頭」、「足」二本、「体」を分けたいので、こちらで「Gimp2」でこの4つの部分を分割しました。

そして、分割した画像をUnityにインポートして、下記の状態になりました。

画像のInspectorのTexture TypeSprite (2D and UI)に変更するのを忘れないで下さい。

これで、下準備は完了です。

Step3 SpriteMeshを作る

ここから本番ですね。先用意した画像を選択して、右クリックしてSpriteMeshが作れます。( Create→Anima2D→SpriteMesh)

上記のステップで、拡張子が「asset」のファイルができると思います。保存先が分からなくなってしまわぬよう独立のフォルダーを入れるとよいと思います。

Step4 SpriteMeshをSceneに配置

これから、作り上げたSpriteMeshをシーンに配置します。

まず、シーンにempty GameObjectを作って、この中で二つ空のGameObjectを作ります。下記の画像ご参考までに。

そして、SpriteMeshを一個ずつBodyのGameObjectに入れます。(一気に全部選択しても一個ずつしか入りませんので)

全部入れて、元「牛」の四肢のようにポジションを調整したら、下記の画像のようになるかと思います。

Step5 SortingLayer、OrderLayerの調整

ですが、牛の頭が体に隠れてしまってるように見えますので、そこで、OrderLayerの順位を調整します。

  • 先ず、SpriteMeshのSortingLayerを全部同じにします。SpriteMeshのオブジェクトを選択して、右側は下記のようにします。

デフォルトの状態で全部のSpriteMeshのOrderLayerは0になっていますので、一番前に表示したい物のLayerの順位を0より大すると前面に表示できます。

今回の場合は牛の頭を体の前に表示しようと思いますので、頭のオブジェクトを選択して、OrderLayerは1にすれば、一番前に表示できるようになると思います。

これで、SortingLayerとOrderLayerの説明は維持上です。

Step6 Boneを入れる

これがAnima2Dのとても大事な機能です。スプライトに骨を付けることができます。

先ず、先ほど作ったBoneというゲームオブジェクトに右クリックしてください。

下記の画像のように選択します。

こうすれば、新しいBoneオブジェクトがインスタンスされます。自分が分かりやすい名前を決めてください。

そして、「Torso」の中で頭、両足の2DBoneを作って、針みたいなものを相応の所に配置します。

注意点:上記の赤い箇所で示している所は「骨」の長さです、スプライトの大きさに相応して決めてください。

そして、BoneとSpriteMeshを繋げましょう!

下記の画像の通りにそれぞれのBoneオブジェクトをSpriteMeshのSet bonesの所に入れます。

注意点:繋げたくない部分があれば、右クリックで削除してください。

これで、BoneとSpriteMeshは繋がりました。

とは言え、Boneを動かしてみたら、Meshの方は全然ついて来きません。それはなぜでしょうか?次のステップで解決していきます。

Step7 SpriteMeshはBoneと一緒に動かす

SpriteMeshはBoneと一緒に移動できるようにする場合は、先ず、移動させたいSpriteMeshを選択したまま、「Window」をクリックしてください。そして、「Anima2D」→「Sprite Mesh Editor」を押してください。

開いたら、下記の画面が表示します。

注意点:赤い箇所は頂点の数がコントロールできます。今回はデフォルトの設定で十分だと思いますので、デフォルトのままで行きます。

次は「Bind」の方に進みましょう。

設定する前に、先ず右下の「Overlay」をチェックしてください。そして、影響範囲が可視化されてもっとわかりやすくなるのでしょう。

次は右上の「Apply」を押したら、MeshとBoneは一緒に動かすことができるはずです。

全部上記の設定が完了すると、牛の頭を移動しても体のSpriteMeshも一緒に連動して動きます。

次回はインバース キネマティクス(IK)の使い方を説明したいと思います。

Unityでのアプリ内のムービー表示方法と、常に正しい解像度と比率を維持するように設定する方法。

How to create a movie screen with unity, and to set it to keep the right resolution and ratio at all time. 

ユニティでムービー画面を作成する方法と、常に正しい解像度と比率を維持するように設定する方法。

First you will need to import a video, the list of the supported format in unity can be found here : 

最初にビデオをインポートする必要があります。サポートされているフォーマットのリストはここにあります: 

https://docs.unity3d.com/Manual/VideoSources-FileCompatibility.html

Next, to be able to render the video on screen, you will need to create a special type of texture: a Render Texture. To do that, make a right click on the Project Window, go to create and select Render Texture.  

次に、ビデオをスクリーン上でレンダリングできるようにするには、特別なタイプのテクスチャ:Render Textureを作成する必要があります。 これを行うには、Project Windowを右クリックし、作成して「Render Texture」を選択します。 

Then, to be able to display this render texture on a ui element you will need to create a Raw Image by right clicking on the Hierarchy window and select Raw Image in the UI tab.  

次に、このRender TextureをUI要素に表示するには、Raw Imageを作成する必要があります。Hierarchy windowを右クリックし、[UI]タブの[Raw Image]を選択します。 

Make the Raw Image the same size than the Canvas. And set the Anchor to stretch in all directions. 

Raw ImageをCanvasと同じサイズにします。 Anchorをすべての方向に伸ばすように設定します。 

 

You now have to put the Renderer Texture in the texture element of the raw image. 

これで、Renderer TextureをRaw Imageのテクスチャスロットに配置する必要があります。 

You also need to add a Video Player component to the Raw Image, to drag and drop the video in the Video Clip element and to set the Render Texture as the Target Texture. 

Raw ImageにVideo Playerコンポーネントを追加して、ビデオをVideo Clip要素にドラッグアンドドロップし、Render TextureをTarget Textureとして設定する必要があります。 

Then if you play the scene you will notice that the video is playing but the ratio and the quality of the video will be really bad. That’s because the size of the Render Texture doesn’t match the size of the video (the video used here is 1280×720).  

シーンを再生すると、ビデオが再生されていることがわかりますが、ビデオの比率と品質はとても悪くなります。 これは、Render Textureのサイズがビデオのサイズと一致しないためです(ここで使用されるビデオは1280×720です)。 


You need to give the Render Texture the same size than the video to make it displaying properly.

Render Textureをビデオと同じサイズにして、適切に表示させる必要があります。  

To make the video scale accuratly on different screen size (for exemple on different smartphone size), set the “UI Scale Mode” of the canvas holding the Raw Image to “Scale with screen size”, the “Reference Resolution” the same than the Render Texture, the “Screen match mode” to “match width or weight” and the “Match” to 0.5. 

さまざまな画面サイズ(例えばスマートフォンサイズ)のビデオスケールを正確に作成するには、Raw Imageを保持するキャンバスの「UI Scale Mode」を「Scale with screen size」に設定して、 「Reference Resolution」をRender Textureと同じにして、「Screen match mode」を「match width or weight」に設定して、「マッチ」を0.5に設定します。 

 

Notes: 

注釈: 

*It is also possible to play a video on a GameObject by putting a video player on this object and setting the “Render Mode” of this component to “Material Override”.(Usefull to render 360 videos for exemple). 

*GameObjectでビデオを再生することもできます。このオブジェクトにビデオプレーヤーを置き、このコンポーネントの「Render Mode」を「Material Override」に設定します。(例えば360ビデオをレンダリングするため) 

*You can set the “Audio output mode” of the video player to “Direct” if you want the sound of the video to play, or to put it to “Audio source” if you want to play a separate sound file. (the direct sound mode doesn`t work yet on android smartphones). 

ビデオのサウンドを再生する場合はvideo playerの「Audio output mode」を「Direct」に設定し、別のサウンドファイルを再生する場合は「Audio source」に設定します。 (Directサウンドモードはアンドロイドスマートフォンではまだ動作しません)。 

(Unity3D)ダイナミックボタンアクション

あるゲームのUIを作っている間にボタンに関する問題に遭遇しました。選択されたエンティティによって、表示されているボタンが変わるようにしたいと思いました。

もちろん一つずつのエンティティのGameObjectを準備して場合によってSetActive()trueかfalseにしてもいいですが、スケーラビリティは?エンティティを追加しようとする毎に新しいGameObjectを準備しますか?そんな面倒なことは勘弁してほしいですよね。

ということでスケーラビリティのため、エンティティを選択する時にボタンが編集され、ちょっとしたアルゴリズムを書きました。 

こういうシステムが入っているUIを作る人がいて参考になればと思い、分かりやすいバージョンを準備して下記にそのケースを紹介します。 

想定ケース: 

1.エンティティによる、ボタンの数が異なる場合でもOK。 

2.ボタンの見た目を編集可能にする。 

3.ボタンのアクションがstringの引数を受け取れる。 

4.簡単にするため、ボタンの最大数は10にします。 

先ずはボタンの情報をまとめるクラスActivityButtonをつくります 

public class ActionButton {
    public UnityAction<string> theAction;
    public string argument;
    public Sprite sprite;
    public ActionButton(UnityAction<string> act, Sprite sprite, string arg=""){
        theAction = act;
        argument=arg;
        this.sprite = sprite;
    }
}

UIマネージャーにはButton、Image、GameObjectの配列を必要です。パブリックなGameObjectの配列を作ってシーンからボタンをドラッグして、Start()でButtonとImageの配列を作りました 

public class MyEpicUIManager : MonoBehaviour {
    Button[] actionBtns;
    Image[] actionImgs;
    public GameObject[] actionBtnObjs;

    void Start () { 
        // Action Panel Setup
        actionBtns = new Button[actionBtnObjs.Length];
        actionImgs = new Image[actionBtnObjs.Length];
        for(int i=0; i<actionBtnObjs.Length; i++){
            actionBtns[i]=actionBtnObjs[i].GetComponent<Button>();
            actionImgs[i]=actionBtnObjs[i].GetComponent<Image>();
        } 
    }
}

ボタンをゲットしたので、次はActionButtonのリストを取得しボタンを編集するメソッドを作りました。そしてボタンをクリアするメソッドも必要です。 

public void SetActions(List<ActionButton> btnActions){
    ClearActions();
    for(int i=0; i<btnActions.Count; i++){
        actionBtnObjs[i].SetActive(true); 
        UnityAction<string> action = btnActions[i].theAction;
        string arg = btnActions[i].argument;
        actionBtns[i].onClick.AddListener(()=>action(arg)); 
        actionImgs[i].sprite = btnActions[i].sprite; 
    } 
}

public void ClearActions(){
    for(int i = 0; i<actionBtnObjs.Length; i++){
        actionBtns[i].onClick.RemoveAllListeners();
        actionBtnObjs[i].SetActive(false);
    }
}

これでUIマネージャーが完了です。Start()でClearActionsを呼べば、ゲームを起動する際にボタンクリアできます 

エンティティにはそれそれに自分のActionButtonリストが必要です。UIマネージャーのSetActionsを呼べるようにする必要があります。そしてアクション自体も必要です。

public class MyEntity1 : MonoBehaviour {
 
    public MyEpicUIManager ui;
    List<ActionButton> uiActions = new List<ActionButton>();

    void Start(){
        uiActions.Add(new ActionButton(Action1,Resources.Load<Sprite>("Sprites/E1A1"))); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E1A2"), "Test argument 1")); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E1A2"), "Test argument 2")); 
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E1A3"), "3"));
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E1A3"), "5")); 
    }

    // An action that doesn't really use the string provided 
    public void Action1(string s =""){
        print("Entity 1 Action 1");
    }

    // An action that uses the string
    public void Action2(string s =""){
        print("Entity 1 Action 2 Argument: " + s);
    }

    // An action that changes the string to an int
    public void Action3(string s =""){
        string msg = "Entity 1 Action 3 ->"+s+" hashes: ";
        int n = 0;
        int.TryParse(s, out n);
        for(int i=0; i <n; i++) msg+="#";
        print(msg);
    }

    public void OnSelect(){
        ui.SetActions(uiActions);
    }
} 
public class MyEntity2 : MonoBehaviour {
 
    public MyEpicUIManager ui;
    List<ActionButton> uiActions = new List<ActionButton>();

    void Start(){
        uiActions.Add(new ActionButton(Action1,Resources.Load<Sprite>("Sprites/E2A1"))); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E2A2"), "Test argument 1")); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E2A2"), "Test argument 2")); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E2A2"), "Test argument 3"));
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E2A3"), "3"));
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E2A3"), "5")); 
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E2A3"), "7")); 
    }

    // An action that doesn't really use the string provided 
    public void Action1(string s =""){
        print("Entity 2 Action 1");
    }

    // An action that uses the string
    public void Action2(string s =""){
        print("Entity 2 Action 2 Argument: " + s);
    }

    // An action that changes the string to an int
    public void Action3(string s =""){
        string msg = "Entity 2 Action 3 ->"+s+" asteriscs: ";
        int n = 0;
        int.TryParse(s, out n);
        for(int i=0; i <n; i++) msg+="*";
        print(msg);
    }

    public void OnSelect(){
        ui.SetActions(uiActions);
    }
}

こちらはエンティティのサンプルです。OnSelectはキーボードかシーン上のボタンで試してみてください。このサンプルを動かすため “Assets/Resources/Sprites”に、正しい名前のスプライトを入れてください。そしてスプライトのImport SettingsのTexture Typeは “sprite (2D and UI)”にする必要があります。 

シーンに必要なものはCanvasと7つ以上のボタンです。UIマネージャーをシーンに追加して、インスペクターでボタンをドラッグします。エンティティもシーンに追加してインスペクターでUIマネージャーをドラッグしてください。 

それで完了です。短くて簡単な例となりますが、これでエンティティを追加ときにいちいち新しいパネルを準備する必要がなくなります。そしてアクションを追加したり削除する場合でも、リストから追加したり削除することで実現できます。

特定のUI要素上でマウスのローカルポジションを見つける

まず、特定のUI要素が特定されているかどうかを調べる必要があります。UI要素がマウスでクリックされているかどうかを判断する方法は複数ありますが、最も一般的な方法はUnityのPointerEventSystemを使用することです。使用できるようにするには、イベントをトリガーするために必要なさまざまなインターフェースと“using UnityEngine.EventSystems;”というNamespaceを実装する必要があり、SceneのHierarchyにEventSystemを追加することも必要です。また、スクリプトはトリガーされたオブジェクト上にある必要があります。
 
このEventSystemの詳細については、このリンクをご覧ください:
https://docs.unity3d.com/ScriptReference/EventSystems.PointerEventData.html

EventSystemの実装例を次に示します:

別の方法はUnityのBoundsを使用します。

イメージのようなUIオブジェクトでそれを使用できるようにするには、コライダーを置いてオブジェクトと同じサイズにする必要があります。次に、Boundsを見つかるために、このコライダーコンポーネントをスクリプトで取得します。これにより、マウスの位置がこれらの範囲内にあるかどうかを確認することができます。

Bounds についての詳細は、このリンクをチェックしてください:

https://docs.unity3d.com/ScriptReference/Bounds.html

Bounds の実装例を次に示します:

オブジェクトをHoveringしていることがわかったので、次のステップは、マウスの位置を世界に相対的ではなく、そのオブジェクトに関連させて見つけることです。そのために、UnityのRectTransformUtilityを使用することができます。ローカルのRectTransformを新しいスクリーン位置として設定することができます。

RectTransformUtility についての詳細は、このリンクをしてください:

https://docs.unity3d.com/ScriptReference/RectTransformUtility.html

https://docs.unity3d.com/ScriptReference/RectTransformUtility.ScreenPointToLocalPointInRectangle.html

RectTransformUtility の二つの実装例を次に示します、1つはBoundsシステムを使用し、もう1つはEventSystemを使用します。

Boundsシステム:

EventSystem:

*canvasがScreen space – Overlayに設定されているため、カメラパラメータはnullに設定されています。
このlocal mouse positionはいろいろな使い方ができます。 たとえば、カンバスにある、レンダーテクスチャを使用してミニーマップ上でクリック位置を取得することができます。

FFmpegの動画圧縮・変換コマンドの使い方

ちょっとした動画をアップロードしたいとき、スマートフォンなどでの動画撮影は大変便利ですが解像度が高すぎて容量が大きくなりがちです。動画のサイズを小さくしたい、変換したいときFFmpegはとてもパワフルなツールです。
Taking a small video with a smartphone is very easy but the resolution might be too high for uploading.
To reduce the size of the video, you can use  FFmpeg to convert it ,it is a very powerful tool.

なかでも使用頻度が高く、個人的によく使うコマンドを下記に記載します。
各コマンドは圧縮元ファイルがbinフォルダの直下にある場合を前提としています。
Among the frequently used commands here are the most efficient ones in my opinion.
Each command assumes that the source file is located directly under the bin folder.

コマンドプロンプトでbinフォルダまで移動して、
ffmpeg -i 圧縮元ファイル 圧縮率設定 出力ファイル名
の順で記述すると圧縮してくれます。
Each command assumes that the source file is located directly under the bin folder.with the command prompt, navigate to the bin folder and write in this format:

for compression:

[text]ffmpeg -i exapmle_original.mp4 -crf 10 exapmle_compressed.mp4[/text]

exapmle_original.mp4(オリジナルファイル)を圧縮率10でexapmle_compressed.mp4(圧縮したファイルのま名前を記述)
The original file will be compressed by a ratio of 10.

圧縮率は数字が大きいほど高圧縮です。
32くらいだとスマホで撮った動画を圧縮した場合に、ちょうどよい容量でした。
You can increase the ratio value To make a higher compression.
For movies taken with smartphones, 32 seems like good ratio.

また、サイズ変更も可能です。
For scaling:

[text]ffmpeg -i sample.mp4 -vf scale=320:-1  sampleout.mp4[/text]

縦横比をそのままに、sample.mp4から幅が320pxの動画を作ることが出来きます。縦のサイズ−1(-vf scale=320:-1 部分)と指定するだけで、アスペクト比から自動計算されます。
You can create a movie with a width of 320px and keep the aspect ratio intact by setting the second parameter to -1.

そのほか、「iPhoneで動画をとったが縦にとるつもりが横向きになっちゃった。なおらないかなぁ」のような場合も下記のコマンドで一発解決できます。
To change landscape to portrait:

[text]ffmpeg -i sample.mp4 -vf "transpose=1" sample_rotate.mp4[/text]

時計回りに90度回転 -vf transpose=1 部分
This will rotate clockwise 90 degrees

180°回転させた場合は下記のとおりです。
If you want rotate by 180 :

[text]ffmpeg -i sample.mp4 -vf "rotate=180*PI/180" sample_rotate180.mp4[/text]

※180の部分を任意の数値に入れ替え可能です。
* You can choose any number for the rotation.

ムービー撮影時、話ながら動画を撮影してしまい映像のサウンドを無音化したい場合は
To mute the sound:

[text]ffmpeg -i exapmle_original.mp4 -an exapmle_nosound.mp4[/text]

で無音化したり、

さらに応用例としては画面右隅に別の動画を小さく入れたるようなPinP映像も
To insert a movie in the lower right corner of another movie:

[text]ffmpeg -i mainmov.mp4 -i submov.mp4 -filter_complex "[1]scale=iw/2:ih/2 [pip]; [0][pip] overlay=main_w-overlay_w-20:main_h-overlay_h-20" -profile:v main -level 3.1 -b:v 440k -ar 44100 -ab 128k -s 1920x1000 PinP.mp4[/text]

上記のようなこともコマンドで実現可能で大変便利なツールです。
These are just a few examples to show you the power of this amazing tool.
If you want to know more please visit FFmpeg official website documents!