スタジオしまづさんの1Wゲームジャムへ作品を出展しました😆
皿割りシューティングです。
今まで学んできた要素を詰め込めるだけ詰め込んでみました。
InputSystem でキーボードでもマウスでもコントローラーでも遊べるようにできました。
ちょっと操作しづらいけどスマホでも遊べちゃいます。
皿を割った時に出る時の得点表示は、最後まで苦労したところ。
何せ、今まで3DでUIを使ったことがなくて、座標をどういうふうにしたら良いのか分からない。
nekojara.city
を参考にやってみたけれど、なぜかUIの座標が桁違いな値になってしまう。
ちょうど、今週の水曜が、しまづさんのオンライン講義だったので、教えを請い、なんとか完成させました😁
仕組みは、こんな感じです。
まず、皿のスクリプトに皿が割れた時のメソッドBrokenPlateを用意して、そこでスコア表示のUIを作成しています。
public class PlateManager : MonoBehaviour { public void BrokenPlate() { int angle =Random.Range(0,240); //割れた皿のオブジェクトを生成。 //このとき、回転と破裂力をランダムにして、割れ方の違いを演出しています。 Transform brokenPlate = Instantiate(brokenPrefab,transform.position,Quaternion.Euler(new Vector3(angle,270,90))); brokenPlate.localScale=transform.localScale; foreach (Rigidbody rigi in brokenPlate.GetComponentsInChildren<Rigidbody>()) { int force=Random.Range(30,120); rigi.AddExplosionForce(force,transform.position,3f); } GameManager.Instance.AddScore(score); GameManager.Instance.Clash(); //ここで皿のワールド座標をスクリーン座標に変換。 var targetScreenPos=Camera.main.WorldToScreenPoint(transform.position); //スクリーン座標にスコア表示用のUIを仮作成 GameObject ui=Instantiate(uiPrefab,targetScreenPos, Quaternion.identity, _Canvas.transform); //スクリーン座標をUI座標?に変換。 RectTransformUtility.ScreenPointToLocalPointInRectangle( _Canvas.GetComponent<RectTransform>(), targetScreenPos, Camera.main, out var uilocalPos); //その位置に仮作成しておいたUIの座標を変更 ui.transform.localPosition=uilocalPos; //皿の色を取得 var co=transform.GetComponent<Renderer>().material.color; //皿の設定メソッドに皿の得点と色を引数で渡してやる。 ui.GetComponent<PointUI>().SetParam(co,score); //皿を消す Destroy(gameObject); } }
ポイントはCanvasのレンダーモード。
自分の場合は「スクリーンスペース-カメラ」ですが、ここが変わる場合、先ほどのRectTransformUtilityの引数が変わる感じです。
僕はこれが理解できずに延々と悩みました😅
UI側のスクリプトはこんな感じです。
using UnityEngine; using UnityEngine.UI; public class PointUI : MonoBehaviour { private float _displaytime = 0.7f; //消えるまでの時間です。 private float _timer; private Text _txt; private Vector3 pos; private void Awake() { _txt = GetComponent<Text>(); pos = transform.position; } void Update() { _timer += Time.deltaTime; if (_timer > _displaytime) Destroy(gameObject); //時間以上になったら消す transform.localScale=new Vector3(_timer*5f,_timer*5f,_timer*5f);// pos.y += 2f*Time.deltaTime; //時間まで毎フレーム、localscaleをあげてます。 } public void SetParam(Vector4 _color,int value) { _txt.color = new Color(_color.x, _color.y, _color.z, _color.w); _txt.text = value.ToString(); } }
こんな感じです〜😁