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

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

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

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

321閲覧

自作ゲームにおいてプレイヤーキャラクターが特定の場所に来ると移動できなくなるのを改善したい

MujinSekai

総合スコア18

C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2017/09/04 08:53

編集2017/09/04 16:09

###自作ゲームにてプレイヤーキャラクターが移動できなくなるのを改善したい
十字キーを押下するとプレイヤーキャラクターが1ユニット移動するようにしていたのですが、エネミーの上に移動すると以後移動できなくなりました。他の三方向は問題ありません。下の画像のとおりRaycastHit2Dで当り判定を行っています。

移動不可時の画像
###発生している問題
上記の画像のとおりエネミーの上の位置にくると以後移動できなくなります(わかりにくいですが……)。ただ向く方向を変えることは出来ます。正直どこに問題があるのか分からない状態で、関係あるスクリプトがどれかも迷っています。なので最も怪しい部分を載せます。

###該当のソースコード

C#

1 UserInput userInput; 2 public GameObject questObject; 3 private Quest _quest; 4 5 public GameObject gameManagerObject; 6 GameManager gameManager; 7 8 protected Animator animator; 9 private float _directionX; 10 private float _directionY; 11 private bool walking; 12 13 public GameObject childRightCheck; 14 public GameObject childLeftCheck; 15 public GameObject childFrontCheck; 16 public GameObject childBackCheck; 17 18 RaycastHit2D rightCheck; 19 RaycastHit2D leftCheck; 20 RaycastHit2D frontCheck; 21 RaycastHit2D backCheck; 22 23 public LayerMask BlockingLayer; 24 25 void Update() 26 { 27 rightCheck = Physics2D.Linecast (transform.position, childRightCheck.transform.position, BlockingLayer); 28 leftCheck = Physics2D.Linecast (transform.position, childLeftCheck.transform.position, BlockingLayer); 29 frontCheck = Physics2D.Linecast (transform.position, childFrontCheck.transform.position, BlockingLayer); 30 backCheck = Physics2D.Linecast (transform.position, childBackCheck.transform.position, BlockingLayer); 31 32 if (animator) { 33 34 35 walking = true; 36 37 if (userInput.horizontalInput > 0){ // 右 38 _directionX = 1; 39 _directionY = 0; 40 41 } else if (userInput.horizontalInput < 0){ // 左 42 _directionX = -1; 43 _directionY = 0; 44 45 } else if (userInput.verticalInput < 0){ // 下 46 _directionX = 0; 47 _directionY = -1; 48 49 } else if (userInput.verticalInput > 0){ // 上 50 _directionX = 0; 51 _directionY = 1; 52 53 } else{ 54 walking = false; 55 } 56 if (walking) { 57 58 if (gameManager.encounterFlag == false) { 59 60 transform.Translate (new Vector3 (_directionX, _directionY, 0)); 61 62 } else if (gameManager.encounterFlag == true){ 63 //if 64 /* ((!rightCheck && Input.GetKeyDown (KeyCode.RightArrow)) 65 || (!leftCheck && Input.GetKeyDown (KeyCode.LeftArrow)) 66 || (!frontCheck && Input.GetKeyDown (KeyCode.DownArrow)) 67 || (!backCheck && Input.GetKeyDown (KeyCode.UpArrow))) 68 {*/ここの条件式が怪しい(特にfrontCheck) 69//------------------------------------------------------------------------------------------------------------------------ 70 /*(!(_directionX == 1 && _directionY == 0 && rightCheck) 71 && !(_directionX == -1 && _directionY == 0 && leftCheck) 72 && !(_directionX == 0 && _directionY == -1 && frontCheck) 73 && !(_directionX == 0 && _directionY == 1 && backCheck)) 74 && (Input.GetKeyDown (KeyCode.UpArrow) || 75 Input.GetKeyDown (KeyCode.DownArrow) || 76 Input.GetKeyDown (KeyCode.RightArrow) || 77 Input.GetKeyDown (KeyCode.LeftArrow))*/ 78//------------------------------------------------------------------------------------------------------------------------ 79 80 81 transform.Translate (new Vector3 (_directionX, _directionY, 0)); // 移動できる 82 //} 83 } 84 } 85 86 animator.SetFloat ("DirectionX", _directionX); 87 animator.SetFloat ("DirectionY", _directionY); 88 animator.SetBool ("Walking", walking); 89 } 90 }

###試したこと
起こっている現象から、frontCheckに問題があるのだと思い該当部分をコメントアウトしてみたのですが、結果は変わりませんでした。
条件式を変えてみたり、frontCheckの中身を調べてみたりしたのですが結局改善されないまま現在に至っています。
問題点の心当たりなどありましたらお教え頂きたいです。

###補足情報(言語/FW/ツール等のバージョンなど)
C#
Unity2017.2.0b8

###追記

C#

1// 怪しいと思った箇所をこのようにしました。 2if ((!rightCheck & Input.GetKeyUp (KeyCode.RightArrow)) 3 | (!leftCheck & Input.GetKeyUp (KeyCode.LeftArrow)) 4 | (!frontCheck & Input.GetKeyUp (KeyCode.DownArrow)) 5 | (!backCheck & Input.GetKeyUp (KeyCode.UpArrow))) 6{ 7 if(frontCheck) 8 Debug.Log ("frontCheckがtrueです"); 9 10 transform.Translate (new Vector3 (directionX, directionY, 0)); 11}

実はGetKeyDownの時は矢印キーを2つ同時に押さないと移動できなかったのです(理由はわかりません)が、GetKeyUpにすると意図どおりの挙動になりました。
ただ上記のコードにある"frontCheckがtrueです"がfrontCheckがエネミーに重なった場合表示されるはずが重なっても表示しませんでした。しかし移動は出来ない状態です。trueではないにもかかわらず移動が出来ず、しかも!frontCheckをコメントアウトするとエネミーの上の箇所でも移動できます(下矢印キーを何度も押すとすり抜けます)。また、frontCheckに意図していない代入を行っているのかと思い、探してみましたがみつかりませんでした。

###閲覧して頂きありがとうございます

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

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

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

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

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

sakura_hana

2017/09/05 01:18

userInput.〜InputとInput.GetKey〜は同じ意味合いと考えていいのでしょうか? もしそうなら、_directionX、_directionY、〜Checkのみの条件分岐とすることが出来ます。一旦全ての条件文をこちらで書き直して整理してもらえますか?
MujinSekai

2017/09/05 02:57 編集

userInputはhorizontalInput = Input.GetAxisRaw ("Horizontal");とverticalInput = Input.GetAxisRaw ("Vertical");になります。GetKey〜と使い分けているのは押しっぱなしで移動できる場合と一度の入力で1ユニット移動させる処理をゲーム上、作りたかったからです。おっしゃられたように一旦全ての条件文を書き直して実行してみましたが、やはり同じ現象が起きてしまいます。また、Debug.Log ("frontCheckがtrueです");ですが、frontCheckがエネミーに重なった場合ではなく、!frontCheckをコメントアウトし、下に(エネミーと重なりながら)ユニット移動したタイミングでtrueになりました。更新のタイミングの問題でしょうか?
guest

回答1

0

ベストアンサー

押しっぱなしで移動できる場合と一度の入力で1ユニット移動させる処理をゲーム上、作りたかったからです。

こうしたいなら、キー入力自体は毎フレーム取得(userInput.〜Inputに統一)、別途フラグを用意してキー入力処理を実行するタイミングを制御すべきです。
(フラグがfalseの時入力があった→移動処理開始、フラグはtrueに→移動処理完了後フラグをfalseに、という流れ)
Input.GetKeyDownを使うと今度は「押しっぱなしで移動」が作れなくなるかと思います。

Input.GetKeyUpにすると動いた。

ということは、キーが押されたフレーム(Input.GetKeyDown)ではwalkingがfalseになっている可能性があります。
また、本来であればキーを離したフレームではwalkingはfalseになるはずなので、ここが呼ばれるはずがありません。
そうでないということは、恐らくこのクラスとUserInputで少なくとも1フレーム分、入力のズレが発生しているのではないかと思います。

frontCheckがエネミーに重なった場合ではなく、!frontCheckをコメントアウトし、下に(エネミーと重なりながら)ユニット移動したタイミングでtrueになりました。

walkingがtrueの時にしかこの条件分岐に入って来ないので、キーを離していたら呼ばれません。

投稿2017/09/05 04:48

sakura_hana

総合スコア11427

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

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

MujinSekai

2017/09/05 05:41 編集

回答ありがとうございます。 お教え頂いたとおりUserInputに入力を統一しようと思います。ただ恥ずかしながら例えばInput.GetKeyUp (KeyCode.UpArrow)をUpdate()内に記述します。ここからが分からないのですが、UserInput以外の入力があったかを条件式でつかっているスクリプトで使用する場合Input.GetKeyUp (KeyCode.UpArrow)をUserInputのpublic変数に代入すると思うのですが、その際のクラス名がわかりません(Inputでしょうか)。もしかしたら(というかたぶん)的はずれな事を聞いているのかもしれませんが、その際は指摘して頂けるとありがたいです。 追記) 例えば以下のように記述するのでしょうか? public float horizontalInput; public float verticalInput; public Input upArrowInput; void Update () { horizontalInput = Input.GetAxisRaw ("Horizontal"); verticalInput = Input.GetAxisRaw ("Vertical"); upArrowInput = Input.GetKeyUp (KeyCode.UpArrow); }
sakura_hana

2017/09/05 05:49 編集

「UserInput以外の入力があったかを条件式でつかっているスクリプトで使用する場合Input.GetKeyUp (KeyCode.UpArrow)をUserInputのpublic変数に代入する」の意味がよく分かりません。 基本的には追記のコードで問題無いと思いますが、UserInputを複数のクラスから呼び出す場合、同様の問題が発生する可能性があります。 これは「複数スクリプトにおけるUpdateの実行順は不透明」である為で、 スクリプトA→ UserInput→スクリプトB のような順番で呼ばれた場合、 「スクリプトAでは未入力なのに、スクリプトBでは入力されている」みたいなことが起こります。 詳しくは以下をご覧ください。 http://tsubakit1.hateblo.jp/entry/2017/02/05/003714
MujinSekai

2017/09/06 03:59

せっかく回答して頂いたのに返答が遅れて申し訳ありません。 現在、無闇矢鱈に様々なクラスのUpdate()に書いていた処理をまとめる作業をしております。表題と少しずれてしまいますが、これをしないとこの問題を解決したとしても同じようなことが起きてしまうと思っております。理想(目標)はUpdate()を一つ以下(おそらくUserInput)にし、更新が必要な処理はメソッド化しメインループに入れる事になると思います。このやり方があっているか調べてみましたが確証は無く、非常に不安です。徒労に終わる可能性が高いような気がします。もしよろしければ、このような場合に参考になるサイトや書籍をご存知でしたら、お教えいただけないでしょうか?
sakura_hana

2017/09/06 05:19

実際、そこまでシビアになる必要があるのか?というのを考えるべきかと思います。 というか1フレームの誤差を気にしない処理であれば、一本化する必要はありません。 参考資料としては、まずは公式リファレンスですかね。 https://docs.unity3d.com/jp/530/Manual/ExecutionOrder.html あとは「Unity update」でコツコツ検索かと。
MujinSekai

2017/09/06 07:32 編集

実はターン制を考えておりまして、参考にさせて頂いているソースコードがUserInput.csでUpdate()を使っているだけで他はほぼ使用していないのです。ですから分かりやすい気がして自分もそのようにしようと思っていたのですが、一般的に異なるものなのでしょうか?onelinerrogue(https://github.com/pigeon6/onelinerrogue-src) うまくいくか定かでは無いまま下記のようにしようとしていました。 メインループメソッド { While(ゲーム中かどうかのフラグ) { —ターンの開始— ターン数インクリメント 通常時UserInputメソッド
 エンカウントメソッド(encounterFlag = true)
 while(encounterFlag){ abstractActor配列の生成 UserInput(); Foreah(abstracrtActor配列) { エンカウント時UserInputメソッド
 Actorの行動 敵Actorがフィールドからいなくなったら encounterFlagをfalseに } abstractActor配列の削除 } —ターンの終了— } }
MujinSekai

2017/09/07 04:26

いずれにしても表題の問題点と解決法を提示して頂いたので、この質問を終了させたいと思います。ターン制やUpdate()をまとめる事などはまた別の質問にさせて頂くかもしれません。何度も回答して頂きありがとうございます。
sakura_hana

2017/09/07 04:48

私はかなり我流でして、一般的かどうかという質問の回答をするには不安が残りますので、仰る通り別の質問としてもらった方が的確な回答が付くかと思います。 トライアンドエラーもよい勉強になると思います。こちらもお付き合いありがとうございました。
MujinSekai

2017/09/07 18:44

追記と言うか蛇足というか……。 原因が判明したのでコメント致します。 ・FrontCheckだけがtrueになっているのではなく(他の三方向も含めて四方向全て)trueになっていました。どうやらLinecastのオブジェクトの位置と(プレイヤーとエネミーの)BoxCollider2Dのoffsetの位置とspriteのpivotの位置が悪く、四方向のLinecastの判定に複数引っかかっていたようです。上記とAnimatorとAnimationを改善すると意図どおりの挙動になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問