まずは参考記事を載せておきます。
次に、それを配置して効果を実現します。
理由をお話しますと、今回のプロジェクトでこのエフェクトを使う必要があったので、ネットで参考記事を見つけたのですが、後になって、なぜうまくいかないのかわからなかったので、何が問題なのか自分で変更してみようと思いました。
元のコードを投稿します。
//ZoomObj是需要缩放的UI
private void ZoomImgByMousePos(GameObject ZoomObj)
{
//判断鼠标滚轮是否滚动
if (Input.GetAxis("Mouse ScrollWheel") == 0)
return;
//一些变量的声明
RectTransform RectTran = ZoomObj.GetComponent<RectTransform>();
float PivotX = RectTran.pivot.x;
float PivotY = RectTran.pivot.y;
float OffsetX = 0f;
float OffsetY = 0f;
Vector2 addOffset;
//获取轴心点在屏幕的坐标
previewPosition = Camera.main.WorldToScreenPoint(RectTran.position);
//获取鼠标坐标
newPosition = Input.mousePosition;
//计算偏差值
addOffset = newPosition - previewPosition;
//计算轴心点偏移量
if (RectTran.rect.width != 0 && ZoomObj.transform.localScale.x != 0)
OffsetX = addOffset.x / RectTran.rect.width / RectTran.localScale.x;
if (RectTran.rect.height != 0 && ZoomObj.transform.localScale.y != 0)
OffsetY = addOffset.y / RectTran.rect.height / RectTran.localScale.y;
//计算轴心点新值
RectTran.pivot += new Vector2(OffsetX, OffsetY);
//计算UI新位置
RectTran.anchoredPosition += addOffset;
//放大UI
if (Input.GetAxis("Mouse ScrollWheel") > 0)
ZoomObj.transform.localScale += (ZoomObj.transform.localScale.x >= MaxScale - 0.1f ? Vector3.zero : Vector3.one * 0.1f);
else if (Input.GetAxis("Mouse ScrollWheel") < 0)
ZoomObj.transform.localScale += (ZoomObj.transform.localScale.x < MinScale + 0.1f ? Vector3.zero : Vector3.one * -0.1f);
}
元の記事と比較すると、いくつかのバグや実装原則など、いくつかの変更が加えられていることがわかります。実は元の記事がよく理解できず、説明が省略されすぎていて、数学オタクでUnity初心者の私が泣いてしまいました。
キーコードの内容を説明しますと、まずスクリプトクラス内でいくつかの変数に値を代入する必要がありますので、ご自身で修正してください。
画面上のピボットポイントの座標を取得します
//获取轴心点在屏幕的坐标
previewPosition = Camera.main.WorldToScreenPoint(RectTran.position);
UIのワールド座標を画面座標に変換すると、UIのピボットポイントがワールド座標のどこにあるかのように見えますが、ピボットポイントが画面から出ることがないので、安全に変換して変換することができます。値を取得します。
先頭に配置しているのは、後で UI を拡大縮小したときにピボット ポイントが移動するためです。このオフセットは、UI スケーリング コード ブロックが終了しても変更されません。遅延が発生します。最後に配置すると、変更された値がキャプチャされない可能性があります。
偏差値の計算
//计算偏差值
addOffset = newPosition - previewPosition;
ピボットポイントのマウス位置と画面位置の差を計算します
ピボット ポイントのオフセットを計算する
//计算轴心点偏移量
if (RectTran.rect.width != 0 && ZoomObj.transform.localScale.x != 0)
OffsetX = addOffset.x / RectTran.rect.width / RectTran.localScale.x;
if (RectTran.rect.height != 0 && ZoomObj.transform.localScale.y != 0)
OffsetY = addOffset.y / RectTran.rect.height / RectTran.localScale.y;
スケーリング後の UI ピボット ポイントのオフセット距離は、オフセット値によって計算されます。デフォルトではピボット ポイントの位置がマウスと同じ位置にあるため、このオフセット距離はマウスの位置に基づきます。画面座標の単位距離はアンカー座標系の単位距離と同じであるため、オフセット値を拡大した UI の幅と高さで直接除算してピボット ポイントのオフセット距離を求めることができます。
ピボットポイントの位置を計算する
//计算轴心点新值
RectTran.pivot += new Vector2(OffsetX, OffsetY);
ピボットポイントをマウスの位置に移動します
UIの位置を計算する
//计算UI新位置
RectTran.anchoredPosition += addOffset;
UI の位置にはオフセット値を追加する必要があります。この位置はローカル座標またはアンカー座標です。UIのピボットポイントの移動に伴いUIの位置も移動するようです。追加しない場合、スケーリング後に UI が所定の座標から一定の距離だけオフセットされることがわかりますが、このマルチオフセット距離が上記で計算されたオフセット値になります。具体的なロジックは明確ではありませんが、Unity の最下層で設定する必要があります。
2023/2/11 更新履歴
新しいプロジェクトではこの機能を使用する必要があるため、自分のプロジェクトをコピーするときにバグが見つかることがあり、すぐに腹が立って一晩かけて比較とトラブルシューティングを行って問題を見つけました。
- UI をスケーリングする必要がある Transform コンポーネントの Pivot の初期値は 0.5 と 0.5 である必要があります。
- UI をスケーリングする Transform コンポーネントのアンカー プリセットは中央のものである必要があります
設定は次のとおりです。
2023/6/9 更新履歴
コメントで友人が問題を抱えていたので、UIにあまり詳しくない人もいるのではないかと少し思ったのと、どのような状況でこのコードが使用されているかを明確に説明していなかったので、追記したいと思います。若干。
このコードは Scroll View コンポーネントで使用されます。Scroll View は X 軸と Y 軸をロックできません。(下図のように設定します)
コード内の ZoomObj は通常、Scroll View の Content オブジェクトを指します。
要約する
- コード内の ZoomObj は通常、Scroll View の Content オブジェクトを指します。
- UI をスケーリングする必要がある Transform コンポーネント (コンテンツ) の Pivot の初期値は 0.5 と 0.5 である必要があります
- UI をスケーリングする Transform コンポーネントのアンカー プリセットは中央のものである必要があります
恥ずかしながら、この記事には初版があり、考えられる問題点をいくつか挙げてみましたが、一転して罠にはまってしまいました。最初のバージョンでは、画面サイズと UI サイズが同じだったので、運次第で目的の効果が得られましたが、実際には UI サイズを変更すると、何か問題が発生します。その後、さらに数時間かけてバグを修正し、この記事を改訂しました。このバージョンの内容は正しいはずです。
実際、この効果は十分ではありません。カードが 1 枚ずつ出てくるように感じます。実際、スクロール ホイールの値を減らし、コルーチン ループを使用して数回ズームすることで同じ効果を達成することで改善できます。これで改善されると思います。もちろん、より多くの設定が必要になります。でも、私はめんどくさいので、自分で最適化するのは皆さんにお任せします。
コードを見ただけでは理解するのは難しいので、自分で試したり、場所を変えたりして効果を確認することをお勧めします。Unity2D プロジェクトに取り組んでいる場合は、遅かれ早かれこの問題に遭遇するでしょう。早めに理解することで、Unity コンポーネントへの理解が深まるでしょう。とにかく、私はそれをしませんでした。
Unity にスケーリング機能が組み込まれていれば最高ですが、なぜそうしないのでしょうか?
最後に、この記事が困っている友達を助けることができれば幸いです。そして皆さんの幸運を祈ります。