- 投稿日:2021-06-20T23:41:27+09:00
プレイ中にFreezePositionとFreezeRotationのオンオフ
空中アスレチックを作成していて、回る物体を作りました。 回してPlayerを移動させるとPlayerが物体に当たったら下の床に食い込むんですね。 この原因はPlayerのRigidbodyのFreezePositionのY軸のチェックが入ってなかったからです。 では、チェックを入れるとどうなるのか? 現象は解消されました! が。。。床から落とすと当然下に落ちません。。。 こういう場合、床に乗っている時はFreezePositionのY軸をオン、 床に乗っていない時はオフにしたい訳です。 まず、RigidbodyのFreezePositionとFreezeRotationを全てチェックを外します。 それからコードを書いていきます。 rb.constraints = RigidbodyConstraints.FreezeRotation; //Rotationを全てオン rb.constraints = RigidbodyConstraints.FreezePosition; //Positionを全てオン rb.constraints = RigidbodyConstraints.FreezeRotationX; //RotationのXのみオン rb.constraints = RigidbodyConstraints.FreezeRotationY; //RotationのYのみオン rb.constraints = RigidbodyConstraints.FreezeRotationZ; //RotationのZのみオン rb.constraints = RigidbodyConstraints.FreezePositionX; //PositionのXのみオン rb.constraints = RigidbodyConstraints.FreezePositionY; //PositionのYのみオン rb.constraints = RigidbodyConstraints.FreezePositionZ; //PositionのZのみオン ※rbはRigidbodyの変数です。 では、私の場合はRotationは全てオン、PositionはY軸のみオンにしたいので。。。 rb.constraints = RigidbodyConstraints.FreezeRotation; //Rotationを全てオン rb.constraints = RigidbodyConstraints.FreezePositionY; //PositionのYのみオン こう書けば大丈夫!! だと思いましたが、残念ながら違います… rb.constraints = RigidbodyConstraints.FreezeRotation //Rotationを全てオン | RigidbodyConstraints.FreezePositionY; //PositionのYのみオン こう書かないといけないのです。 1行目はセミコロンのみ書かなくて良くてrb.constraintsは書かなくていいです!! これで大丈夫!! ちなみに 私の場合は常にRotationは全てオン、 床に乗っている時だけPositionはY軸のみオンにしたいので。。。 //collisionに接触している場合はRotationは全てオン、PositionはY軸のみオンにする。 void OnCollisionStay(Collision collision) { rb.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionY; } //collisionに接触してない時はPositionのY軸はオフ。Rotationは全てオンのまま。 void OnCollisionExit() { rb.constraints = RigidbodyConstraints.FreezeRotation; } これで最初は全てチェック外している状態ですが、Rotationは全て、PositionのY軸のみプレイしたらチェックが入り、床から落ちるとPositionのY軸のみチェックが外れます!!
- 投稿日:2021-06-20T22:24:25+09:00
UnityでArduinoにシリアル通信を送る
UnityからArduinoにシリアルを送ってLチカする やること UnityでArduinoにシリアル通信を送るテストを行います。 前回記事 UnityでArduinoからシリアル通信を受け取る の逆です。 主な参考URL UnityとArduinoをシリアル通信 環境 Unity Hub Unity 2018.4.28f1 Arduino 事前準備 UnityでArduinoからシリアル通信を受け取る ↑に書かれている内容を実施し、動く状態にしておきます。 この記事では上記との差分のみを説明します。 Arduinoの準備 Arduino側のスクリプトはシンプルに下記のようにします。 "1"という文字を受信したらLEDを点灯するようにします。 Arduino #define LED_PIN 13 //LEDのピン番号。13は内蔵LED。 char data; void setup() { Serial.begin(115200); pinMode(LED_PIN, OUTPUT); } void loop() { if ( Serial.available() > 0 ) { // 受信データがあるか? data = Serial.read(); // 1文字だけ読み込む if (data == 0x31) { //文字コード0x31、つまり"1"を受信したらLEDを光らせる。 digitalWrite(LED_PIN, HIGH); delay(200); digitalWrite(LED_PIN, LOW); } } } Arduinoに書き込んだら準備は終了です。 Unityの設定変更 Unityから一定間隔で"1"という文字をシリアルで送ろうと思います。 FixedUpdateメソッドを使えば、Unityのフレーム更新毎の命令とは別に、コードを一定間隔で実行する設定ができます。先にその「一定間隔」を設定しておきます。 「Edit」→「Project Setting」→「Time」より、 Fixed Timestepを0.001(1/1000)に設定しておきます。(環境によっては0.01などでもかまいません。デフォルトは0.02のようです。) Unityのスクリプト設定 UnityからArduinoへシリアルを送信するスクリプトを作成します。 SerialSend.cs を作成します。 C#のスクリプトを作成し、ファイル名を「SerialReceive」にします。 スクリプトは下記のようにします。 SerialReceive.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class SerialSend : MonoBehaviour { //SerialHandler.cのクラス public SerialHandler serialHandler; int i = 0; void FixedUpdate() //ここは0.001秒ごとに実行される { i = i + 1; //iを加算していって1秒ごとに"1"のシリアル送信を実行 if (i > 999) // { serialHandler.Write("1"); i = 0; } } } 終わったらセーブします。 スクリプトをアタッチする 作成したスクリプトが実行できるようにします。 「Assets」内にあるスクリプト「SerialSend」をヒエラルキーウィンドウのオブジェクト「Serial_Test」にドラッグ&ドロップでアタッチします。 ヒエラルキーウィンドウの「Serial_Test」をクリックし、右のインスペクターウィンドウを確認します。 インスペクターの「SerialSend(Script)」の「SerialHandler」のボックスに、ヒエラルキーウィンドウの「Serial_Test」をドラッグアンドドロップしてアサインします。 また、インスペクターの「SerialRead」のチェックを外して無効にします。 これで準備が完了です。 実行 Unityの再生ボタンを押し、実行します。 うまくいけばArduinoのLEDが1秒間隔で点滅します。 終了方法 Unityの再生停止ボタンを押した後、Arduino側のリセットボタンを押します。(超重要) Arduino側のリセットボタンを押さないと、Unityがシリアルの送受信プロセスを終了することができず、カーソルがクルクル回り続け終了できません。 今回はテストなのでそのままでもよいですが、いざ実用となった際にはコードにタイムアウト処理やクローズ処理を入れるなど、もう一手間必要でしょう。 おわりに これで最低限のUnity→Arduino間のシリアル通信もできるようになりました。 双方向通信やスピード調整、長いデータのやりとりなどに細かなTipsが必要のようなので、そのあたりを調べていきます。 前回記事:UnityでArduinoからシリアル通信を受け取る 参考 下記のサイトを参考にさせていただきました。ありがとうございました。 SerialPort または Uniduino を使った Unity と Arduino を連携させる方法調べてみた Unity - Arduino間でBluetooth Serial通信をするとUnity終了時にSerialを閉じるのに失敗する UnityとArduinoをシリアル通信 Unityでシリアル通信する際に試したこと Arduino+Unity(シリアル通信)するときの手順メモ
- 投稿日:2021-06-20T19:03:53+09:00
Unity から Google Cloud Anchor を使うための Google Cloud Platform の設定方法
Unity から Google Cloud Platform で Google Cloud Anchor を使うたための設定手順です。 Anchor を使うためのプログラムはところどころ見かけまので、そちらを参考にしてください。 GoogleCloudConsole の設定 1. ARCore Cloud Anchor API を有効にします 2. 認証情報の作成 ボタン押します 認証情報の種類の設定します スコープの設定は省力可なので何もしません keytool で SHA-1証明書のフィンガープリントを取得します。こちらは後ほど使用します。 取得用のサンプルコマンドは↓ "tekisetsuna-path/keytool.exe" -list -v -keystore filename.keystore OAuth クライアントIDを設定します Unity の設定 Publish Settings の Custom Keysotore を keytool で SHA-1証明書のフィンガープリントを取得 で利用したものに変更、二か所あパスワード設定します。 これだけで、後はコードをかけば Anchor を利用できます。 おまけ ErrorNotAuthorized が出る場合 上記設定しても Host がうまくいかない場合(ErrorNotAuthorized)は、Unity の PlayerSettings/Player/Other Settings/Identification/Package Name の値と、GCPの認証用に作ったパッケージ名が完全に一致しているか確認してみてください。(私は com.xxxx と jp.xxxx とで間違えていて、ErrorNotAuthorized が出ていました) ErrorHostingDatasetProcessingFailed が出る場合 GCP の内部エラーの一つです。利用端末から送っている特徴量が少なすぎて保存できないことが原因だと思われます。 一度カメラで周りを見渡してから、Host することで出なくなりますので、数回そのまま試してみてください。 (Hostを開始前から周辺情報を蓄積しているようなので、先に見回しておくのが良いみたいです。)
- 投稿日:2021-06-20T14:36:27+09:00
床が自動で動くと同時にPlayerも一緒に動く方法
前回の続きです。 void OnCollisionStay(Collision collision) { if (collision.gameObject.tag == "Stage") { transform.parent = collision.gameObject.transform; } } void OnCollisionExit() { transform.parent = null; } 動く床にCollisionをつけてタグも設定し、Playerスクリプトに書きます。 OnCollisionStayはブジェクト同士が接触している間なので、 Stageタグの上に乗っている間Playerが移動する。 OnCollisionExitはオブジェクト同士が接触から離れた瞬間なので 離れた瞬間はnullします。 こうすることで床が動くと同時にPlayerも動くようになります。
- 投稿日:2021-06-20T14:13:34+09:00
床が自動で動く方法
空中アスレチックを作成していて、床が自動で動く方法をご紹介します。 using System.Collections; using System.Collections.Generic; using UnityEngine; public class UpDown : MonoBehaviour { private Vector3 StagePos; //StagePos変数を設定 void Start() { StagePos = transform.position; } void Update() { transform.position = new Vector3(StagePos.x, Mathf.Sin(Time.time) * 5.0f + StagePos.y, StagePos.z); } } Mathf.Sin関数を使います。 5.0fは動く範囲を判断。 今回は上下に動く床を作りたかったのでyに足しています。 左右に動いてほしかったらxに足せば良いです。 床が動くとPlayerも動かさないと落ちてしまいます。 つまり、床の上に乗るとPlayerは一緒に動いてくれません。 次回はPlayerも一緒に動かす方法をご紹介します。
- 投稿日:2021-06-20T14:12:27+09:00
UnityでArduinoからシリアル通信を受け取る
罠だらけらしいので最低限の動作確認から やること UnityでArduinoのシリアル通信を受信するテストを行います。 逆方向の通信が必要な方は、当記事のチェック後に、UnityでArduinoにシリアル通信を送るをご覧ください。 主な参考URL UnityとArduinoをシリアル通信 環境 Unity Hub Unity 2018.4.28f1 Arduino Arduinoの準備 Arduino側のスクリプトはシンプルに下記のようにします。 "Hello, this is Arduino."という文字列のメッセージを1秒毎にシリアルに送信します。 Arduino void setup() { Serial.begin(115200); //シリアルポートを115200bpsで開く } void loop() { //文字列のメッセージを1秒毎にシリアルに送信する Serial.print("Hello, this is Arduino."); Serial.println(); delay(1000); } Arduinoに書き込んだら準備は終了です。 Unityの環境設定 Unityのプロジェクトを作成し、環境設定を整えます。 Unity Hubより、バージョンを2018.4.28f1に指定してUnityの新規プロジェクトを作成します。 メニューの「EDIT」→「Project settings...」を選択します。 「Player」の「Other Settings」から、 - 「Script Runtime Version」 を「.NET 4.x Eauivalent」に設定。 - 「Api Compatibility Level」を 「.NET 4.x」に設定。 これで環境設定は完了です。 Unityのスクリプト設定 Unityで使うスクリプトを2つ準備します。 ① SerialHandler.cs を作成します。 スクリプトファイルを作ります。 画面下の「Assets」の中で右クリックし、「Create」→「C# Script」を選択。 ファイル名を「SerialHandler」とします。 UnityとArduinoをシリアル通信より、SerialHandler.csのスクリプトを作成したファイルの中にコピペします。 ファイルの内容を環境に合わせて書き換えます。 先に、ArduinoのIDE等で今回のシリアル通信で使うポート名を調べます。 スクリプトを、下記のように書き換えます。 public string portName = "(調べたポート名)"; public int baudRate = 115200; 終わったらセーブします。 ② SerialReceive.cs を作成します。 ①と同様にC#のスクリプトを作成し、ファイル名を「SerialReceive」にします。 スクリプトは下記のようにします。 SerialReceive.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class SerialReceive : MonoBehaviour { //https://qiita.com/yjiro0403/items/54e9518b5624c0030531 //上記URLのSerialHandler.cのクラス public SerialHandler serialHandler; void Start() { //信号を受信したときに、そのメッセージの処理を行う serialHandler.OnDataReceived += OnDataReceived; } //受信した信号(message)に対する処理 void OnDataReceived(string message) { var data = message.Split( new string[] { "\n" }, System.StringSplitOptions.None); try { Debug.Log(data[0]);//Unityのコンソールに受信データを表示 } catch (System.Exception e) { Debug.LogWarning(e.Message);//エラーを表示 } } } 終わったらセーブします。 スクリプトをアタッチする 作成したスクリプトが実行できるようにします。 左上のヒエラルキーウィンドウの中で右クリックし、空のオブジェクトを作成します。 オブジェクト名を「Serial_Test」などに変更します。 次に、「Assets」内にある2つのスクリプト、「SerialHandler」「SerialReceive」をヒエラルキーウィンドウの「Serial_Test」オブジェクトにドラッグ&ドロップでアタッチします。 ヒエラルキーウィンドウの「Serial_Test」をクリックし、右のインスペクターウィンドウを確認します。 インスペクターの「SerialReceive(Script)」の「SerialHandler」のボックスに、ヒエラルキーウィンドウの「Serial_Test」をドラッグアンドドロップしてアタッチします。 これで準備が完了です。 実行 Unityの再生ボタンを押し、実行します。 画面下部の「Console」タブを選択すると、Arduinoから受信したメッセージが表示されます。 おわりに これで最低限のArduino→Unity間のシリアル通信環境がなんとか整いました。 双方向通信やスピード調整、長いデータのやりとりなどに細かなTipsが必要のようなので、そのあたりを調べていきます。 次の記事では、Unityから送られたシリアル信号をArduinoで受け取りLチカをさせてみますので、よかったら合わせてお読みください。 次回記事:UnityでArduinoにシリアル通信を送る 参考 下記のサイトを参考にさせていただきました。ありがとうございました。 SerialPort または Uniduino を使った Unity と Arduino を連携させる方法調べてみた UnityとArduinoをシリアル通信 Unityでシリアル通信する際に試したこと Arduino+Unity(シリアル通信)するときの手順メモ
- 投稿日:2021-06-20T13:57:05+09:00
Playerが動く方向にカメラも動く方法
CameraManager public class CameraManager : MonoBehaviour { //格納する変数 public GameObject Player; public float CameraX; public float CameraY; public float CameraZ; void Start() { } void Update() { Vector3 Pos = Player.transform.position; //カメラとプレイヤーの位置を同じにする transform.position = new Vector3(Pos.x + CameraX, Pos.y + CameraY, Pos.z + CameraZ); } } ここまで書けたらカメラにスクリプトをアタッチ。 インスペクターにある CameraX CameraY CameraZ にはPlayerとカメラの位置を設定する。 PlayerにはヒエラルキーのPlayerを入れる。 (私の場合はPlayerですが、カメラで追いかけたいものを紐づける) これでPlayerが動くと同時にカメラが追いかけるようになりました。
- 投稿日:2021-06-20T13:11:14+09:00
全部消えたらクリア画面を表示
ブロック崩しゲームを作成していて、全部消えたらクリア画面に遷移したいと思います。 全部消えたらの表現はタグを作って実装しています。 GameClear using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; //シーン遷移に必要な記述 public class GameClear : MonoBehaviour { private GameObject[] BlockObjects; //GameObjectにBlockObjectsを格納します void Update() { //消えるオブジェクトにBlockタグをつけます。 BlockObjects = GameObject.FindGameObjectsWithTag("Block"); if (BlockObjects.Length == 0) //Blockタグがついてる残りが0になれば { SceneManager.LoadScene("GameClear"); //クリアシーンを表示 } } } シーン遷移する時はBuildsettingもしないといけません。 ※以前にBuildsettingのやり方を書いた記事があります。 これで無事、ブロックが全て消えた時にシーンが切り替わるようになりました。 ここで注意点なのですが、このスクリプトは消えるブロックにアタッチすると 全部消えた際にシーンは切り替えされません。 理由はブロックが消えてしまったらゲーム中にヒエラルキー上のブロックオブジェクト自体も消えてしまい、アタッチしたスクリプトも消えてしまいます。 なので、他のオブジェクトにアタッチするか、新たにオブジェクトを作成する必要があります。 こういうミスする人はいないかもしれませんが、私はこれで悩まされました(笑)