質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Q&A

解決済

2回答

3872閲覧

Unity5.6 パスワード入力実装について

y_unity

総合スコア39

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

0グッド

0クリップ

投稿2017/07/11 10:55

Unity5.6を使用しています。

4桁のパスワード機能を実装しようと思っております。
GUIは完成して、あとはプログラムのところなのですが
わからいない点が何点かあり、質問させていただきます。

□プログラム概要
Sphere(プレイヤー)をハンドセンサーでトラッキングさせ
cube(0~9までの数字オブジェクト)に衝突すると
各々の数字の値をintする仕様です。

□質問内容
例えばパスワードを"6443"に設定する方法
およびcubeとの衝突判定でどのように変数を追加していくのか
6,4,4,3の順番で衝突判定を行うと合計で17になる為
(衝突判定の回数で制御?変数を4桁分用意する?)

恐れ入りますが、ご査収の程よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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
Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_unity

2017/07/12 02:55

ご回答ありがとうございます。 大変参考になりました。 恐れ入りますが、これを衝突判定で行う場合どのように書けばよろしいでしょうか?ご査収の程よろしくお願い致します。
Bongo

2017/07/12 04:52

方針としては「if (!string.IsNullOrEmpty(digit) &&...」の{}内でやっていることを、衝突イベントハンドラ(OnCollisionEnter)内で行う感じでどうでしょう。 各数字キューブにはキューブの表す数字が入った変数を持たせて(キューブのゲームオブジェクトの名前で区別してもいいかもしれません)、衝突時にその数を上のコードの「digit[0]」の代わりに連結してやればいいかと思います。 あいにく今はUnityをいじれるいとまがないのですが、余裕があれば後で衝突入力版も実験してみたいですね。
y_unity

2017/07/19 06:43

追記ありがとうございます! 大変参考になります。 実装致しましたらエラーになってしまいました。。。 NumberPaneContrpllerが見つかりませんとなります。 恐れ入りますが、ご確認の程よろしくお願い致します。
Bongo

2017/07/19 10:34

NumberPaneControllerは数字表示板の制御のために別途用意したスクリプトで、本題とは直接関係ないと思い載せなかったのです... のちほど別回答としてお出しします(この回答に追記ですと少々長くなりすぎかと思ったため)。
guest

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

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_unity

2017/07/20 09:34

すいません、どうしても実装出来ないので プロジェクトファイルを頂くことはできませんでしょうか。 図々しいお願いですが、よろしくお願い致します。
Bongo

2017/07/20 12:35

http://fast-uploader.com/file/7056108958843/にアップロードしました。ダウンロード用パスワードは「3456」です。 正直作り込みが甘く、人様にお見せするのは恥ずかしい代物ですが、実験的なものということでご勘弁ください。 先にも申し上げましたが、回答に提示しました部分以外は見た目に関するものがほとんどですし、また、操作もハンドセンサーではなくマウスによるものですので、ご質問者さんのプロジェクトに直接応用可能な部分は少ないかと思いますが、ご参考になりましたらさいわいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問