Unityで動画ファイルを再生する



Unityで動画を再生させるのがすごい簡単だったので驚いたのですよ。

平面オブジェクトに動画を貼り付けてそれを再生させたり停止させたりします。

まずCreate から 3D object → Plane を選択
プロジェクトビューに再生したい動画をD&D
テクスチャを貼り付けるみたいにオブジェクトにD&D
あとはPlaneのインスペクターのPlay On Awake にチェック入れるだけで動画が再生されます。

スクリプトから動画を再生したり停止したりいろいろやりたい

まず
using UnityEngine.Video; これを冒頭で宣言

次に
private VideoPlayer videoPlayer;   

再生したいタイミングで
videoPlayer = GameObject.Find(“hogePlane”).GetComponent<VideoPlayer>();
videoPlayer.Play();

動画停止は
videoPlayer.Stop();

ポーズは
videoPlayer.Pause();


再生が終わったらいろいろやる方法

再生が終わったら次の動画、とかやるのに使える方法はコレ。
テストとして再生が終わったら動画パネルオブジェクトを見えなくしてみる。

基本的には動画が再生中かどうかを判定するには
videoPlayer.isPlaying を使うみたい。
これがtrue なら再生中、 false なら再生されていない らしい。

で、ifで videoPlayer.isPlaying == false だけで判定しようとすると動画が再生されるまで少しタイムラグがあるみたいで動画が再生される前に falseと判定されてif文が実行されてしまった。

そこでdeltaで数を数えて動画が再生されている頃からif判定を始めるようにすると思い通りの結果になった。

GameObject ActPanel;    //Planeの大きさを変えるのに使う
float delta = 0;	//数を数えるのに使う

void Update()
    {
        delta += Time.deltaTime;    //数を数える
        if ((videoPlayer.isPlaying == false)&amp;(delta>2))
        {
            ActPanel = GameObject.Find("hogePlane");        //動画Planeオブジェクトを見つける
            ActPanel.transform.localScale = Vector3.zero;   //見えなくする
        }
    
    }

↑なんか & が 勝手に & amp; に変えられているみたいです。
正しい表示はコレ
if ((videoPlayer.isPlaying == false)&(this.delta>2))


動画を再生すると WindowsVideoMedia error という警告が出る問題について

なんかmp4ファイルを再生しようとするとこんな警告が出て怒られる。
aviファイルなら大丈夫やったのでもうaviでええわ

.


なんか動画を再生すると映像にグレーのレイヤーがかかっているみたいに暗く表示される問題について

なんか動画が暗い?
Mesh RendererのElement0 をdefault material から
Sprites-Default に変えたら正常に表示された
これでOK ^^v

Unityで64bitの設定をしても「このリリースは google play の 64 ビット要件に準拠していません」エラー



↑このように設定してビルドすると64ビット対応のAPKができて今まで普通にアップデートできていたわけですよ。

それが先日から突然「お前のアプリ64ビットでも動くけど32ビットのネイティブコードしかないわ。エラーな。」などと言い出したのです。

aaptでapkを調べたら

ちゃんとarm64-v8a があるのでこれは64bitに対応してると思う。

unityのフォーラム見てみたら同じような症状の人がいてアンサーでx86のチェック外せっていうのがあったので外したらうまくいった!

これでエラーともおさらば ^^v

Unityでファイルを削除する時の注意点



exsistFileName="hoge.png";

            var captureDirectory = Application.dataPath;
            var captureFileName = exsistFileName;
            var capturePath = Path.Combine(captureDirectory, captureFileName);
            if (File.Exists(capturePath)) File.Delete(capturePath);

こんな風に書くとファイルを削除することができますが

A meta data file (.meta) exists but its asset ‘Assets/hoge.png’ can’t be found. When moving or deleting files outside of Unity, please ensure that the corresponding .meta file is moved or deleted along with it.

こんな警告をされることがあります。

画像は削除したけどメタデータは残ってるよ。
メタデータも一緒に削除しないと恐ろしいことになりますよ、という脅しらしい。

なので上の命令の後に

exsistFileName="hoge.png.meta";

      captureDirectory = Application.dataPath;
            captureFileName = exsistMetaName;
            capturePath = Path.Combine(captureDirectory, captureFileName);
            if (File.Exists(capturePath)) File.Delete(capturePath);

こんな風にセットで削除すれば怒られない。

ふふふ。やったぜ。


unityでボタンのプレハブ作ったらOn Clickが使えなくなる問題


——–

なんか2018年のいつからかプレハブの仕様が変わった? ボタンのプレハブのOnClickに関数を設定できなくなりました。なんでや?

Kantokuいうオブジェクトがボタン押したときに実行する関数を持ってる。
ButtonAのOnClickにD&Dして関数を設定
ヒエラルキーからプロジェクトビューにD&Dしてプレハブ化。
するとなぜかさっき指定したはずのKantokuが消える。
Noneの横の丸ボタン押してKantokuを探してもいない。
もう一度ヒエラルキーからKantokuをD&DしようとしたらD&Dができない!はじかれる! なんでや!

以下、これが正しい解決方法かどうかわからないですが方法を書いておきます。

2019/7/19追記 :この方法はダメです!エラーが出ます

スクリプトをアタッチしてるオブジェクト(ここではKantoku)をDuplicateで複製します。監督の影武者です。
名前を KantokuKage にしました。
それをプロジェクトビューにD&Dしてプレハブ化してみる。
ボタンプレハブのOnClickのNoneの横にある丸ボタンを押すと、Kantokuはいないが影武者のKantokuKageはいる!
これを選択してNo Functionから関数を選択すればいけました。

俺のunityはおかしくなってしまったのか・・・? 前はこんなんせんでよかったのに・・・ なんでや!

——- 2019/7/19 追記 : エラーの出ないやり方————

なんかやり方 わかったかも。

プロジェクトビューでボタンのプレファブに直接スクリプトをD&D。
するとインスペクタにアタッチしたスクリプトが表示されるので
それをNoneにD&D。これで関数にアクセスできます。

う~ん? これが正しい方法で今までの私のやり方が間違っていたのか? もうほんまよう分からん。

————————————-

unityでたくさんのパラメータを1つのセーブデータで保存する

HPやアイテム所持フラグなどたくさんのパラメータを保存する時。今までは

PlayerPrefs.SetInt("SVhp", hp);     //HPをセーブ
PlayerPrefs.SetInt("SVmp", mp);     //MPをセーブ

こんな風にひとつひとつセーブしていたのですが多くの項目をPlayerPrefsで保存するのはあまり良くないらしいので、1つのセーブデータで保存できないかといろいろ考えました。

まず各パラメータを区切り文字カンマ「,」で区切って一つの文字列に結合してセーブ。

public void SaveR()
    {

	strget = null;      //文字列初期化。こいつに文字列型に変換したデータを全部足してぶち込む

        for (int i = 0; i < 10; ++i)                        //アイテムデータを文字列で結合
        {
            strget = strget + Item[i].ToString()+",";       //数値型を文字列型に変換して区切り記号のカンマ付けて足していく
        }

        for (int i = 0; i < 20; ++i)                        //宝箱データを文字列で結合
        {
            strget = strget + Tres[i].ToString() + ",";
        }

        strget = strget + Aria.ToString() + ",";    //エリア情報
        strget = strget + KenLV.ToString() + ",";   //剣のレベル
        strget = strget + Money.ToString() + ",";   //お金

        posMX = transform.position.x;     //プレイヤー位置情報
        posMY = transform.position.y;
        posMZ = transform.position.z;

        strget = strget + posMX.ToString("F2") + ",";       //ポジション情報はフロート型なので小数第2まで保存。
        strget = strget + posMY.ToString("F2") + ",";
        strget = strget + posMZ.ToString("F2") + ",";

        strget = strget + mp.ToString() + ",";    //MP
        strget = strget + hp.ToString() + ",";    //HP
        strget = strget + maxhp.ToString();       //最大HP


	PlayerPrefs.SetString("svItmTre", strget); 		//文字列型でセーブ
    }

↑ こんな感じでカンマで区切ってひとつの文字列にする。
エリアは3で所持コインは101610でその後ろが位置情報です。
これをロードしてみます。

ロードするときは読み込んだセーブデータを区切り記号のカンマで配列変数に分解し、数値型に変換して各データにぶち込む。文字列を指定した区切り文字で分解してくれるSplit命令がすごい便利で感動しました。

public void LoadR()
    {

	LoadMan = PlayerPrefs.GetString("svItmTre", null); 	//ロード


        //string[] strArray = strget.Split(',');        //この命令 めちゃ便利ね~
        string[] strArray = LoadMan.Split(',');         //読み込んだセーブデータを区切り記号のカンマで配列変数に分解。

        for (int i = 0; i < 10; ++i)
        {
            Item[i] = int.Parse(strArray[i]);           //あとはそれぞれの配列変数を数値型に変換して各データにぶち込めば完了
        }

        int a = 0;
        for (int i = 10; i < 30; ++i)
        {
            Tres[a] = int.Parse(strArray[i]);
            a++;
        }

        Aria = int.Parse(strArray[30]);
        KenLV = int.Parse(strArray[31]);
        Money = int.Parse(strArray[32]);
        posMX = float.Parse(strArray[33]);
        posMY = float.Parse(strArray[34]);
        posMZ = float.Parse(strArray[35]);
        mp = int.Parse(strArray[36]);
        hp = float.Parse(strArray[37]);
        maxhp = float.Parse(strArray[38]);


        this.transform.position = new Vector3(posMX, posMY, posMZ-7);             //セーブした位置に移動

    }
スタート地点のエリア0でLoad dataでロードすると
エリア3に移動しました。
所持コインも101610でちゃんとセーブとロードができました!

アクションゲーム Blatt Adventure

Unityで作ったゲームをApp Storeで公開しています。

無料なのでぜひ遊んでみてください。

ダウンロードはこちら ↓

————————————————————————————————

プロモーション動画 ↓

ダウンロードはこちら ↓

Unityで3D酔いしないように工夫する

    

   

こういう風に壁沿いを歩いているとき
キャラが壁で隠れると壁が近すぎて酔いそうになる。
これはカメラが壁に近すぎるのが原因だと思う。
そこで壁を厚くしてカメラを壁の中にめり込ませる。

カメラには壁の中に張ったテクスチャを映させる。

プレイヤーが壁の中に入れないように外側に膜を作る。

という作戦を考えたですよ。
これがダンジョンの壁なのです。

ブレンダーで作ってます。
見やすいようにソリッドで表示。

左が正面から見た壁。

右が壁の裏がわ。

青い線が法線の向きです。
裏の面を選択して法線を方向転換させます。

めり込んだカメラに映してもらうためです。
裏の面を選択してEキーでその場に押し出してから内側に移動させます。
四隅を選択して面を作成。

これがプレイヤー侵入防止の膜になります。
これでイメージ通りの壁ができました。

Xの距離は実際にプレイして調整します。
壁沿いを歩くと
うんうん。

まあ最初よりはだいぶ良くなったような気がしないでもないな。

3D酔い対策はなかなか難しいですな・・・

——————— 4 / 7 追記 ——————————

もっといい方法を思いついたのであった。

左の壁が今までの壁。

今回は下のほうにナイフで切り込みを入れて
画像で選択してる面だけを内側に押し出します。
その押し出した面の法線は壁の内側に向けておきます。

これをカメラに映してもらいます。

他の面は外側に向けて法線を出しておきます。
最後にプレイヤーが壁に入れないように膜の面を作成。

この面は外側に向けて法線を出す。

さあ壁沿いを歩いてみよう!
プレイヤーと壁が重なると
内側に法線を向けた面だけが描写されます。

うんうん。これは酔わない。

酔いやすい私の脳がそう言っているので間違いない。

やった! ^0^

    

Unityの動作がWindowsとMacで違う問題について

Translateの速度が違う?

—————————————————— ——————————————————

Windowsのunityで開発してMacのxcodeでビルド→iPhone転送→動作確認

という手順でやっていたのですが、どうもwindowsでの動作とmacやiPhoneでの動作に違いがあるように思えるのですよ。

この青いゲートをくぐるとスピードが上がります。
もしゲートをくぐらずに遅いスピードのまま進むと扉が閉まって先に進めない、というステージ。

windowsでは上の画像のようになるのですが、MacやiPhoneでプレイすると青いゲートをくぐらなくても先に進めてしまうのです。

なんか扉が落ちてくるスピードがwindowsよりも遅いので先に進めてしまう。

前に「Unityで自分に向かってくる敵の弾を作る」という記事でプレイヤーを狙い撃つ弾道を作ったのですが、

windowsではこのようにちゃんと命中します。
ところがMac&iPhoneでは弾が遅く、どこ狙ってんの状態。

使ってるwindowsパソコンのほうが性能が高いのでスペックの違いで速度が違うのかな?とも思いましたが、MacとiPhoneは同じような動きなのですよ。

この扉や狙い撃つ弾はTranslateで動かしていました。

↓こんな風に
this.transform.Translate(0, -0.3f, 0);

そこでこの扉をTranslateではなく、rigidbodyで重力落下させてみました。

:ゲームプレイ中断画面:

するとこんどは両方とも手前でちゃんと扉が落下しました。扉が落ちる速度に違いは出ませんでした。

となると怪しいのはTranslateですよ。

windowsとmac&iPhoneではTranslateの速度が違うのでは?

検索しても同じような症状の人がいないのでまだよくわからないのが現状です・・・

      ---

Unityで自分に向かってくる敵の弾を作る

自分を狙って飛んでくる敵の弾を作りたいのです。

ある地点に向かってオブジェクトを動かすにはMoveTowardsを使うと出来るそうなので、プレイヤーの位置情報を取得してそこに動かせばいいのだろうと

this.transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(playerpos.x, playerpos.y, playerpos.z), 0.5f);

このように書いてみたところ

自分のほうに飛んでは来たものの、ずっと張り付いて離れなくなってしまった。ずっとプレイヤーの座標を参照してるからずっとその座標を目指してしまう。

位置を参照するのは1回で良さそう。

プレイヤーのボールをP1、敵弾を赤丸とすると

プレイヤーは前に進むわけだからP1の座標を目指して敵弾を飛ばしても命中しないし狙ってる感じがしない。

プレイヤーの移動先のP2の地点の座標をゲットしてそこに飛ばそう。

public class EnemyMove : MonoBehaviour {

   Vector3 tmpE;                        //myballの位置情報をここに入れる 
    public Transform hogeEne;
    GameObject BPninja;     //
    int Ecnt = 0;       //フラグ立てに使う
    float calcZ = 0;    //敵とプレイヤーの距離を測るのに使う

    void Start () {

        this.BPninja= GameObject.Find("MyBall");            //playerposにボール位置情報を格納
        Vector3 playerpos =this.BPninja.transform.position; //
    }

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

         Vector3 playerpos = this.BPninja.transform.position;    //ball位置情報取得する
            this.calcZ = this.transform.position.z - playerpos.z;   //敵のZ座標からボールのZ座標を引く。これで距離が出る

            if (this.calcZ < 50)    //プレイヤーが弾に近づいて来たら

            {
                if (this.Ecnt == 0)     //ここで一回だけ現在のプレイヤー位置情報を調べる
                {
                    hogeEne = GameObject.Find("MyBall").GetComponent<Transform>();  //ボールを見つける
                    tmpE = hogeEne.transform.position;                              //ボールの位置情報をvector3でtmpに格納
                    this.Ecnt = 2;      //Ecntを2にして再度位置情報をゲットしないようにする
                }

                if (this.Ecnt == 2)     //Ecnt=2ならゲットした位置情報の座標にMoveTowardsで弾を飛ばす
                {
                    this.transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(tmpE.x, tmpE.y, tmpE.z + 10), 0.6f);
                }
            }
        }

上のコードではプレイヤーのボールが敵弾に近づくと弾が発射されるようにしています。狙う位置はプレイヤーの移動先なのでtmpE.z + 10 としてプレイヤーより奥の座標を指定しています。

このコードを敵弾のオブジェクトにD&Dでアタッチして実行してみると

うむ!

プレイヤーが近づくと移動先に向かって敵弾が発射されました!

四角い岩も飛んできたぜ! やった^^v

buttonのPrefabを表示するのに苦労した話

//////////////////////////////////////// ー広告ー ////////////////////////////////////////

こんな感じでSTARTボタンを押したらゲームがスタートするようにしたかったんです。そのボタンをPrefabで作ろうとしたらいろいろエラーが出て苦しみました・・・

まずボタンが表示されませんでした。

なんでかというとボタンとかテキストはCanvasの子オブジェクトにしてやらないと表示されないようです。ボタンのPrefabのBTstartはCanvasの外にできちゃってます。これはアカン。

いろいろ調べてCanvasの子オブジェクトとしてPrefabを作る方法を発見。

public class test : MonoBehaviour { 

public GameObject canvas;//キャンバス
public GameObject PutStart; //スタートボタンのプレファブを入れる箱 

void Start () { 

GameObject prefab = (GameObject)Instantiate (PutStart); 

prefab.transform.SetParent (canvas.transform, false); 
} 

void Update () { 
} 

}

これでいけるはずなんですが・・・

こんなエラーを吐かれてしまう。

UnassignedReferenceException: The variable canvas of MainJ has not been assigned.
You probably need to assign the canvas variable of the MainJ script in the inspector.

はぁ~ん? 何を言っとるのかわからんのう~

public class test : MonoBehaviour { 
public GameObject PutStart; //スタートボタンのプレファブを入れる箱 
public RectTransform canvas;//キャンバス 

void Start () { 
Instantiate(PutStart, new Vector3(4, 12, -299), 
Quaternion.identity).name = "PreStrat"; canvas=GameObject.Find("Canvas").GetComponent<RectTransform>(); 
PutStart.transform.SetParent(canvas.transform, false); } 

void Update () { } 

}

Canvasが見つからないのかと思ってFindで見つけようとか訳のわからんことをしてみる。

すると今度はこんなエラーを吐きだしたのでった。

Setting the parent of a transform which resides in a prefab is disabled to prevent data corruption.

どうもこれはPrefab自身を親オブジェクトに設定しようとすると出るエラーらしい。

なんかよくわからんけど私のPrefabの作り方がおかしかったぽい。

public class test : MonoBehaviour { 

public GameObject canvas; //キャンバス 
public GameObject PutStart; //スタートボタンのプレファブを入れる箱 

GameObject ObjK; //ちゃんとInstantiateするための箱 

void Start () { 
ObjK = Instantiate(PutStart, new Vector3(3.9f, 18.6f, -298.6f), Quaternion.identity); 

canvas = GameObject.Find("Canvas"); 

ObjK.transform.SetParent(canvas.transform, false); } 

void Update () { 
} 

}

このように書くと

ちゃんとCanvas内にクローンが作れて

やっとボタンを表示することができました^0^

すごい基本的なことなのかな~?

やっぱ独学はアカンね・・・^^;

↓こういうところで本格的に勉強したいですな!