Blenderで次元を作ってアニメーションさせる



↑作成動画
ガンマンには夕日がよく似合うぜ!
正面からと真横から見た下絵を描きます。
顔のパーツとか腕、腰の位置などは正面と横で揃えて描きます。
プロパティパネルの下絵にチェック入れて下絵を読み込む。
正面の画像は座標軸メニューから前を選択、横の画像は右を選択。
不透明度を調整して前を選択。
下絵に沿ってペタペタ面を張っていきます。
頂点や辺を押し出すにはEキー。
新しく頂点をつくるにはctrl+左クリックだよ

こんな感じになりました。
次はこれにボーンという骨格を入れて動かせるようにしよう
追加→アーマチュア→単一ボーンでボーン作成。
編集モードで先端を選択してEキーで押出し。
人体のモデルに沿って骨格を作っていきます。
こんな感じになったよ。
次はボーンとボディオブジェクトを関連付けします。
bodyオブジェクトを全部選択した後、shiftキー押しながら
ボーンオブジェクトを選択。
オブジェクト→親→自動のウエイトで→自動のウエイトで
これでボーンを選択→ポーズモードから
ボーンを動かすと体も動きます。
これで思い通りに動くのかといえばそんなことは稀で
大抵はこんな風にオブジェクトが破綻したりします^^;
ウエイトペイントモードにしてボーンの影響範囲を設定します。
Drawでボーンがオブジェクトに与える影響度を設定します。
塗れば塗るほど赤くなって影響度が強くなります。
影響度を強め過ぎたらSubtractで弱めます。
あとはポーズモードでボーンを動かしてポーズを作って
iキーでキーフレーム打って
またちょっとフレーム動かしてポーズ作って
iキーでキーフレーム打って
パラパラ漫画の要領でアニメを作ります。
はーい 完成でーす ^0^


Rigidbodyのfreezeにチェックを入れたり外したりする



突進してくるボスと戦闘中に壁に挟まれるとプレイヤーが上に持ち上げられて壁を越えてしまうというバグが出てしまった。

そこでボス戦に突入したらRigidbodyのFreeze PositionのYにチェックを入れて上に上がらないようにしてボス戦が終わったらこのチェックを外して再び上下に移動できるようにしたい。

public Rigidbody rigidy;        //rigidbody

.
.
.

//Freezeしたいタイミングで

this.rigidy = this.GetComponent<Rigidbody>();
this.rigidy.constraints = RigidbodyConstraints.FreezePositionY;      //これでYだけフリーズされる

//どうもfreeze使うとRotationまでチェック外れるぽいのでチェック入れる
this.rigidy.freezeRotation = true;	

これでボス戦だけはY軸方向に移動不可能

ボス戦が終わったらFreezeのチェックを外してまた段差を移動できるようにするんやけど、特定の項目だけチェック外すいうのができんらしい。

this.rigidy.constraints = RigidbodyConstraints.None; 

まずこれで全部のチェックを外す。するとRotationも外れてしまうので
Rotationに再びチェックを入れる

this.rigidy.freezeRotation = true;
これでOK ^^v

↑このゲームはこちらで公開中↓

Google Play で手に入れよう

Transformで敵を動かすと壁をすり抜ける



if (this.a == 1) { this.transform.Translate(Espd, 0, Espd); }
if (this.a == 2) { this.transform.Translate(-Espd, 0, -Espd); }
if (this.a == 3) { this.transform.Translate(-Espd, 0, Espd); }
if (this.a == 4) { this.transform.Translate(Espd, 0, -Espd); }

↑こんな風にtransformで敵を動かしたら壁をすり抜ける現象がたまに起こってしまった。上下左右に移動させる敵はすり抜けないけど斜めに移動させたらすり抜けた。

敵の移動にtransformは使わないほうがいいよとは聞いていたけどやっぱりいろいろ挙動がおかしくなるのね^^;

そこでRigidbodyを付けてaddforceで動かすことにする。

int a = 1;		//移動方向を決めるのに使う
float delta = 0;	//数を数えるのに使う
float span = 3.0f;	//方向転換させるタイマー
float maxSpd = 5;       //最高速度
float nowSpd = 0;       //今のスピード。最高速度以下なら加速させる
float powX = 25;        //X方向に加えるスピード
float powZ = 25;        //Z方向に加えるスピード


void FixedUpdate() {

        this.delta += Time.deltaTime;    //数を数える


        if (this.delta > this.span)   //スパンまで加算したら
        {
            this.delta = 0;
            this.a = Random.Range(1, 5);     //ランダムに方向転換
        }

        //歩く速度を計測する
        this.nowSpd= Mathf.Abs(this.GetComponent<Rigidbody>().velocity.x)+ Mathf.Abs(this.GetComponent<Rigidbody>().velocity.z); 	//歩く速度を計測。

        //壁にハマって動かなくなるのを防止。移動速度が極端に低いということは壁にハマっとる。方向転換させる。
        if(this.nowSpd < 1) { this.a = Random.Range(1, 5); }


        if (this.a == 1)    //左下
        {
            if (this.nowSpd < maxSpd)
            {
                this.GetComponent<Rigidbody>().AddForce(transform.right * 1 * powX);
                this.GetComponent<Rigidbody>().AddForce(transform.forward * 1 * powZ);
            }
        }

        if (this.a == 2)    //右上
        {
            if (this.nowSpd < maxSpd)
            {
                this.GetComponent<Rigidbody>().AddForce(transform.right * -1 * powX);
                this.GetComponent<Rigidbody>().AddForce(transform.forward * -1 * powZ);
            }
        }

        if (this.a == 3)    //左上
        {
            if (this.nowSpd < maxSpd)
            {
                this.GetComponent<Rigidbody>().AddForce(transform.right * 1 * powX);
                this.GetComponent<Rigidbody>().AddForce(transform.forward * -1 * powZ);
            }
        }

        if (this.a == 4)    //右下
        {
            if (this.nowSpd < maxSpd)
            {
                this.GetComponent<Rigidbody>().AddForce(transform.right * -1 * powX);
                this.GetComponent<Rigidbody>().AddForce(transform.forward * 1 * powZ);

            }
        }
    }


これですり抜けなくなった^^v

↑このゲームはこちらで公開中↓

Google Play で手に入れよう
ー広告ー

ITMS-90809問題でUnityをアップデートしたらAdMobが表示されなくてハマる



長くなるので最初に問題の概要と解決を書きます。

問題1.アプリをAppStoreにアップロードしたらAppleからITMS-90809:WebViewやめろメールが来た。

解決法:
https://issuetracker.unity3d.com/issues/ios-apple-throws-deprecated-api-usage-warning-for-using-uiwebview-when-submitting-builds-to-the-app-store-connect
↑ここにこの問題を修正したバージョンが載ってるのでそのバージョンにUnityをアップデートする。
私の場合2018.4.16f1 を使うといけた

問題2.Unityをアップデートしてビルドしたらテスト広告は表示されるのに本番IDの広告がiPhoneで表示されない。と思ったらiPadでは表示される。なにコレ?

解決策:スマートバナーを使ったら表示された

BannerView bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Top);

問題3.Xcodeでビルドしたら
GADUNativeExpressAd.m cannot be found

解決策:
Assets/Plugins/iOS/GADUNativeExpressAd.h
Assets/Plugins/iOS/GADUNativeExpressAd.m
Xcodeでこいつらを削除。

問題4.↑上の問題を解決してビルドしたら今度は
library not found for lgoogleutilities

解決策:Unityでビルドして出来たファイルで
hogeApp.xcodeproj じゃなくて
hogeApp.xcworkspace の方を開く

問題5.↑上の問題を解決してビルドしたら今度は
80 duplicate symbols for archtecture arm6

解決策:
a.最新Google Mobile Ads Unity Pluginをダウンロード
b.AssetのGoogleMobileAdsとPlayServicesResolverとPluginsフォルダをUnityから削除。
c.最新のやつをインポートしてビルド
d.ビルドするときreplaceかappendか聞かれるとreplaceで一旦置き換える。この時最初はDestinationがなんたらでエラー出るけど2回目は出なかった
e.出来たhogeApp.xcworkspaceを開いてxcode起動。その時duplicate symbolsのエラーが出てるけどビルドしたら消える。
f.最新Google Mobile Ads SDKをダウンロードしてxcodeのフレームワークに追加。最新のAdsSDKには4つフレームワークあるけど入れるのはGoogleMobileAds.Frameworkだけで他の訳分からんの入れたらビルド時にduplicate symbolsのエラー。

問題6.xcworkspaceからプロジェクト開くと証明書関連がなんかおかしくなる

解決策:
debug—Apple Development
Any iOS SDK—iOSDeveloper
Release—Apple Distribution
Any iOS SDK—iOSDeveloper
ReleaseForProfiling—Apple Distribution
Any iOS SDK—iOSDeveloper
ReleaseForRunning—Apple Distribution
Any iOS SDK—iOSDeveloper
この設定にしたらいけた

問題7.ArchiveのあとValidateしようとしたら
appstore connect operation error
一旦戻ってもう一回やろうとしたら
no app store connect account

解決策:Macを再起動


今回のITMS-90809の問題はたくさんエラーが出て迷走したけどやることは問題1と2だけで良かった。つまりUnityアップデートしてAdMobはスマートバナーを使う。これだけで良かったぽい。
なんで迷走したのかといえばアップデートしてビルドしてもiPhoneで本番広告が表示されなかったからで、ああ最新のバージョンは最新のAdsSDKやら全部最新の入れないとダメなのねと思ってしまいPluginとか全部再インポートしたらxcodeが激おこエラーの嵐。
最終的には無事アップロードできたので良かったけどもうほんま疲れた~^^;


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

クロスシミュレーションを動画出力するとバグる問題について



クロスシミュレーションをBlender上で再生すると正常に動いてるのに
アニメーションをAVIで出力するとクロスシミュレーションが
バグる問題に遭遇したけどなんとかなったので方法を書いておきます。


1.まず一回再生する。

2.物理演算タブのクロスのキャッシュでベイクをクリック

3.レンダーからOpenGLアニメーションレンダリングをクリックすると

バグらないで出力できましたー ^0^


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でちゃんとセーブとロードができました!