20210901のUnityに関する記事は5件です。

【Unityメモ】The script don't inherit a native class that can manage a script.

Unity上で新しい C#スクリプトを作成し、オブジェクトにアタッチしようとしたら以下のエラーが出た。 The script don't inherit a native class that can manage a script. 調べると、スクリプト名とクラス名が一致していないことが原因とわかったが、何度確認しても二つが一致している。 Hoge.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class Hoge : MonoBehaviour { private void Start() { Debug.Log("Start"); } } スクリプトの作り直しやアタッチし直しをしても治らず。 結果、全く別のスクリプトのエラー(セミコロンつけ忘れ)が原因だった。 エラーを読んでも修正箇所がわからなかったのでメモ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】レイヤーを使わずに衝突判定をなくす方法【Physics】

Physics.IgnoreCollisionhttps://t.co/0vViTb5uJ0public static void IgnoreCollision ( Collider collider1, Collider collider2, bool ignore=true);>2 つのコライダーの衝突判定を無効化しますレイヤーとコリジョンマトリックスの設定なしでCollider単位で衝突制御できるのでは!??— su10@ハイパーカジュアルゲーム開発 (@su10_dev) September 1, 2021 はじめに Unityを使った開発でチームの人数が増えるとレイヤーがカオス化しがちです。 具体的には以下のような問題が発生したりします。 レイヤーが無秩序に追加されて枯渇する カスタムレイヤーは24個しか追加できない! コリジョンマトリックスの衝突する・しないがいつの間にか変更されていて既存の実装が壊れる しかも原因が追いにくい ある程度大きな規模の開発ならルールを作ったり安全な仕組みを作って対応するところですが、小規模開発だとそもそも可能な限りレイヤー使わないほうが良くない?と思ってます。 いろいろ調べていたら少なくとも衝突判定をなくす方法についてはレイヤーを使わずに済む方法を見つけたのでご紹介します。 Physics.IgnoreCollision Physics.IgnoreCollision public static void IgnoreCollision (Collider collider1, Collider collider2, bool ignore= true); 2つのコライダーの衝突判定を無効化します Physics2D.IgnoreCollision public static void IgnoreCollision (Collider2D collider1, Collider2D collider2, bool ignore= true); collider1 と collider2 のペア間の衝突/トリガーを検知するか無視するようにします Collider を2つとフラグを受け取って衝突判定を無効化。良さそう。 試してみた Default レイヤーに設定してあるオブジェクト2つ(Cube と Floor)に対してAPIを呼んでみました。 using UnityEngine; public class CollisionSwitcher : MonoBehaviour { [SerializeField] private Collider _colA; [SerializeField] private Collider _colB; public bool ignoreCollision; private bool _ignoreCollisionCache; void Start() { _ignoreCollisionCache = ignoreCollision; } void Update() { if (_ignoreCollisionCache != ignoreCollision) { Physics.IgnoreCollision(_colA, _colB, ignoreCollision); _ignoreCollisionCache = ignoreCollision; } } } ちなみにレイヤーとコリジョンマトリックスの設定で最初から衝突しないようにしてある場合は Physics.IgnoreCollision() を呼んでも衝突するようにはできませんでした。 あくまで「衝突させないようにする、もしくは元通り衝突するように戻す」専用。 APIの制限 リファレンスにいろいろ書いてあるので載せておきます。 Physics.IgnoreCollision This is useful, say, for preventing projectiles from colliding with the object that fires them. Note that IgnoreCollision will reset the trigger state of affected colliders, so you might receive OnTriggerExit and OnTriggerEnter messages in response to calling this. IgnoreCollision has a few limitations: 1) It is not persistent. This means ignore collision state will not be stored in the editor when saving a Scene. 2) 有効なゲームオブジェクトにしか IgnoreCollision を適用できません。 Physics2D.IgnoreCollision 選択されたコライダー間のいかなる衝突判定も無視します。つまり、すべての衝突判定とトリガー判定が起こらなくなります。まず最初に衝突レイヤーで2つのレイヤーが接触できるか確認し、その後接触が起こらないようにします。それらの処理の次に、特定のコライダーが作用しないようにします。 IgnoreCollision にはいくつかの制約があります: 1) It is not persistent. This means that the ignore collision state will not be stored in the editor when saving a Scene. 2) You can only apply the ignore collision to colliders in active game objects. When deactivating the collider the IgnoreCollision state will be lost and you have to call Physics2D.IgnoreCollision again. あとがき 小規模開発だとそもそもレイヤー使わないほうが良くない?と思ってます。 こうは書いたものの、カメラで写す対象を絞るとかはどうしてもレイヤーを使う必要があったりして、現実的には使う必要が出てくると思います。 コリジョンマトリックスは実行時に動的に変更できるみたいなので、Unityの素のレイヤーの上に一つ抽象レイヤー(層)を作ってシーンごとに衝突判定を切り替えたりすることは可能そうです。鋭意調査中
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】ActionとUnityEventについて

Action Actionとは、他のクラスの関数をいくつも受け取って、一斉に実行できる参照型です。 Action を使って依存関係を逆転すれば、再利用しやすいクラスが作れます。 例として、OnTriggerEnter が呼ばれたら、他のクラスから受け取った関数を実行するクラスを紹介します。 OnTriggerEnterEvent.cs using UnityEngine; using System; public class OnTriggerEnterEvent : MonoBehaviour { [SerializeField] public event Action<Collider> Action; private void OnTriggerEnter(Collider other) { // Action が持っている各関数の引数に other を代入して、各関数を実行 Action.Invoke(other); } } OnTriggerEnterEvent の Action に関数を渡すときは、下記のように記述します。 DebugLog.cs using UnityEngine; public class DebugLog: MonoBehaviour { [SerializeField] OnTriggerEnterEvent onTriggerEnter; private void Start() { // Action に View 関数を渡す(引数が一致している必要がある) onTriggerEnter.Action += View; } private void View(Collider collider) { Debug.Log(collider.name); } } 上記の関数を実行すると、衝突したコライダーの名前がコンソールに表示されるようになります。 補足 Action から View 関数を除外するときは「onTriggerEnter.Action -= View;」のように書きます。 Action に関数が渡されていない状態で Invoke を呼ぶとエラーになります。Action が空の状態で Invoke を呼ぶかもしれない場合は「if (action != null) aciton.Invoke();」のようにNullチェックしましょう。 Action の宣言の前についている event を取ると、他のクラスからも Invoke を呼べるようになるので注意して下さい。 UnityEvent UnityEventとは Action と同様、他のクラスの関数をいくつも受け取って、一斉に実行できる参照型です。 Action より遅いですが、コンポーネント上から関数を渡せます。 OnTriggerEnterEvent を UnityEvent で実装すると、下記のようになります。 OnTriggerEnterEvent.cs using UnityEngine; using UnityEngine.Events; public class OnTriggerEnterEvent : MonoBehaviour { [SerializeField] UnityEvent<Collider> Event; private void OnTriggerEnter(Collider other) { // Event が受け取った各関数の引数に other を代入して、各関数を実行 Event.Invoke(other); } } 上記のコンポーネントをゲームオブジェクトに追加すると、Event(Collider) と書かれた枠が出現します。 コンポーネント上で UnityEvent に関数を渡すには、 枠の右下の + ボタンを押す 枠の左下の None(Object) にゲームオブジェクトを割り当てる 枠の右上の No Function と書かれたプルダウンメニューから関数を選択 と操作します。これで、OnTriggerEnter が呼ばれたタイミングで選択した関数が実行されます。 補足 関数の引数が1つだけの場合に限り、インスペクタ上で自由な値を代入できます(関数の引数が一致している必要もありません)。 関数の引数が2つ以上の場合は、スクリプトから関数を追加するか、引数が全て一致する関数を指定する必要があります。 プルダウンメニューに関数が出てこない場合は、関数が public になっているか、戻り値が void になっているかを確認して下さい。 スクリプトから関数を渡す例.cs using UnityEngine; public class DebugLog : MonoBehaviour { [SerializeField] OnTriggerEnterEvent onTriggerEnter; private void Awake() { // Event に View 関数を渡す(引数が一致している必要がある) onTriggerEnter.Event.AddListener(View); } private void View(Collider collider) { Debug.Log(collider.name); } } ラムダ式 ラムダ式とは、使い捨ての関数を作れる便利な機能です。 ラムダ式を使えば、1つ目のコードを2つ目のコードのように、簡潔に書き換えられます。 1つ目のコード.cs private void Awake() { onTriggerEnter.Event.AddListener(View); } private void View(Collider collider) { Debug.Log(collider.name); } 2つ目のコード.cs private void Awake() { onTriggerEnter.Event.AddListener((collider) => { Debug.Log(collider.name); }); } コードが一行なら、中括弧とセミコロンを省略できます。 onTriggerEnter.Event.AddListener((collider) => Debug.Log(collider.name)); 引数が一つなら、括弧も省略できます。 onTriggerEnter.Event.AddListener(collider => Debug.Log(collider.name));
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity:オブジェクトの動きの設定とprefabのclone作成

Unity備忘録 Objectの移動 void Move() { transform.position += new Vector3(0, 4.5f, 0) * Time.deltaTime; } 上記スクリプトでy軸方向に一定速度でオブジェクトが移動する。 void Move() { float x = Input.GetAxis("Horizontal"); float y = Input.GetAxis("Vertical"); transform.position += new Vector3(x, y, 0) * Time.deltaTime * 4f; } 方向指示キーでオブジェクトを動かす場合、Input.GetAxisをnew Vector3の中で受け取る。 Prefabのクローニング void Clone() { if (Input.GetKeyDown(KeyCode.Space)) { Instantiate(Prefab, PrefabPoint.position, PrefabPoint.rotation); } } 取得したPrefub Objectをスペースキーが押されるときにInstantiateで呼び出す場合、上記のように記載。呼び出す場所の位置(position)と回転(rotation)も指定する必要がある。 実装 プレイヤーを方向指示キーで動かし、玉の発射の実装。慣れると、10分ぐらいで実装可能。Unity C#は慣れるとわかりやすい言語だな再認識。#スタジオしまづ https://t.co/8QWBZ399xV pic.twitter.com/iwM6WmCnMr— Unity勉強中の整形外科医:北城雅照|医療者向けプログラミングスクール「もいせん」開校! (@teru3_kitashiro) September 1, 2021 実際の動きと、書いたスクリプト PlayerShip.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerShip : MonoBehaviour { public GameObject BulletPrefab; public Transform FirePoint; // Update is called once per frame void Update() { Move(); Shot(); } void Move() { float x = Input.GetAxis("Horizontal"); float y = Input.GetAxis("Vertical"); transform.position += new Vector3(x, y, 0) * Time.deltaTime * 4f; } void Shot() { if (Input.GetKeyDown(KeyCode.Space)) { Instantiate(BulletPrefab, FirePoint.position, FirePoint.rotation); } } } Bullet.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class Bullet : MonoBehaviour { // Update is called once per frame void Update() { ShotMove(); } void ShotMove() { transform.position += new Vector3(0, 4.5f, 0) * Time.deltaTime; } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】簡単にレンダリングの品質を上げる方法

Post Processing に標準搭載されているエフェクトの品質を簡単に上げる方法です。 標準エフェクトの品質には満足してるけど、あとほんのちょっとだけ、似たようなエフェクトを再開発すせずにプロジェクト特有の問題に対処したい、という時に。 望遠だと出てくる PP Stack v2 Ambient Occlusion の同心円状のモアレ消したい pic.twitter.com/jhSRXYrxQz— サトー (@sator_imaging) August 12, 2021 もくじ はじめに 簡単に直せるのに直せない問題 正攻法で直すには もっと簡単に直す方法 おわりに はじめに Post-Processing で Ambient Occlusion の Multi-Scale Volumetric Obscurance を適用した際、カメラのレンズが 100mm を超えた辺りから ↑ に示した画像のように同心円状のモアレ、ノイズが出てしまうという問題にぶつかりました。@ Post-Processing v2.3.0 これはオクルージョンのアルゴリズムを見直せば解決できる、とか深刻なモノではなく、デプスの値をほんのちょっと弄るだけで簡単に直せる問題です。が、それが簡単なのに簡単ではないというのが問題です。 簡単に直せるのに直せない問題 修正は非常に簡単で、MultiScaleVO.shader というシェーダーにちょっとデプスをごにょる1行を加えるだけです。 そして、これは望遠レンズで撮った時に限った問題なので、このプロジェクト以外では不要なモノ、ワンオフでサクッと修正したい。ところが、、、 // 0 - Depth copy with procedural draw Pass { HLSLPROGRAM #pragma vertex VertDefault #pragma fragment Frag float4 Frag(VaryingsDefault i) : SV_Target { float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoordStereo); // ↓ ↓ ↓ 追加 ↓ ↓ ↓ d += sin(i.texcoordStereo.x * _ScreenParams.x * 2.1414) * cos(i.texcoordStereo.y * _ScreenParams.y * 2.524) * 0.00000075 * min(1, d * 100000); // ↑ ↑ ↑ 追加 ↑ ↑ ↑ return d; } ENDHLSL } ※ パフォーマンスは多少落ちるけど問題ない。他では使わないし。 正攻法で直すには これを Post-Processing のお作法に則ってプロジェクトに適用するのは非常に面倒です。 下記の通り Post-Processing には独自のエフェクトを追加する方法が用意されていますが、 Writing Custom Effects | Post Processing | 2.3.0 マニュアルにあるのはあくまで新規にエフェクトを書き起こす為の方法であり、既存のエフェクトを微調整する方法は示されていません。 -- それなら、と Packages/ 以下のファイルを直接修正すると、Unity を再起動するたびに元の状態に戻ってしまいます。 なので、Ambient Occlusion 関係のスクリプト/シェーダーを複製して調整版エフェクトの追加を試みると、、、 internal アクセスレベルなモノがあったりするので Ambient Occlusion 以外のファイルもコピー・リネームが必要。 どんどんコピー・リネームが必要なファイルが増えていく。 結局全部コピー・リネームが必要っぽい。 Packages/ から Assets/ に移せば internal も見える、けど今風じゃない。 という、非常に面倒な感じです。新たなエフェクトを作りたいのではなく、ほんのちょっとだけ手を加えたいだけなのにかなりの大事。途中でイヤになってやめました。 もっと簡単に直す方法 幸いなことに Post-Processing Stack v2 に標準搭載のエフェクトで使用されるシェーダーは PostProcessResources.asset に参照の形でまとめられていたので、コチラを書き換えることで面倒なことをせずとも調整版エフェクトへの差し替えが行えます。 このアセットファイルもスクリプト/シェーダーと同様、Unity を再起動するたびに元の状態に戻るので InitializeOnLoadMethod で起動のたびに書き換えるスクリプトを用意してやります。 MonoBehaviour からランタイム中に書き換えても動作するようなので、シーンごと、負荷ごとにシェーダーの切り替えも出来そうです。 -- これで公式パッケージの恩恵を受けつつ、プロジェクトに合わせた微調整が簡単に行えるようになりました。 ありきたりのポストエフェクトを再開発するような無駄を省きつつ、プロジェクト特有の問題に対処できる。イイ感じですね。 using UnityEngine; using UnityEditor; using UnityEngine.Rendering.PostProcessing; public static class ReplacePostProcessingShader { const string SHADER_NAME = "Hidden/Path/to/Customized/Version/of/MultiScaleVO"; [InitializeOnLoadMethod] static void Init() { var GUIDs = AssetDatabase.FindAssets(nameof(PostProcessResources)); foreach(var id in GUIDs) { var path = AssetDatabase.GUIDToAssetPath(id); if (AssetDatabase.GetMainAssetTypeAtPath(path) != typeof(PostProcessResources)) continue; Debug.Log($"GUID: {id} ({path})"); var asset = AssetDatabase.LoadMainAssetAtPath(path) as PostProcessResources; var shader = Shader.Find(SHADER_NAME); if (null == asset || null == shader) continue; asset.shaders.multiScaleAO = shader; } } } おわりに 対象が球体だから特にエラーが目立つだけ、人型キャラにちゃんとテクスチャが載ってれば目立たない(目立ちにくい)、望遠レンズを使わなければ問題なし、という特殊な事例です。 ↓ 人型だったり周波数の高いテクスチャが貼られていれば目立ちにくい Post-Processing の出力にもパフォーマンスにも不満はないけど、処理を追加したり省いたり、ほんの少しだけプロジェクト向けに調整を加えたい! という時に使える手法じゃないでしょうか。 以上です。お疲れ様でした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む