Unity5.6を使用しています。
4桁のパスワード機能を実装しようと思っております。
GUIは完成して、あとはプログラムのところなのですが
わからいない点が何点かあり、質問させていただきます。
□プログラム概要
Sphere(プレイヤー)をハンドセンサーでトラッキングさせ
cube(0~9までの数字オブジェクト)に衝突すると
各々の数字の値をintする仕様です。
□質問内容
例えばパスワードを"6443"に設定する方法
およびcubeとの衝突判定でどのように変数を追加していくのか
6,4,4,3の順番で衝突判定を行うと合計で17になる為
(衝突判定の回数で制御?変数を4桁分用意する?)
恐れ入りますが、ご査収の程よろしくお願い致します。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
ベストアンサー
いろいろやり方がありそうですね。質問者さんのおっしゃるように、変数を4桁分作って(これは配列とかList<int>でもよさそうです)、さらに「現在何桁目の入力受付中か」を表す変数を追加すれば各桁を入力していくことができるかと思います。
別パターンとして、パスワードを文字列として格納し、入力文字列がパスワード文字列の長さ以上になったら両者の内容を比較、一致不一致を判定する方式を試してみましたが、いかがでしょうか。
C#
1using UnityEngine; 2 3public class PasswordBehaviour : MonoBehaviour 4{ 5 public string PasswordString; // 入力してほしいパスワード、あらかじめインスペクタから適当な値を入れておく 6 private string playersAnswer; // プレイヤーの回答 7 8 private void Start() 9 { 10 this.playersAnswer = ""; // プレイヤーの回答を空にしておく 11 } 12 13 private void Update() 14 { 15 var digit = Input.inputString; // 実験用に、球の衝突の代わりにキーボードから入力を受け取る 16 if (!string.IsNullOrEmpty(digit) && char.IsDigit(digit, 0)) 17 { 18 this.playersAnswer += digit[0]; // 実際には球とキューブの衝突に対応して回答文字列に数字を追加 19 Debug.Log("Password : " + this.playersAnswer); 20 21 // 回答に数字を追加するたび回答の長さをチェック 22 if (this.playersAnswer.Length >= this.PasswordString.Length) 23 { 24 if (this.playersAnswer == this.PasswordString) 25 { 26 Debug.Log("Accepted!"); 27 } 28 else 29 { 30 Debug.Log("Denied!"); 31 } 32 this.playersAnswer = ""; // プレイヤーの回答を空に戻す 33 } 34 } 35 } 36}
[追記]
ボールと箱の衝突でパスワードを入力するテストをやってみました。自身の勉強も兼ねて、画面上の見栄えをいくらかそれらしくするためのコードを追加したため、ちょっとシンプルさは損なわれてしまいましたがご容赦ください。
次のような構成で作りました。
- ボール、箱0〜9、ゲートを用意する。
- ボールはプレイヤーの操作に合わせて転がるだけで、衝突判定やパスワード判定のロジックは持っていない。
- 箱が衝突判定を行う。ボールと自身の衝突を検知したら、自身が持つ文字(箱0であれば「0」...)を引数とする数字入力イベントを発生する。
- ゲートは箱からの数字入力イベントに応答し、そこで上記コードのロジックによってパスワードを入力していく。パスワードが正しければ、ゲートを開くアニメーションを行う。
肝になる箱とゲートのスクリプトは下記のようにしました。
コード内の「※」の付いたコメントの部分は、今回のパスワード入力とは直接関係のない箇所ですので、あまり気にしないでください(見た目の制御などに関わる部分です)。
箱のスクリプト
C#
1using UnityEngine; 2using UnityEngine.Events; 3 4 // 数字入力のためのカスタムイベント 5[Serializable] 6public class NumberBoxEvent : UnityEvent<string> 7{ 8} 9 10public class NumberBoxController : MonoBehaviour 11{ 12 public string Character; // 箱が表す数字、インスペクタで箱ごとに設定しておく 13 public NumberBoxEvent OnEnterNumber; // 衝突時にこのイベントを発生させる 14 private NumberPaneController numberPaneController; // ※箱の見た目が同じだと画面上で区別が付かないので、子オブジェクトとして数字表示板を持たせた 15 16 // 衝突発生時に物理シミュレーションエンジンによって自動的に呼び出される 17 private void OnCollisionEnter(Collision collision) 18 { 19 if (collision.gameObject.tag == "Player") // ボールには「Player」タグを付けておき、ボールとの衝突だけに応答する(箱同士や地面・壁との衝突があっても何もしない) 20 { 21 this.numberPaneController.Lit = true; // ※数字表示板を点灯させて衝突したことを分かりやすくした 22 this.OnEnterNumber.Invoke(this.Character); // Characterを引数にして数字入力イベントを起こす 23 } 24 } 25 26 // 衝突終了時に物理シミュレーションエンジンによって自動的に呼び出される 27 private void OnCollisionExit(Collision collisionInfo) 28 { 29 if (collisionInfo.gameObject.tag == "Player") 30 { 31 this.numberPaneController.Lit = false; // ※ボールが箱から離れたら数字表示板を消灯する 32 } 33 } 34 35 private void Start() 36 { 37 if (this.OnEnterNumber == null) 38 { 39 this.OnEnterNumber = new NumberBoxEvent(); 40 } 41 if (this.numberPaneController == null) 42 { 43 this.numberPaneController = this.GetComponentInChildren<NumberPaneController>(); 44 } 45 this.numberPaneController.CharacterIndex = 46 NumberPaneController.GetIndexForCharacter(string.IsNullOrEmpty(this.Character) ? ' ' : this.Character[0]); 47 this.numberPaneController.Lit = false; 48 } 49 50 private void Update() 51 { 52 } 53}
ゲートのスクリプト
C#
1using UnityEngine; 2 3[RequireComponent(typeof(Animator))] 4public class GateController : MonoBehaviour 5{ 6 private const float BlinkingInterval = 0.5f; // ※Accepted、Deniedの時の数字表示点滅間隔 7 public NumberPaneController[] NumberPaneControllers; // ※ゲート前面にある4枚の数字表示板、インスペクタ上で割り当てておく 8 public string PasswordString; // パスワード文字列、インスペクタ上で決めておく 9 private Animator animator; // ※ゲート用のアニメーター 10 private string playersAnswer; // 入力されたパスワード候補文字列 11 private float time; // ※数字表示板点滅のための時間格納用変数 12 13 // 箱とボールの衝突発生時に箱で発生するOnEnterNumberに対応して、これを実行するようインスペクタで設定しておく 14 public void EnterDigit(string character) 15 { 16 if (!this.animator.GetCurrentAnimatorStateInfo(0).IsName("WaitingForInput")) 17 { 18 return; // パスワード入力待ち状態以外では何もしない 19 } 20 if (string.IsNullOrEmpty(character)) 21 { 22 return; 23 } 24 25 this.playersAnswer += character; // characterには入力された文字が渡されるので、これをplayersAnswerに連結する 26 Debug.Log("Password : " + this.playersAnswer); 27 this.UpdateDisplay(); // ※playersAnswerを書き換えたので、ゲート前面の数字表示板を更新する 28 if (this.playersAnswer.Length >= this.PasswordString.Length) 29 { 30 if (this.playersAnswer == this.PasswordString) 31 { 32 Debug.Log("Accepted!"); 33 this.animator.SetTrigger("PasswordAccepted"); // ※パスワードが正しければAccepted状態に遷移、その後アニメーターによって自動的にゲートを開くモーションに遷移する 34 } 35 else 36 { 37 Debug.Log("Denied!"); 38 this.animator.SetTrigger("PasswordDenied"); // ※パスワードが間違っていればDenied状態に遷移、その後アニメーターによって自動的にパスワード入力待ちに戻る 39 } 40 this.playersAnswer = ""; 41 } 42 } 43 44 // ※ゲート前面数字板表示を一斉に変えるためのメソッド...アニメーター上のステートにStateMachineBehaviourが仕掛けてあり、そこで使用している 45 public void ResetDisplay(string character) 46 { 47 this.time = 0.0f; 48 if (character == null) 49 { 50 this.UpdateDisplay(); 51 } 52 else 53 { 54 var paneCount = this.NumberPaneControllers.Length; 55 var characterIndex = NumberPaneController.GetIndexForCharacter(character[0]); 56 for (var i = 0; i < paneCount; i++) 57 { 58 var pane = this.NumberPaneControllers[i]; 59 if (pane == null) 60 { 61 continue; 62 } 63 64 pane.CharacterIndex = characterIndex; 65 } 66 } 67 } 68 69 // ※ゲート前面数字板の点灯状態を変えるためのメソッド...Accepted・Denied時の点滅エフェクト用 70 private void InvertLit() 71 { 72 var paneCount = this.NumberPaneControllers.Length; 73 for (var i = 0; i < paneCount; i++) 74 { 75 var pane = this.NumberPaneControllers[i]; 76 if (pane == null) 77 { 78 continue; 79 } 80 81 pane.Lit = !pane.Lit; 82 } 83 } 84 85 private void Start() 86 { 87 this.animator = this.GetComponent<Animator>(); 88 this.playersAnswer = ""; 89 this.UpdateDisplay(); 90 } 91 92 private void Update() 93 { 94 var stateInfo = this.animator.GetCurrentAnimatorStateInfo(0); 95 if (stateInfo.IsName("Denied") || stateInfo.IsName("Accepted")) 96 { 97 // ※Accepted・Deniedの時は数字表示板を点滅させて目立たせる 98 this.time += Time.deltaTime; 99 if (this.time > BlinkingInterval) 100 { 101 this.time -= BlinkingInterval; 102 this.InvertLit(); 103 } 104 } 105 } 106 107 // ※現在のplayersAnswerに合わせて数字板の表示を切り替えるメソッド 108 private void UpdateDisplay() 109 { 110 var paneCount = this.NumberPaneControllers.Length; 111 var answerLength = string.IsNullOrEmpty(this.playersAnswer) ? 0 : this.playersAnswer.Length; 112 for (var i = 0; i < paneCount; i++) 113 { 114 var pane = this.NumberPaneControllers[i]; 115 if (pane == null) 116 { 117 continue; 118 } 119 120 pane.CharacterIndex = 121 NumberPaneController.GetIndexForCharacter(i < answerLength ? this.playersAnswer[i] : '?'); 122 pane.Lit = false; 123 } 124 } 125}
投稿2017/07/11 18:22
編集2017/07/14 15:20総合スコア10807
0
数字表示板はQuadに文字のテクスチャを貼り付けたもので、それにNumberPaneControllerをアタッチしております。
数字表示板スクリプト
C#
1using System; 2using UnityEngine; 3 4[RequireComponent(typeof(MeshFilter), typeof(Renderer))] 5public class NumberPaneController : MonoBehaviour 6{ 7 private const int CellsPerRow = 8; 8 private const int LitStateOffset = 2; 9 private const int Row = 4; 10 private static readonly Vector2 CellSize = new Vector2(1.0f / CellsPerRow, 1.0f / Row); 11 12 private static readonly char[] Characters = 13 { 14 ' ', 15 '?', 16 'v', 17 'x', 18 '0', 19 '1', 20 '2', 21 '3', 22 '4', 23 '5', 24 '6', 25 '7', 26 '8', 27 '9' 28 }; 29 30 // 表示するべき文字を表すインデックス 31 // 当初の予定では、表示をアニメーションクリップ上で操作しようとしたため、intではなくfloatになっています 32 // アニメーションクリップからの操作はできたのですが、別の不具合が発生してこの方式は中止しました 33 public float CharacterIndex; 34 35 // 点灯状態を表すブール値 36 public bool Lit; 37 38 private float currentCharacterIndex; 39 private bool currentLit; 40 private bool inited; 41 private Material material; 42 43 // 文字からインデックスを求めるために用意したメソッド 44 public static int GetIndexForCharacter(char character) 45 { 46 return Math.Max(Array.IndexOf(Characters, character), 0); 47 } 48 49 // マテリアルのmainTextureOffsetをCharacterIndexに応じた位置にずらして見た目を変えるメソッド 50 public void UpdateMaterial() 51 { 52 if (this.inited) 53 { 54 var index = Math.Min(Math.Max(Mathf.RoundToInt(this.CharacterIndex), 0), Characters.Length - 1); 55 var u = index % CellsPerRow; 56 var v = (Row - 1 - (index / CellsPerRow)) + (this.Lit ? LitStateOffset : 0); 57 this.material.mainTextureOffset = new Vector2(u * CellSize.x, v * CellSize.y); 58 this.currentCharacterIndex = this.CharacterIndex; 59 this.currentLit = this.Lit; 60 } 61 } 62 63 // Start内でUV座標を1文字分の大きさに小さくした四角形メッシュを作り、元々のQuadメッシュと差し替える 64 private void Start() 65 { 66 this.material = this.GetComponent<Renderer>().material; 67 var meshFilter = this.GetComponent<MeshFilter>(); 68 var mesh = new Mesh(); 69 meshFilter.mesh = mesh; 70 var vertices = new[] 71 { 72 new Vector3(-0.5f, -0.5f, 0.0f), 73 new Vector3(0.5f, -0.5f, 0.0f), 74 new Vector3(-0.5f, 0.5f, 0.0f), 75 new Vector3(0.5f, 0.5f, 0.0f) 76 }; 77 var triangles = new[] {0, 2, 1, 3, 1, 2}; 78 var normals = new[] 79 { 80 new Vector3(0.0f, 0.0f, 1.0f), 81 new Vector3(0.0f, 0.0f, 1.0f), 82 new Vector3(0.0f, 0.0f, 1.0f), 83 new Vector3(0.0f, 0.0f, 1.0f) 84 }; 85 var uv = new[] 86 { 87 new Vector2(0.0f, 0.0f), 88 new Vector2(CellSize.x, 0.0f), 89 new Vector2(0.0f, CellSize.y), 90 CellSize 91 }; 92 mesh.vertices = vertices; 93 mesh.triangles = triangles; 94 mesh.normals = normals; 95 mesh.uv = uv; 96 this.inited = true; 97 this.UpdateMaterial(); 98 } 99 100 // Update内でCharacterIndexやLitに変化があったかチェックし、変化があればUpdateMaterialで表示を更新する 101 private void Update() 102 { 103 if ((this.currentCharacterIndex != this.CharacterIndex) || (this.currentLit != this.Lit)) 104 { 105 this.UpdateMaterial(); 106 } 107 } 108}
この数字表示板が箱の上面やゲート扉の前面に仕込んであります。
投稿2017/07/19 11:34
総合スコア10807
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/07/20 12:35
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/07/12 02:55
2017/07/12 04:52
2017/07/19 06:43
2017/07/19 10:34