まゆたまガジェット開発逆引き辞典

電子工作やプログラミングのHowtoを逆引き形式で掲載しています。作りたいモノを決めて学んでいくスタイル。プログラマではないので、コードの汚さはお許しを。参照していないものに関しては、コピペ改変まったく問いません

MESHの動きタグでUnityちゃんを走らせる(アセットなし)

ソニーMESHの動きタグをめっちゃ振ると、Unityちゃんが走ります。
疲れるので、人によってはスクリプトの微調整が必要かもです。
とりあえずできたのでポストです。

GPIOを使い、M5Stack(Arduino)経由でUnityにデータを送ります。
f:id:prince9:20180927053705p:plain

基本的には下記と同じです。
prince9.hatenablog.com



Arduinoでシリアルモニタを立ち上げた状態でUnityを動かすと、シリアルが認識しません。注意!

■準備
ソニーMESHの「動きタグ」
ソニーMESHの「GPIO」
・M5Stack(Arduino)
・ワイヤー

●MESH
これを下記のように接続します。
f:id:prince9:20180925205928p:plain

●Unity側(アセットなし)
1.Unityのプロジェクトを作り、「GameOBject」メニュー→「3DObject」→「Cube」などを選び、適当にオブジェクトを作る
2.「File」メニュー→「Build Settings」を選択し、「Player Settings」をクリックする
3.Inspectorの「Other Settings」→「Api Compatibility Level」を「.NET 2.0」にする
4.「Build Settings」を閉じる

5.アセットストアからUnityちゃんのデータをダウンロードする
6.アセットストアの「ダウンロードボタン」を押した後に「インポートボタン」を押す
7.「Import」をクリックし、「Heirarchy」にUnityちゃんをドラッグ&ドロップする
(「UnityChan」→「Models」→「unitychan」)

8.「Assets」を右クリックし、「Create」→「C# Script」を選択する
9.「MESHReceive」など適当にファイル名をつけて、後からスクリプトを書く
10.スクリプトを書いたら保存し、「Hierarchy」にあるUnityちゃんにドラッグ&ドロップして適用する

11.「Create」→「Animator Controller」を選択し「UnitychanMoveController」などに変更
12.「Assets」の中にある「UnitychanMoveController」をダブルクリックし、画面左上の「Animator」タブが選択されていることを確認
f:id:prince9:20180927050844p:plain
13.灰色の何もないところで右クリックし、「Create State」→「Empty」を選択
14.「New State」をクリックし、名前を「Idle」にする
15.もう一度灰色の何もないところで右クリックし、「Create State」→「Empty」を選択
16.名前を「Run」にする
17.「Idle」をクリックし、「Inspector」の「Motion」の横の◯アイコンをクリック
f:id:prince9:20180927050948p:plain
15.「WAIT00」をクリックして、モーションを設定する
16.「Run」をクリックし、「Inspector」の「Motion」の横の◯アイコンをクリック
17.「RUN00_F」をクリックして、モーションを設定する
18.「Idle」を右クリックし、「Make Transition」を選択する
19.白い矢印がのびるので、「Run」をクリックする。これはアニメーションが待機状態(Idle)から走る(run)に移行する設定を示している
f:id:prince9:20180927051833p:plain
20.白い矢印をクリックし、「Inspector」→「Has Exit Time」のチェックを外す。このチェックはアニメーションが終了するまで次のアニメーションが開始されないという設定で、もっさりとした動きになることがある
21.下記の「+」ボタンをクリックし、「Bool」を選ぶ
f:id:prince9:20180927051915p:plain
22.「New Bool」を「Running」と名前を変える
23.「Conditions」の「+」ボタンをクリックし、「Running」を「true」にする
f:id:prince9:20180927052034p:plain
24.「Run」を右クリックし、「Make Transition」を選択する
25.白い矢印がのびるので、「Idle」をクリックして下記のようにする
f:id:prince9:20180927052136p:plain
26.できた矢印をクリックし、「Inspector」→「Has Exit Time」のチェックを外す
27.「Conditions」の「+」ボタンをクリックし、「true」となっているところをクリックして「false」にする
f:id:prince9:20180927052212p:plain
28.「Hierarchy」のunitychanを選択し、「inspector」→「Animator」 →「Controller」の「None」と書かれているところに、「Assets」の中にある「UnitychanMoveController」をドラッグ&ドロップする
29.「Inspector」→「Animator」の「Apply Root Motion」のチェックを外す。プログラミングによってキャラクターを動かすときはこのチェックを外す


■コード
まずMESHは以下になります。
動きタグで振動を認識したら、デジタル出力をHight(ON)にします。その1秒後にデジタル出力をLow(OFF)にすることで、Hight(ON)の状態をリセットしています。
リセットしないと、振った後にHightのままになってしまいます。
動くタグの動作確認のために音も鳴らしています。
f:id:prince9:20180927030917p:plain

Arduino(M5Stack)コード
動きタグが振られたときが1、振られていないときは0をUnityに送っています。
シリアルモニタ代わりにM5Stackを使用しています。

#include <M5Stack.h>

#define MESH_pin 36  // GPIOをGPIO36につなぐ

int mdata = 0; //MESHのデータ用変数
 int sdata = 0; //0or1に変換する変数

void setup(){
    M5.begin();


Serial.begin(9600);
    pinMode(MESH_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);

    mdata = analogRead(MESH_pin); //動きタグデータ読み込み
    sdata = mdata / 3000; //データが振られていないときは0、振ったときは3700〜3800前後で出てくるので、0か1かに変換
    
    Serial.println(sdata); // シリアルに出力
    
//Unityにデータを送るとシリアルモニタが使えないので、M5Stackをシリアルモニタ代わりに
 M5.Lcd.setTextColor(WHITE);
      M5.Lcd.setTextSize(5);
    M5.Lcd.print(sdata);
    
    delay(100); //0.1秒ごとにデータを出力。疲れないためにこの値を要調整
      M5.update();
}

「めっちゃ振ったらそのぶんだけ動く」=「めっちゃ振ったら大きく動く」ことで、Unityちゃんを走らせています。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;

public class UnitychanMoveScript : MonoBehaviour {

//Animator Contollerを処理するときのおまじない
private Animator animator;


	//new SerialPort("")にArduinoアプリで調べてメモしたシリアルポート名を指定する
SerialPort sp = new SerialPort("/dev/cu.SLAB_USBtoUART", 9600);

	// Use this for initialization
	void Start () {

//Animator Contollerを処理するときのおまじない
		animator = GetComponent<Animator>();

//シリアルポートが開いているか否か
		if (!sp.IsOpen) {
			sp.Open();
			sp.ReadTimeout = 1000;
		} else {
			sp.Close();

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

		//文字列を数値に変換、meshMoveがArduinoアプリから送られてきた値
		int meshMove = int.Parse(sp.ReadLine());
		Debug.Log(meshMove);


//動きタグを振ったとき(meshMoveが1のとき)
		if(meshMove > 0) {
			
//Unityちゃんが走る
		 transform.position += transform.forward * 0.1f;
            animator.SetBool("Running", true);
		}
		else {

//振っていないときは止まる
            animator.SetBool("Running", false);
        }

//キーボードの左右キーで向きを変える
		if (Input.GetKey("right")) {
            transform.Rotate(0, 10, 0);
        }
        if (Input.GetKey ("left")) {
            transform.Rotate(0, -10, 0);
        }
		
		
	}
}

M5StackをArduinoのように使ってUnityに送る(MESHの動きタグ・アセットなし)

アナログ出力はちょっと工夫が必要っぽいので、まずはデジタル出力から。
Arduino使えば早いというツッコミはナシの方向で・・・(汗

ソニーMESHの動きタグを振ると、Unityのオブジェクトが移動します。
追記でたくさん振ると大きく動くようにすることで、アナログ出力っぽい挙動を出してみました。

テストなので簡単なものを。
上手くやれば、動きタグを振ってる間、キャラクターが走るということも可能です。
(キーボードで移動させるスクリプトに手を加えるだけ)

f:id:prince9:20180927032837j:plain

M5Stack(Arduino)とUnityとの接続は前回と同じです。アセットは使いません。
prince9.hatenablog.com

Arduinoでシリアルモニタを立ち上げた状態でUnityを動かすと、シリアルが認識しません。注意!

■準備
ソニーMESHの「動きタグ」
ソニーMESHの「GPIO」
・M5Stack(Arduino)
・ワイヤー

●MESH
これを下記のように接続します。
f:id:prince9:20180925205928p:plain

●Unity側(アセットなし)
1.Unityのプロジェクトを作り、「GameOBject」メニュー→「3DObject」→「Cube」などを選び、適当にオブジェクトを作る
2.「File」メニュー→「Build Settings」を選択し、「Player Settings」をクリックする
3.Inspectorの「Other Settings」→「Api Compatibility Level」を「.NET 2.0」にする
4.「Build Settings」を閉じる
5.「Assets」を右クリックし、「Create」→「C# Script」を選択する
6.「MESHReceive」など適当にファイル名をつけて、後からスクリプトを書く
7.スクリプトを書いたら保存し、「Hierarchy」にある1.で作ったオブジェクト名にドラッグ&ドロップして適用する

■コード
まずMESHは以下になります。
動きタグで振動を認識したら、デジタル出力をHight(ON)にします。その1秒後にデジタル出力をLow(OFF)にすることで、Hight(ON)の状態をリセットしています。
リセットしないと、振った後にHightのままになってしまいます。
動くタグの動作確認のために音も鳴らしています。
f:id:prince9:20180927030917p:plain

Arduino(M5Stack)コード
これも前のこちらのコードを改良したものです。
prince9.hatenablog.com
動きタグが振られたときが1、振られていないときは0をUnityに送っています。

M5Stackを使う利点として、簡単にシリアルモニタ代わりにできるという点があります。
UnityやProcessingなど、他の開発環境にデータを送る場合、Arduinoアプリのシリアルモニタが動いているとエラーが出るので・・・

#include <M5Stack.h>

#define MESH_pin 36  // GPIOをGPIO36につなぐ

int mdata = 0; //MESHのデータ用変数
 int sdata = 0; //0or1に変換する変数

void setup(){
    M5.begin();


Serial.begin(9600);
    pinMode(MESH_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);

    mdata = analogRead(MESH_pin); //動きタグデータ読み込み
    sdata = mdata / 3000; //データが振られていないときは0、振ったときは3700〜3800前後で出てくるので、0か1かに変換
    
    Serial.println(sdata); // シリアルに出力
    
//Unityにデータを送るとシリアルモニタが使えないので、M5Stackをシリアルモニタ代わりに
 M5.Lcd.setTextColor(WHITE);
      M5.Lcd.setTextSize(5);
    M5.Lcd.print(sdata);
    
    delay(500);
      M5.update();
}


●Unity
動きタグが繊細なせいか、一度振っても、下記のように複数値が返ってくることがあります。

0 ←振ってない
1 ←実際に振った
1 ←自分的には誤認識
1 ←自分的には誤認識
0 ←振ってない

なので、実際に振ったときのみ処理を行うよう、1の値を出した回数をカウントする変数「count」を作っています。
まずは単純に「振ったら動く」です。振るごとに動きます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;

public class meshUnityScript : MonoBehaviour {

	 private int mMove = 0;
	 private int count = 0;

	//new SerialPort("")にArduinoアプリで調べてメモしたシリアルポート名を指定する
SerialPort sp = new SerialPort("/dev/cu.SLAB_USBtoUART", 9600);

	// Use this for initialization
	void Start () {
		if (!sp.IsOpen) {
			sp.Open();
			sp.ReadTimeout = 1000;
		} else {
			sp.Close();

		}
		
	}
	
	// Update is called once per frame
	void Update () {
		//文字列を数値に変換、meshMoveがArduinoアプリから送られてきた値
		int meshMove = int.Parse(sp.ReadLine());
		Debug.Log(meshMove);

//動きタグを振ったとき(meshMoveが1のとき)
		if(meshMove > 0) {
			count += 1;
		}
		else {
			count = 0;

		}
//動きタグを「実際に振ったとき」オブジェクトを動かす
		if(count == 1) {
			mMove += 1;
			transform.Translate(Vector3.left * mMove,Space.World);
		}
		
	}
}

誤認識をあまり厳密に捉えず、「めっちゃ振ったらそのぶんだけ動く」=「めっちゃ振ったら大きく動く」場合のコードはこちらです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;

public class meshUnityScript : MonoBehaviour {

	 private int mMove = 0;
	 private int count = 0;

	//new SerialPort("")にArduinoアプリで調べてメモしたシリアルポート名を指定する
SerialPort sp = new SerialPort("/dev/cu.SLAB_USBtoUART", 9600);

	// Use this for initialization
	void Start () {
		if (!sp.IsOpen) {
			sp.Open();
			sp.ReadTimeout = 1000;
		} else {
			sp.Close();

		}
		
	}
	
	// Update is called once per frame
	void Update () {
		//文字列を数値に変換、meshMoveがArduinoアプリから送られてきた値
		int meshMove = int.Parse(sp.ReadLine());
		Debug.Log(meshMove);

//動きタグを振ったとき(meshMoveが1のとき)
		if(meshMove > 0) {
			count += 1;
mMove += 1;
			transform.Translate(Vector3.left * mMove,Space.World);
		}
		else {
			count = 0;

		}

		
	}
}

M5StackをArduinoのように使ってUnityに送る(光センサー・アセットなし)

本来は加速度センサーを使ったほうが分かりやすいですが、手持ちがなかったので光センサーで代用です。
光センサーに光を当てると、Unity側のオブジェクトが回転します。
いろいろ書いて最初は上手くいかなかったのですが、どうも「int rot = int.Parse(sp.ReadLine());」がキモなようです。

f:id:prince9:20180926055721p:plain
f:id:prince9:20180926055732p:plain
写真は手持ちがなくて10kオームの抵抗を使ったせいで、値が1kオームのときとは異なってますが、お気になさらず。

■準備(Arduinoと同じ)
・1kオームの抵抗
・光センサ
・M5Stack
・ワイヤー

Arduino
1.下記のように接続する
図と抵抗の値が違っていますが、抵抗の色は無視してください。1kオームを使用します。
f:id:prince9:20180925195123p:plain
2.Arduinoアプリの「ツール」メニュー→「シリアルポート」の「シリアルポート"なんとか" ▶︎」の「"なんとか"」の部分をメモする。下記の例の場合は「"/dev/cu.SLAB_USBtoUART"」をメモする
f:id:prince9:20180926032905p:plain

●Unity側(アセットなし)
1.Unityのプロジェクトを作り、「GameOBject」メニュー→「3DObject」→「Cube」などを選び、適当にオブジェクトを作る
2.「File」メニュー→「Build Settings」を選択し、「Player Settings」をクリックする
3.Inspectorの「Other Settings」→「Api Compatibility Level」を「.NET 2.0」にする
4.「Build Settings」を閉じる
5.「Assets」を右クリックし、「Create」→「C# Script」を選択する
6.「ArduinoReceive」など適当にファイル名をつけて、後からスクリプトを書く
7.スクリプトを書いたら保存し、「Hierarchy」にある1.で作ったオブジェクト名にドラッグ&ドロップして適用する


スクリプト
Unity側はYouTube動画もろもろに助けられました。

Arduino

#include <M5Stack.h>

#define LDR_pin 36  // センサーをGPIO36につなぐ
int val=0;
int sdata=0;

void setup(){
    M5.begin();

Serial.begin(9600);
    pinMode(LDR_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);
    
val = analogRead(LDR_pin);
sdata = val/4; //値が大きすぎる場合は0-255になるよう、「/4」の「4」の値を変更する
 Serial.println(sdata); // センサーを読み、シリアルに出力
 
//M5の液晶に値を表示
    M5.Lcd.setTextColor(WHITE);
      M5.Lcd.setTextSize(5);
    M5.Lcd.print(sdata);
    
    delay(500);
      M5.update();
}

●Unity側

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;

public class ArduinoToUnityScript : MonoBehaviour {
int sdata = 0;

//new SerialPort("")にArduinoアプリで調べてメモしたシリアルポート名を指定する
SerialPort sp = new SerialPort("/dev/cu.SLAB_USBtoUART", 9600);

	// Use this for initialization
	void Start () {
		//シリアルポートが開いてないときはポートを開ける
		if (!sp.IsOpen) {
			sp.Open();
			sp.ReadTimeout = 1000;
		} else {
			sp.Close();

		}
		

		
	}
	
	// Update is called once per frame
	void Update () {
		//文字列を数値に変更
		int rot = int.Parse(sp.ReadLine());
		//オブジェクトの角度を変える
		transform.eulerAngles = new Vector3(0,rot,0);
		//コンソールにセンサーの値を出力
		Debug.Log(rot);

		
	}


}

M5StackをArduinoのように使う(MESHの動きタグ)

MESHの動きタグのデータをM5Stackに送り、M5Stackの色を変えるテストです。
動きタグを振ると、M5Stackの画面の色が変わります。

f:id:prince9:20180925210728p:plain
↑すみません、静止画です(汗

MESHのタグのデータをUnityなどに送ろうとしていたのですが、SDKが直のデータを出してくれずプロセスが大変になるので、GPIO経由で送ることにしました。
こっちのほうが楽ですね。お金かかるけど・・・時間をお金で買ったと思えば・・・

■準備
ソニーMESHの「動きタグ」
ソニーMESHの「GPIOタグ」
・M5Stack
・ワイヤー

これを下記のように接続します。
まずはGPIOのデジタル出力で試してみました。
f:id:prince9:20180925205928p:plain


■コード
まずMESHは以下になります。
動きタグを振ると、GPIOのデジタル出力が切り替わり、結果M5Stackの画面が切り替わります。
動きタグは設定をちゃんとしないと認識が微妙なときがあるため、データを検知したか知らせるために音を鳴らしています。

MESHのコード作成にあたり、下記を参考にさせて頂きました。
www.buildinsider.net

・MESHコード
f:id:prince9:20180925210141p:plain

Arduino(M5Stack)コード

#include <M5Stack.h>

#define MESH_pin 36  // GPIOをGPIO36につなぐ

void setup(){
    M5.begin();

Serial.begin(9600);
    pinMode(MESH_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);

   int sdata = digitalRead(MESH_pin);
    
    Serial.println(sdata); // GPIOの値を読み、シリアルに出力
    
if (sdata >= 1)
{
  M5.Lcd.fillScreen(GREEN);
}

else
{
  M5.Lcd.fillScreen(RED);
}
    delay(500);
      M5.update();
}

M5StackをArduinoのように使う(光センサー)

IoTとして使用されるケースが多いためか、ド基本が書かれているところが意外とないのでまとめ代わりに。
M5StackをArduino+LCD代わりにして、光センサの値をM5Stackの画面に表示します。
M5Stackはすでに使えるようになっているものとします。
この後、ソニーのMESHをつなげるので、動作チェック代わりにやってみました。

結果はこんな感じ(容量が大きくてGIFがアップロードできなかったので、静止画で)。
f:id:prince9:20180925195718p:plain
f:id:prince9:20180925195738p:plain
写真は手持ちがなくて10kオームの抵抗を使ったせいで、値が1kオームのときとは異なってますが、お気になさらず。

■準備(Arduinoと同じ)
・1kオームの抵抗
・光センサ
・M5Stack
・ワイヤー

これを下記のように接続します。
図と抵抗の値が違っていますが、抵抗の色は無視してください。1kオームを使用します。
f:id:prince9:20180925195123p:plain

■コード
下記のようなコードを書いてアップロードします。

#include <M5Stack.h>

#define LDR_pin 36  // センサーをGPIO36につなぐ
int val=0;

void setup(){
    M5.begin();

Serial.begin(9600);
    pinMode(LDR_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);
    
val = analogRead(LDR_pin);
sdata = val/4; //値が大きすぎる場合は0-255になるよう、「/4」の「4」の値を変更する
 Serial.println(sdata); // センサーを読み、シリアルに出力
 
    M5.Lcd.setTextColor(WHITE);
      M5.Lcd.setTextSize(5);
    M5.Lcd.print(sdata);
    
    delay(500);
      M5.update();
}

UnityのMecanim Locomotion Starter Kit+Character Controller+Box Colliderで衝突判定

Character Controllerは衝突判定を備えており、キャラクターのコントロールを簡単にするものです。
が、衝突判定との相性が良くないのか苦労されている方が多いようです。
ここでは下記の条件で衝突判定を行い、「衝突したら音が鳴る」「特定のエリアに入ったらシーン移動(ワープ)する」例を作ってみました。
Box Colliderの「Is Trigger」にチェックを入れるとキャラクターがオブジェクトをすり抜けるので、「この範囲に来たらワープする」などに使用できます。

今回はMecanim Locomotion Starter Kit+Character Controllerを使用しているため、障害物の前で止まる=障害物に接触しない=他の当たり判定が発動しないことになります。
(Character Controller自身で当たり判定のアクションを動作させることもできますが、あまり上手くいかなった)
なので、障害物より少し大きめの当たり判定エリアを作り、そのエリアに接したら(衝突したら)アクションが開始するようにします。

また障害物がキャラクターの身長より小さいと乗り越えて進んでしまうため、そこも注意が必要です。


●3Dキャラクター
・Mecanim Locomotion Starter Kitを使用
・Character Controllerを使用
・Rigidbodyを使用(ジャンプのアニメーションをさせたりしてたので)

最終的な状態:
f:id:prince9:20180729184243p:plain


●衝突するオブジェクト
・すり抜けをさせたくなかったので、衝突用のオブジェクトと衝突エリア用のオブジェクトをそれぞれ用意
・Box Colliderでキャラクターのすり抜けができなくなる(停止する)

最終的な状態:
f:id:prince9:20180729184451p:plain


●音が鳴る用の衝突エリア用のオブジェクト(いわゆる当たり判定エリア)
・Box Colliderの「Is Trigger」にチェックを入れる

最終的な状態:
f:id:prince9:20180729184358p:plain


●ワープ用の当たり判定エリア用のオブジェクト
・Box Colliderの「Is Trigger」にチェックを入れる

最終的な状態:
f:id:prince9:20180729184559p:plain



ではまず、「衝突したら音が鳴る」から。
すでに
・「Mecanim Locomotion Starter Kit」を使って矢印キーでキャラクターが操作できている
・Character Controllerを設定済み

な状態からスタートします(プログラミングの必要なし)。

■障害物を設置する
1.「GameObject」→「3D Object」→「Cube」を選択して立方体を出す
※キャラクターの身長より大きいサイズであること。でないと乗り越えてしまう
2.Hierarchy」→「Cube」をクリックし、「Inspector」の「Cube」を「Block」などにして名前を変える。必要であれば移動させておく
3.「Hierarchy」→「Block」をクリックし、「Inspector」→「Add Component」をクリックする


■Box Colliderを設定する
4.虫眼鏡アイコンのところに「Box Collider」と入力し、「Box Collider」をクリックする
5.衝突して止まるかの確認のため、Unityの再生ボタンを押して動作させる
※「Character Controller」を設定していないか、「Box Collider」の「Is Trigger」のチェックがONだとすり抜けてしまう


■当たり判定エリアを設定する
今回はCharacter Controllerを使用しているため、障害物の前で止まる=障害物に接触しない=他の当たり判定が発動しないことになります。
なので、障害物より少し大きめの当たり判定エリアを作り、そのエリアに接したら(衝突したら)アクションが開始するようにします。

6.「GameObject」→「3D Object」→「Cube」を選択して立方体を出す
7.「Hierarchy」→「Cube」をクリックし、「Inspector」の「Cube」を「JudgeArea」などにして名前を変える。1.で作った障害物と同じ位置に移動させる(Transformの数値を設定するなどで)
8.「Hierarchy」→「JudgeArea」をクリックし、「Inspector」→「Mesh Renderer」の右にある歯車のアイコンをクリックする
9.「Remove Component」を選択する。オブジェクトが非表示になり、枠線が表示される
10.「Hierarchy」→「JudgeArea」をクリックし、「Inspector」→「Transform」の「Scale」をXYZともに「1.5」程度に若干拡大する


■当たり判定エリア用のBox Colliderを設定する
11.「Hierarchy」→「JudgeArea」をクリックし、「Inspector」→「Add Component」をクリックする
12.虫眼鏡アイコンのところに「Box Collider」と入力し、「Box Collider」をクリックする
13.「Hierarchy」→「JudgeArea」をクリックし、「Inspector」→「Box Collider」の「Is Trigger」にチェックを入れる
※こうすることで「OnTriggerEnter」関数が呼び出され、「衝突したらアクションを起こす」という処理をさせることができる
※「Box Collider」の「Is Trigger」にチェックを入れると、そのオブジェクトをすり抜けることができる。そのためオブジェクトに衝突する前にキャラクターが止まらないので、衝突判定を設定することができる


■音を出す準備をする その1
14.「Hierarchy」→「JudgeArea」をクリックし、「Add Component」をクリックする
15.虫眼鏡アイコンのところに「AudioSource」と入力し、「AudioSource」をクリックする
16.「Asset」を右クリックし、「Import New Asset」をクリックして音源ファイルを選択する
17.「Hierarchy」→「JudgeArea」をクリックし、「Inspector」→「Audio Source」→「AudioClip」に音源ファイルをドラッグ&ドロップする


■衝突判定
18.「Hierarchy」→「JudgeArea」をクリックし、「Inspector」→「Add Component」をクリックする
19.「New Script」を選択し、名前を「AreaSctipt」として「Create and Add」を押す
20.「Asset」→「AreaSctipt」をダブルクリックして、下記のコードを書く

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class AreaSctipt : MonoBehaviour {

//音を出す準備
public AudioClip crashSound;

private AudioSource audioSource;

	void Start () {
//音を出す準備
audioSource = gameObject.GetComponent<AudioSource> ();
	}

//衝突したときの処理
void OnTriggerEnter(Collider col)
{

//実際の処理を書く(ここでは「crashSound」に設定した音源が鳴る)
audioSource.PlayOneShot (crashSound);
   }

}

■音を出す準備をする その2
21.「Hierarchy」→「JudgeArea」をクリックし、「Inspector」→「Area Script」の「Crash Sound」に「Assets」の中にある音源ファイルをドラッグ&ドロップする
22.「Hierarchy」→「JudgeArea」をクリックし、「Inspector」→「Audio Source」→「Play On Awake」のチェックを外す
23.Unityの再生ボタンを押して、ちゃんと衝突したときに音が鳴るか確認する


これでキーボードでキャラクターを動かして、かつ障害物に衝突すると音が鳴ります。鳴らない場合のいちばんの原因として、当たり判定のオブジェクトのサイズが小さすぎることがあります。Scaleの値を調整して、少し大きくしてあげましょう。


次は「この範囲に来たらワープ(シーン移動)する」です。
・「Mecanim Locomotion Starter Kit」を使って矢印キーでキャラクターが操作できている
・Character Controllerを設定済み

な状態からスタートします。
ワープした後、次のシーンでもキャラクターがいるようにしてあげます。
単純に同じシーンの他の位置へワープしたい場合は、キャラクターにスクリプトとタグ(これは後でやります)を設定し、下記のようにすればOKです。

void Update () {
//「WarpSctipt」というスクリプトに書いたフラグがOnのとき
if (WarpSctipt.flag == true) {
//このオブジェクトを原点に移動させる
this.gameObject.transform.position = new Vector3(0,0,0);
//「WarpSctipt」のフラグをOffにしておく(でないとワープした後動けない)
Warpctipt.flag = false;
}
}


■ワープエリアを設定する
ここでは壁にしました。

1.「GameObject」→「3D Object」→「Plane」を選択して平面を出す
2.「Hierarchy」→「Plane」をクリックし、「Inspector」の「Plane」を「NextStage」などにして名前を変える。必要であれば位置・大きさ・角度を調整する
※このとき壁の大きさはキャラクターの身長より高くする
3.「Hierarchy」→「NextStage」をクリックし、「Inspector」→「Mesh Renderer」の右にある歯車のアイコンをクリックする
4.「Remove Component」を選択する。オブジェクトが非表示になり、枠線が表示される


■ワープエリア用のBox Colliderを設定する
5.「Hierarchy」→「NextStage」をクリックし、「Inspector」→「Add Component」をクリックする
6.虫眼鏡アイコンのところに「Box Collider」と入力し、「Box Collider」をクリックする
7.「Hierarchy」→「NextStage」をクリックし、「Inspector」→「Box Collider」の「Is Trigger」にチェックを入れる
※ワープ用の壁はすり抜けてかまわないので、「Box Collider」の「Is Trigger」にチェックを入れる。すり抜けて欲しくない場合は「衝突したら音が鳴る」の1.-13.まで同じ


■キャラクターにタグをつける
オブジェクトが複数になってくると判別しにくくなるので、タグをつける。ここでは操作キャラクターに「Player」というタグをつける

8.「Hierarchy」→「3Dキャラクターのファイル名」をクリックし、「Inspector」→「Tag」の「Untagged」をクリックする
9.「Untagged」を「Player」に変える


■衝突(エリアに入ったか否か)判定
10.「Hierarchy」→「NextStage」をクリックし、「Inspector」→「Add Component」をクリックする
11.「New Script」を選択し、名前を「NextStageSctipt」として「Create and Add」を押す
12.「Asset」→「NextStageSctipt」をダブルクリックする
13.下記のコードを書く

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class NextStageSctipt : MonoBehaviour {
//フラグのOn/Offをbool(true/false)で管理する宣言
public static  bool flag;

	void Start () {
//最初のフラグはオフにしておく
flag = false;
	}

//キャラクターがエリアに入ったら
void OnTriggerEnter(Collider secondswarp)
{

//Playerというタグを持つオブジェクトがエリアに入ったら
if(secondswarp.tag=="Player")
    {

//フラグをOnにする
flag = true;
    }
}


■新しいシーン(次のステージ)をつくる
14.「Assets」→「Scenes」を右クリックし、「Create」→「Scene」を選択して新しいシーン(ステージ)を用意する
15.「New Scene」をクリックし、「2ndScene」に名前を変える
16.「Assets」→「Scenes」→「Sample Scene」をクリックし、「1ndScene」に名前を変える
17.「Assets」→「Scenes」→「2ndScene」のアイコン部分をダブルクリックし、新しいシーンの編集をする
18.「GameObject」→「3D Object」→「Plane」を選択して地面を出す
19.「Hierarchy」→「Plane」をクリックし、「Inspector」の「Plane」という名前を「2ndGround」に変える。必要があればマテリアルも設定する
20.新しいシーンにオブジェクトを配置する


■シーン移動のコードを書く
21.「Hierarchy」→「3Dキャラクターのファイル名」をクリックし、「Inspector」→「Add Component」をクリックする
11.「New Script」を選択し、名前を「WarpPlayer」として「Create and Add」を押す
12.「Asset」→「WarpPlayer」をダブルクリックする
13.下記のコードを書く

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

//ステージ移動できるようにする
using UnityEngine.SceneManagement;

public class WarpPlayer : MonoBehaviour {
	void Update () {

//「NextStageSctipt」で設定したフラグがOn(true)になったら
if (NextStageSctipt.flag == true) {

//「2ndScene」というシーンに移動
SceneManager.LoadScene ("2ndScene");

//「NextStageSctipt」で設定したフラグをOff(false)にしておく(これをしないとステージ移動後に動けなくなる)
NextStageSctipt.flag = false;
}
}

//次のシーンでもキャラクターが存在して動くための設定
void Awake () {
	DontDestroyOnLoad(this.gameObject);
}

}


■シーン移動の設定をする
このままではまだシーンの移動ができない。下記の設定も必要となる
14.「Assets」→「Scenes」→「1ndScene」のアイコン部分をダブルクリックして、「1ndScene」が表示された状態にする
15.Assets」→「Scenes」→「2ndScene」をクリックする
16.「File」メニュー→「Build Settings」を選択する
17.「Add Open Scenes」をクリックする
下記のように「2ndScene」が追加されていればOK。
f:id:prince9:20180729194113p:plain


■照明の設定をする
Unityではシーンの移動をすると全体が暗くなってしまう。その対処法として下記のようにする。
Unity2018版の方法です。

18.「Assets」→「Scenes」→「1ndScene」のアイコン部分をダブルクリックして、「1ndScene」が表示された状態にする
19.「Window」メニュー→「Lighting」→「Settings」を選択し、「Object Maps」タグをクリックする
20.「Auto Generate」のチェックを外す
21.「Generate Lighting」をクリックする
22.「Assets」→「Scenes」→「2ndScene」のアイコン部分をダブルクリックして、「2ndScene」が表示された状態にする
23.「Window」メニュー→「Lighting」→「Settings」を選択し、「Object Maps」タグをクリックする
24.「Auto Generate」のチェックを外す
25.「Generate Lighting」をクリックする

これで再生ボタンを押せば動きます。
f:id:prince9:20180729195213g:plain

時短でUnityちゃんトゥーンシェーダを使う

Unityでアニメ調の見た目にしてくれる「Unityちゃんトゥーンシェーダ」。Unityに慣れてるヤツしか触るな!的で、モデリング始めたばかりの方にはややとっつきにくい印象があります。
なので、Unityに触ったことがないという方でも分かるようにできるだけ細かく書いてみました(たぶん私が忘れるので・・・)。
とりあえず、超簡単に使うための方法です。詳細な設定は、Unityちゃんトゥーンシェーダをダウンロードするとついてくるご本家のマニュアルを参照ください。

とにかく時短、ということで、Unityちゃんトゥーンシェーダを使うにあたり以下の制約条件のもと設定しています。
・表情モーフなし、スカートなどの揺れボーンなし
・Mixamoで自動でボーン&スキニング設定をする
・目以外のテクスチャはなし、3Dアプリで設定するマテリアルは色のみ

表情モーフありの設定バージョンは後日に。

記事執筆にあたり、こちらを参照させて頂きました。

www.slideshare.net
www.youtube.com


■UnityとUnityちゃんトゥーンシェーダをダウンロード
1.下記からUnityをダウンロードする
store.unity.com
2.下記からUnityちゃんトゥーンシェーダをダウンロードする
ユニティちゃんトゥーンシェーダー2.0 - ダウンロード - UNITY-CHAN! OFFICIAL WEBSITE


■モデルを用意する
1.3Dアプリで「.fbx」形式でモデルを書き出す。このときにテクスチャをfbxファイルと同じファイル階層に置くこと(テクスチャ作成時から注意しておく)
※mixamoを使って自動でボーンを入れる場合は、バージョンを「FBX7.4バイナリ」または「FBX2014」にして書き出し、.fbxファイルとテクスチャファイルをフォルダにまとめてZIP圧縮する。それをmixamoのサイトでアップロードしてください。そしてできた.fbxファイルを使用します
2.Unityを立ち上げ、プロジェクトファイルを作成する
3.「Assets」を右クリックして、「Create」を→「Folder」を選択してフォルダを作る
4.「New Folder」の名前を「Textures」にする
5.「Textures」フォルダの中にモデルのテクスチャデータをドラッグする
6.「Assets」を右クリックして、「Inport New Assets」でfbxファイルを選ぶ
f:id:prince9:20180605175231p:plain
7.「Inspector」→「Materials」を選択し、下記のようになっているか確認する
・Import Materialsにチェックが入っている
・「Location」が「Use Embedded Materials」になっている
f:id:prince9:20180605175453p:plain


■ボーンの対応付けを確認する
8.「Assets」→モデルのフォルダをクリックし、下記を行う
・「Inspector」→「Model」を選択し、「Import Cameras」「Import Lights」のチェックを外す。さらに「Apply」を押す
f:id:prince9:20180606214420p:plain
・「Inspector」→「RIg」を選択して、「Animation Type」を「Humanoid」にして「Apply」を押す
・「Inspector」→「RIg」の「Avator Definition」にチェックが入っているか確認する
f:id:prince9:20180605202648p:plain

※ここで「Avator Definition」に×印がついている場合は3Dアプリで作ったボーンとUnityとのリンクが上手くいっていないので、下記のような方法を取る
8-1.「configure」をクリックすると、「Hierarchy」に「Avatar Configuration」という項目が出てくるので、対応するボーンを「Inspector」のそれぞれの対応項目にドラッグする
f:id:prince9:20180605203348p:plain
8-2.対応付けが終わったら、人型がすべて緑色になっていることを確認して「Apply」ボタン→「Done」ボタンを押す
8-3.「Avator Definition」が×印からチェック印に変わっていればOK


■マテリアルを設定する
Unityに読み込むとマテリアルとテクスチャの紐付けが取れてしまっているので、それを結び直します
9.「Inspector」→「Materials」で下記の「Extract Materials」をクリックする
f:id:prince9:20180608031746p:plain
10.「Asstes」フォルダの中に新しく「Materials」フォルダを作り、「Choose」を押す
11.そうすると自動的にマテリアルを紐づけてくれる


■Unityちゃんトゥーンシェーダを使う準備
12.「File」メニュー→「Build Settings」→「PC,Mac&Linux Standalone」が選択されている状態で「Player Settings」をクリックし、「Other Settings」→「Color Space」を「Linear」にする
f:id:prince9:20180703042051p:plain
13.「Hierarchy」ウィンドウの「Directional Light」をクリックし、「Color」を白にする
f:id:prince9:20180703043642p:plain

■照明とカメラの設定をする
デフォルトの状態でUnityちゃんトゥーンシェーダを使うと、若干暗くなってしまう。なので、下記の設定を行う
※2018年10月の時点では、14.は必要なくなりました
14.「Window」→「Lighting」→「Settings」→「Enviroment Lignting」の「Source」を「Color」にして、「AmbientColor」を白系統にする
f:id:prince9:20180703194732p:plain
15.「Hierarchy」ウィンドウの「Directional Light」をクリックし、「Inspector」を下記のようにして仮の照明を設定する
(「UnityChanToonShaderVer2_Project-master」→「Assets」→「ToonShader.unity」のUnityちゃんが映っているシーンを参照)
f:id:prince9:20180703195916p:plain
16.「Hierarchy」ウィンドウの「Main Camera」をクリックし、を下記のようにして仮のカメラを設定する
f:id:prince9:20180703195932p:plain


■3Dモデルを表示する
17.「Assets」→モデルのフォルダを「Hierarchy」ウィンドウにドラッグする
f:id:prince9:20180606034803p:plain
18モデルが表示されるので、シーンビューの右上にある下記のようなアイコンに注目する。このアイコンの中央の□を右クリックして、「Front」を選ぶ
f:id:prince9:20180606214121p:plain
19.下記の方法でモデルを見やすい位置に持ってくる
・視点の平行移動 マウスのスクロールボタンを押す
・視点のズームイン/アウト マウスのスクロールボタンを動かす
・(必要であれば)回転 マウスの右クリックを押す


■モデルの身長を調整する
20.「GameObject」メニュー→「3D object」→「Cube」を選択し、立方体を表示させる
21.「W」キーを押す。次に赤色の矢印が出てくるので、先端をクリックしながらマウスを動かし、立方体を左に移動させる。モデルと並ぶように配置する
22.「R」キーを押す。次に緑色の■が出てくるので、先端をクリックしながらマウスを上に動かして、モデルと同じ「高さ」になるように拡大or縮小する
f:id:prince9:20180703045220p:plain
モデルと立方体の地面の高さが同じになるよう、18.と同じ方法で立方体を動かす
23.立方体がクリックされている状態で、「Inspector」→「Scale」の「Y軸」の値を確認する
この値(m)がモデル(アバター)のサイズと同じくらいであれば問題ないが、大幅に異なる場合は以下のようにモデルのサイズを調整する
23-1.モデルの拡大or縮小率を下記のように計算する
モデル(アバター)の身長(m)÷16.で確認した立方体のY軸のScaleの値
例:アバターの身長が150cm(1.5m)で、立方体のY軸のScaleの値が3の場合
1.5m÷3m=0.5
23-2.「Assets」→モデルのフォルダをクリックし、「Inspector」→「Model」→「Scale Factor」に先ほど算出した拡大or縮小率を入力して(例の場合だと「0.5」)「Apply」を押す
24.「Hierarchy」ウィンドウの「Cube」を右クリックし、「Delete」を選択して立方体を消す


■Unityちゃんトゥーンシェーダで影をセットアップする
具体的にセットアップする項目は、赤色で囲ったところ。
f:id:prince9:20180703202856p:plain
25.「Assets」を右クリックして「Import Package」→「Custom Package」を選択する
26.2.でダウンロードして解凍した「UnityChanToonShaderVer2_Project-master」フォルダの「UTS2_ShaderOnly_v2.0.4_Release.unitypackage」を選択して「Open」を押す
27.「Import」ボタンを押す
28.基本の色や影の色のRGB値を知るため、3Dモデルの設定画(彩色済み)をPhotohopやSAI、クリスタなどで開いておく
29.「Assets」→「Materials」→マテリアル名をクリックし、「Shader」を「Toon_DoubleShadeWithFeather」にする

ここから影色・ハイライト色・輪郭線色などを設定していきます。これはすべての色(マテリアル)に対して行う。
30.「Inspector」に設定画面がずらずら出てくる。影色では下記が設定項目となる
f:id:prince9:20180703055526p:plain
目などテクスチャが必要なマテリアル(色)は、あらかじめ「Assets」→「Textures」フォルダにテクスチャファイルを入れておく。その上で、「Texture」の項目の「Select」ボタンを押してテクスチャを選択する。出てこない場合は、虫メガネアイコンのところにテクスチャのファイル名を入力する。

31.1カゲ(基本の影)と2カゲ(さらに濃い影)の色を設定する
f:id:prince9:20180703172507p:plain
32.「ShaderColor_Step」を0にしておく
f:id:prince9:20180703172821p:plain
33.「BaserColor_Step」のスライダを右に動かし、画面を見ながら影の出る具合を調整する
f:id:prince9:20180703172938p:plain
34.影の境界をボカしたい場合は「Base/Shade_Feather」の値を大きくする
f:id:prince9:20180703173112p:plain
35.2カゲを使う場合は「ShaderColor_Step」のスライダを右に動かし、画面を見ながら影の出る具合を調整する
f:id:prince9:20180703173323p:plain
36.2カゲの影の境界をボカしたい場合は「Base/Shade_Feather」の値を大きくする
f:id:prince9:20180703173450p:plain

■Unityちゃんトゥーンシェーダでハイライトをセットアップする
37.「HighColor」でハイライトの色を設定する
38.「HighColor_Power」でハイライトの強さを設定する
f:id:prince9:20180703174531p:plain

■Unityちゃんトゥーンシェーダでリムライト(反射光)をセットアップする
リムライトとは、キャラクターの背後から当てられる反射光のことです。主に女性や羽など、キャラクターを柔らかく見せるために使われます。
すごく分かりにくいですがこんな感じです。下図では髪の毛のハイライトは水色っぽい光ですが、よく見ると頭の輪郭と頭の間に真っ白な色を塗っています。これがリムライトの効果です。
厚塗りではよく使われます。
f:id:prince9:20180703175623p:plain
39.「RimLigntColor」で反射光の色を設定する
40.「RimLignt_Power」で反射光の強さを設定する
f:id:prince9:20180703180100p:plain

■Unityちゃんトゥーンシェーダで輪郭線をセットアップする
41.「Outline_Width」で輪郭線の太さを調整する
42.「「Outline_Color」で輪郭線の色を調整する
43.「Farthest_DIstance」で輪郭線の太さが変化し始める最短距離を設定する
f:id:prince9:20180703183531p:plain

トゥーンシェーダーのライセンスについて
© Unity Technologies Japan/UCL