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

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

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

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

Q&A

解決済

1回答

1268閲覧

Unityでの画面スワイプの実装と、ウィンドウサイズ取得方法

Matsuri_

総合スコア15

C#

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

0グッド

0クリップ

投稿2022/08/09 14:14

前提

Unityでスマホアプリを作っています。
画面を横にスワイプして切り替える機能を実装しようとしています。
使用コードはこちらhttps://www.youtube.com/watch?v=rjFgThTjLso
(Swaiping Pages In Unity)を参照しています。

以下は画面のスクリーンショットです。
Canvas設定は、
Render Mode : ScreenSpace-Camera
UI Scale Mode : Scale with ScreenSize
にしています。使い慣れているから、という理由です。
スクリプトはPanelConというオブジェクトに付与しています。

イメージ説明

赤→青→緑とスワイプしたいと思っています。

発生している問題

上記のCanvas設定だと、上記のコードSwaiping Pages In Unityを使っても
スワイプ動作が早すぎるなど、うまくいきませんでした。
そのため、自分でわかる範囲で変更を加えました。
(変更後が以下のコードです。)
スワイプ自体はするようになりました。

ただ、どうしてもわからない部分が、
一ページ分だけ、綺麗にスワイプさせる動作の実装です。
中段あたりにある
newLocation += new Vector3(-Screen.width, 0, 0);
のコードですが、
Screen.widthを使ってスワイプすると、
PanelConというパネルがだいぶ遠くに飛んでしまい、
何も見えない状態になってしまいます。

該当のソースコード

PanelCon

1public class Swipeeasier : MonoBehaviour, IDragHandler, IEndDragHandler 2{ 3 public RectTransform canvas; 4 private Vector3 panelLocation; 5 public float percentThreshold = 0.2f; 6 7 // Start is called before the first frame update 8 void Start() 9 { 10 panelLocation = transform.position; 11 } 12 public void OnDrag(PointerEventData data) 13 { 14 float difference = data.pressPosition.x - data.position.x; 15 //transform.position = (panelLocation - new Vector3(difference, 0, 0)) * 0.01f; 16 transform.position += 17 (panelLocation - new Vector3(difference, 0, 0))*0.0006f; 18 19 } 20 public void OnEndDrag(PointerEventData data) 21 { 22 float percentage = (data.pressPosition.x - data.position.x) / Screen.width; 23 Debug.Log(Screen.width); 24 if(Mathf.Abs(percentage) >= percentThreshold) 25 { 26 Vector3 newLocation = panelLocation; 27 if(percentage > 0) 28 { 29 newLocation += new Vector3(-Screen.width, 0, 0); 30 } 31 else if(percentage < 0) 32 { 33 newLocation += new Vector3(Screen.width, 0, 0); 34 } 35 transform.position = newLocation; 36 panelLocation = newLocation; 37 }else 38 { 39 transform.position = panelLocation; 40 } 41 42 } 43 44} 45

試したこと

new Vector3のあとの、Screen.widthの部分をほかの数字に変えてみて、どう映るか確認してみました。
小さい数字にすると、画面にページの色は映るのですが、
画面が中途半端にスクロールされてしまいます。

イメージ説明

例えば、上記のようになります。

動画見本とCanvas設定が違うのでうまくいかないのかもしれませんが、
できればこのままの設定で解決できないかなあと思っています。
もしお分かりの方いらっしゃれば、
よろしくお願いいたします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

実機の解像度とCanvasの解像度に乖離があれば、設定されているCanvas設定ではスクリーン座標系の単位とワールド座標系の単位が違ってきてしまいますね。
なので、x座標計算する時にScreenToWorldPointで補正してみては如何でしょう?
OnDrag時にdataから得た座標はスクリーン座標系になってるから、それをScreenToWorldPointで変換してから計算すると上手く行くような気がします。

投稿2022/08/09 16:02

編集2022/08/09 17:55
drednote

総合スコア336

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

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

Matsuri_

2022/08/10 15:00 編集

ありがとうございます。 解決するかどうか、試してみたいと思います。 OnDragのメソッドなのですが、ここの中身を自分で付け加えています。 なぜかというと、ドラッグ&ドロップしてページをスワイプし、 ふたたびドラッグしようとすると、最初の赤いページに飛んでしまう現象があったからです。 (元のコードの前には//を置いて無効にしています。) 上手なやり方がわからなかったので、とりあえずこう書いたという感じです。
drednote

2022/08/10 16:40

>ふたたびドラッグしようとすると、最初の赤いページに飛んでしまう現象があったからです。 これに関して、元ソースではOnEndDragでpanelLocationにドラッグ結果の座標を新しい元の座標として保存することで対応していた訳です。 (つまり、OnDragでは元座標+差分座標の形でスクロールさせ、OnEndDragで差分座標を元座標に足し込んで元座標を更新している) とりあえず元ソースではスクリーン座標系とワールド座標系の単位合わせを行っていなかったので、そのずれが今回出てきているので、スクリーン座標系をワールド座標系に変換して操作してやれば上手く行くようになると思います
Matsuri_

2022/08/10 17:49 編集

ありがとうございます。 ちょっと直してみて、パネルが飛んで行ってしまうことはなくなりました。 赤いページに飛んでしまうこともありません。 ただ、一つ問題があります。 スワイプして画面を切り替えようとすると、ちょうど半分くらいで止まってしまいます。 例えば、赤から青のページに行こうとしてスワイプすると、 左半分が赤、右半分が青みたいになります。 もう一回スワイプすると、ちゃんと青い画面になります。 下記コードの、 newLocation += new Vector3(-ScreenWorldSize.x, 0, 0); において、このScreenWorldSizeに問題があると思っています。 これはScreen.Widthをワールド座標に変えたものです。 以下は修正後のコード全文です。 public class Swipeeasier : MonoBehaviour, IDragHandler, IEndDragHandler { public RectTransform canvas; private Vector3 panelLocation; public float percentThreshold = 0.2f; Vector2 Press; Vector2 AfterDrag; // Start is called before the first frame update void Start() { panelLocation = transform.position; } public void OnDrag(PointerEventData data) { Press = Camera.main.ScreenToWorldPoint(data.pressPosition); AfterDrag = Camera.main.ScreenToWorldPoint(data.position); float difference = Press.x - AfterDrag.x; transform.position = (panelLocation - new Vector3(difference, 0, 0))*1f; } public void OnEndDrag(PointerEventData data) { Vector2 ScreenWorldSize = Camera.main.ScreenToWorldPoint(new Vector2 (Screen.width, Screen.height)); float percentage = (Press.x - AfterDrag.x) / ScreenWorldSize.x; if(Mathf.Abs(percentage) >= percentThreshold) { Vector3 newLocation = panelLocation; if(percentage > 0) { newLocation += new Vector3(-ScreenWorldSize.x, 0, 0); } else if(percentage < 0) { newLocation += new Vector3(ScreenWorldSize.x, 0, 0); } transform.position = newLocation; panelLocation = newLocation; }else { transform.position = panelLocation; } Debug.Log(percentage); } }
drednote

2022/08/10 19:40

>このScreenWorldSizeに問題があると思っています。 >これはScreen.Widthをワールド座標に変えたものです。 恐らくScreen.widthのワールド座標での範囲を知りたかったのだと思いますが、単純に出た値をそのまま使ってしまうと間違います。 そもそも座標(0,0)の位置がワールド座標とスクリーン座標とで違っていたりするので、Screen.widthをそのままワールド座標にしても座標としての意味は勿論出てきませんし、サイズという意味でも(原点がずれている為)間違った物になります。 ようは、スクリーン座標の(0,0)の位置=ワールド座標の(0,0,0)の位置、と無意識のうちに考えてしまった為に出てくる間違いな訳ですが、widthのワールド座標での大きさを知りたいならスクリーン座標の(0,0)がワールド座標ではどこにあたり、そのX座標とScreenWorldSize.xとの差が正しいScreenWorldSize.x、となると思います。
Matsuri_

2022/08/13 16:38 編集

ありがとうございます。 問題のScreenWorldSizeですが、 下記のようにコードを書きかえると、うまくいきました。 Vector3 ScreenWorldSize = Camera.main.ScreenToWorldPoint(new Vector3 (Screen.width, Screen.height,0)); Vector3にして、カメラの距離を0に指定しました。 なぜVector2ではだめだったのか、その原因まではわかっていませんが、 座標の勉強になりました。 drednote様、大変ご丁寧に教えてくださり、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問