The Evolution of Multi-Group:


Art, Games, and Inspirations

1.Introduction:

    Hi! I’m Tomohiro Okazaki, also known as Multi-Group. Here’s a bit about how I started my creative journey and what keeps me inspired. Back in university, I was involved in art projects, creating works like the “Okazaki Machine” — a conveyor belt that carried 10,000 tiny wire sculptures of a figure I called “Little Old Man.(tittyaiottyan)”

      Later, I moved into web design, video production, and a variety of other creative work. It was rewarding, but I barely had time to sleep, and after about ten years, I needed a break.


      2.How I Started:

      After my health declined, I took a ten-year break. When I felt better, I knew I wanted to dive back into something artistic. Joining a company didn’t suit me, so I decided to focus on something I could do on my own.

        That’s how I started making video games in the spring of 2024. I found Unity and saw that I could potentially make mobile games solo, so I created a small game titled “Catch Nama.”

        App Storeからダウンロード
        App Storeからダウンロード
        Google Playで手に入れよう
        Google Playで手に入れよう

        On November 11, we successfully released the second installment, ‘NamaNama.’ It’s turned out really well, so make sure to download it and give it a try!

        App Storeからダウンロード
        App Storeからダウンロード
        Google Playで手に入れよう
        Google Playで手に入れよう

        3.Inspirations:

        I’m essentially built from video games and manga. I was born the same year as the Famicom.

          so games like “MOTHER”, “UNDERTALE”, “ARMORED CORE”, “Factorio”, “CHRONO TRIGGER”, and “moon” are close to my heart. In manga, there’s “Dragon Ball”, “Yu Yu Hakusho”, and so many others that it’s hard to list them all.

          Akira Toriyama is an absolute legend! In music, I enjoy the works of composers like Yasunori Mitsuda, who scored some of my favorite games, and jazz pianists like Thelonious Monk. I don’t limit myself to any genre; I genuinely enjoy sounds of all kinds — even the natural sounds I hear in cities and mountains.


          4.Links to Streaming Platforms:

          I regularly live-stream my game development process on YouTube and Twitch. Feel free to stop by and check it out!

            X (Twitter): https://x.com/multiGroupOka
            YouTube: https://www.youtube.com/@Multi-Group
            Twitch: https://www.twitch.tv/multigroupoka
            Email: okazakitomohirowork@gmail.com


            5.Message to Young Artists:

            Originality is everything. I believe that copying something just because it’s popular or profitable misses the point entirely. Think of Van Gogh, who sold very few works in his lifetime but left a lasting legacy.

              When I started Multi-Group, I came up with the phrase, “Minor Resistance – Major Misconception.” No matter how hard we try, our actions are just small in the grand scheme of things, and others might even see them as grand illusions. But that’s okay. That’s the way it should be.

              Unityで作ったゲームをiPhoneで再生すると、音が小さくなる問題

              がんばってXcodeで書き出したゲームやアプリをアイフォンでテストしてみたら、なんか異様に音が小さかったことありませんか。私はありました。なぜかAndroidでは問題がないのです。それが中々手強かった...以下直し方です。

              Prepare iOS for Recordingのチェックボックスをオフにする

              これだけです。場所はUnity > Project Settings > Player > iOS > Other Settings > Configuration > Prepare iOS for Recording 中央あたりにあります。


              マイク録音 API を初期化するには、このオプションを有効にします。これにより、録音の遅延は少なくなります (iPhone ではオーディオ出力の再ルーティングはイヤホン経由でのみですが)。

              要するに、iPhoneを電話として使う時に音小さいですよね。あれになってるとのことです。私は音声のラウドネスを上げて書き出し直したり、とにかく試しましたが直らなくて大変でした。以下私が試してみてダメだったこと一覧です。この方法で直る人もいるかも。

              1. 音量設定の確認:

              UnityのAudio Mixer: Audio Mixerを使用している場合、マスターボリュームや各グループのボリュームが適切に設定されているか確認してください。特に、iOSプラットフォーム向けの設定が正しいかどうかを確認します。

              2. AudioSourceの設定:

              AudioSourceコンポーネント: 各AudioSourceの音量設定を確認し、必要に応じて調整します。特に、音量が0.5未満になっている場合は、デフォルト値を1に設定してください。

              3. iOS固有の音量調整 :

              音量倍率の見直し: IOS_VOLUME_MULTIPLIER を2倍にしていますが、これが適切かどうか再評価してください。通常、iOSデバイスの音量は1.0〜1.5倍程度で十分なことが多いです。

              private const float IOS_VOLUME_MULTIPLIER = 2f; // iOSデバイスでの音量倍率
              
              private void ApplyVolume(float value)
              {
              
              #if UNITY_IOS
              	value *= IOS_VOLUME_MULTIPLIER; // iOSデバイスでは音量を2倍に
              #endif
              
              	BGMManager.Instance.ChangeBaseVolume(value);
              	SEManager.Instance.ChangeBaseVolume(value);
              }

              4. オーディオファイルの形式:

              オーディオファイルの最適化: 使用しているオーディオファイルが適切な形式(例:.wav, .mp3)であるか確認し、必要に応じて再エンコードします。また、ビットレートやサンプリングレートも影響することがあります。

              5. デバイス設定の確認:

              iPhoneの音量設定: デバイス自体の音量設定(サウンド設定)やミュートスイッチがオフになっているか確認してください。また、アプリ内で音量が適切に反映されているかもチェックします。

              6. テストとフィードバック:

              異なるデバイスでテスト: 他のiOSデバイスでも同様の問題が発生するかどうか確認し、特定のモデルに問題があるかどうかを特定します。

              Unity Community でも色々みつかりました。

              皆様のお役に立てます様に。

              perplexityのサイトの右カラムを消す

              個人的に一番使いやすいAIのperplexity。とにかく問題解決能力に優れてる。キレイなコードではないかもしれないけど、それは解決してからキレイに書き直せばいい。他のAIの感想載せとく。

              • Gemini:いらん提案をしてくるくせに、コードを書いてくれない
              • ChatGPT:良くも悪くも普通。コードを全文載せてくれるけど、その自ら提案したコードをコピペしてもう一度聞くと、ここがダメ、あれがダメ、と永遠に終わらない
              • Claude:困ったときの最終手段。賢いけど、無料じゃ何回も使えない

              ということで本題。perplexityサイトでは右によくわからない、他のWebから取ってきた情報が表示されるけど、今回はこれを消す。

              1. Stylusをインストール
                Chromeの機能拡張でcssをいじれるものがある。
              1. perplexityページを開いて以下のコードを入力。
              /* 右カラムを消す */
              .col-span-4.isolate {
                  display: none !important;
                  position: absolute !important;
                  width: 0 !important;
                  height: 0 !important;
                  margin: 0 !important;
                  padding: 0 !important;
                  overflow: hidden !important;
                  clip-path: none;
                  white-space: nowrap !important;
                  border: 0 !important;
              }
              
              /* その分広げる */
              .col-span-8 {
                  grid-column: span 12 / span 12;
              }
              
              /* 入力欄を伸ばす */
              .grow {
                  min-width: 800px !important;
              }
              1. 完成

              ご使用は自己責任で。

              UnityでiOS用にビルドする方法

              作ったゲームをiOSで遊べるようにAppStoreに並べるためには、macを使ってXcodeで書き出す必要があります。今回で二回目だが、はじめてやった時同様、苦戦したので議事録として残しておきます。

              基本的には上記の記事が参考になります。丁寧に図付きで説明されてるので、ひっかかることなく進めると思います。

              以前「なまつか」をリリースしたときには、問題なく行えました。が、今回macOS Sequoia(セコイア)15.0.1にアップデートしたらできなくなりました。今回、私がつまずいた所を抜粋します。


              macOSのアプリ、キーチェーンアクセスを起動します。

              キーチェーンアプリの起動場所がアプリケーションから変更になりました。

              キーチェーンアクセス

              キーチェーンアクセスは従来のアプリケーション>ユーティリティじゃなくて、CoreServices>アプリケーションに移動してます。spotlightで検索すればすぐ出てきます。


              Provisioning Profileをダブルクリックすると、自動でmacのキーチェーンに登録

              「Download」を押し、Linble_Keyboard.mobileprovisionをダウンロードします。ダウンロードした.mobileprovisionファイルをダブルクリックすると、自動でmacのキーチェーンに登録してくれます。

              ダブルクリックしたらXcodeが開いてしまい、キーチェーンに登録できません。仕方がないのでドラッグして登録しようとするも、エラーになります。

              ネットには色々な登録方法がみつかりますが、私は次の方法が一番分かりやすかったです。(しかしこれを行ったからBuildが成功したかどうか正直微妙です。)

              Provisioning ProfileをXcodeに設定します。まずは適当な場所にダウンロードしておきます。

              023.png

              Provisioning Profileダウンロード

              ダウンロードしたらSigning & Capabilitiesの設定でAutomatically manage Signingのチェックを外します。

              Provisioning Profileのプルダウンが選択できるので、先ほどダウンロードしたファイルを指定します。


              Xcodeで開くファイル

              Unity-iPhone.xcworkspace と Unity-iPhone.xcodeproj ふたつあるのですが、Unity-iPhone.xcworkspace が正解です。こちらは広告等のデータが入っています。iPhone.xcworkspaceがない場合はUnity-iPhone.xcodeprojでOK。


              毎回言語設定をするのが面倒

              UnityでBuildしてから、Xcodeで開いてそのまま書き出すと、言語が英語になります。面倒なので、Unity側で自動で設定してしまいましょう。

              上記サイトに従って、設定すればOK。成功するとUnityでBuildしただけで自動的に日本語になります。


              Xcodeで開いたらここだけ変更してBuildしましょう

              Unity-iPhone の Signing & CapabilitiesタブでTeamを変更すればOK。Provisioning Profileが正しく設定されていれば、ここだけ変更してBuildすると成功します。

              App Store用に書き出すにはProduct > Archive から書き出せます。

              書き出したら、成功しているかチェック(Validate)してからアップロードすればOK。

              この画面になればOK。あとはApp Store Connectにアクセスしてアプリから目的のアプリを選べばOK。反映するまで数分かかりますが、ビルドの横に+ボタンが出来てるはず。


              プライバシーの設定

              こちらのサイトが参考になります。


              おつかれさまでした。いっしょにがんばっていきましょい。

              カメラ移動スクリプト

              1.直接的な位置の更新:

              using UnityEngine;
              using UnityEngine.EventSystems;
              using System.Collections.Generic;
              
              [RequireComponent(typeof(Camera))]
              public class SceneViewCamera_1 : MonoBehaviour
              {
              	[SerializeField] private float pinchSpeed;
              	[SerializeField] private float dragThreshold;
              
              	private Vector2 touchStartPos;
              	private float initialFingersDistance;
              	private Vector3 initialCameraPosition;
              	private bool isPinching = false;
              	private int? activeTouchId = null;
              	private bool canMoveCamera = false;
              
              	private Camera mainCamera;
              	private Transform cameraTransform;
              
              	private RaycastHit[] raycastHitCache = new RaycastHit[1];
              	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();
              
              	private void Start()
              	{
              		mainCamera = Camera.main;
              		cameraTransform = transform;
              	}
              
              	private void Update()
              	{
              		TouchUpdate();
              	}
              
              	private void TouchUpdate()
              	{
              		if (Input.touchCount == 1)
              		{
              			HandleSingleTouch(Input.GetTouch(0));
              		}
              		else if (Input.touchCount == 2)
              		{
              			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
              		}
              		else
              		{
              			ResetTouchState();
              		}
              	}
              
              	private void HandleSingleTouch(Touch touch)
              	{
              		switch (touch.phase)
              		{
              			case TouchPhase.Began:
              				if (!activeTouchId.HasValue)
              				{
              					activeTouchId = touch.fingerId;
              					touchStartPos = touch.position;
              					touchPositions[touch.fingerId] = touch.position;
              					canMoveCamera = CheckIfCanMoveCamera(touch.position);
              					Debug.Log($"Touch began: canMoveCamera = {canMoveCamera}");
              				}
              				break;
              
              			case TouchPhase.Moved:
              				if (activeTouchId == touch.fingerId && canMoveCamera)
              				{
              					float dragDistance = Vector2.Distance(touchStartPos, touch.position);
              					Debug.Log($"Drag distance: {dragDistance}");
              					if (dragDistance > dragThreshold)
              					{
              						TouchDrag(touch.position);
              						Debug.Log("Camera moved");
              					}
              				}
              				break;
              
              			case TouchPhase.Ended:
              			case TouchPhase.Canceled:
              				if (activeTouchId == touch.fingerId)
              				{
              					ResetTouchState();
              				}
              				break;
              		}
              	}
              
              	private void HandlePinch(Touch touch1, Touch touch2)
              	{
              		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
              		{
              			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			initialCameraPosition = cameraTransform.position;
              			isPinching = true;
              		}
              		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
              		{
              			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			float scaleFactor = initialFingersDistance / currentFingersDistance;
              			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
              			cameraTransform.position = newPosition;
              		}
              		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
              		{
              			isPinching = false;
              		}
              	}
              
              	private bool CheckIfCanMoveCamera(Vector2 touchPos)
              	{
              		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;
              
              		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
              		{
              			return touchedObject.CompareTag("Ground");
              		}
              		return false;
              	}
              
              	private void TouchDrag(Vector2 touchPos)
              	{
              		if (!canMoveCamera) return;
              
              		Vector2 diff = touchPos - touchStartPos;
              		Vector3 worldSpaceDiff = mainCamera.ScreenToViewportPoint(new Vector3(diff.x, diff.y, 0)) - mainCamera.ScreenToViewportPoint(Vector3.zero);
              		worldSpaceDiff.z = 0; // z軸の移動を無視
              
              		// カメラの右方向と上方向のベクトルを取得
              		Vector3 cameraRight = cameraTransform.right;
              		Vector3 cameraUp = cameraTransform.up;
              
              		// 移動量を計算(x軸とy軸を反転)
              		Vector3 movement = (-worldSpaceDiff.x * cameraRight + -worldSpaceDiff.y * cameraUp) * 10f;
              
              		Debug.Log($"Screen diff: {diff}, World space diff: {worldSpaceDiff}, Movement: {movement}");
              
              		// カメラの位置を更新
              		Vector3 newPosition = cameraTransform.position + movement;
              		cameraTransform.position = newPosition;
              
              		touchStartPos = touchPos;
              	}
              
              	private void ResetTouchState()
              	{
              		activeTouchId = null;
              		isPinching = false;
              		touchPositions.Clear();
              		canMoveCamera = false;
              	}
              }

              利点:
              指の動きに正確に追従するため、ユーザーの意図通りの動きを実現できます。
              フレームレートに依存せず、一貫した動きを提供します。
              実装が比較的シンプルで理解しやすいです。
              欠点:
              急激な動きをすると、カメラの動きが不自然に感じる可能性があります。
              高速な動きに対して、カメラが追いつけない場合があります。
              スクリーン座標からワールド座標への変換が必要で、計算コストがやや高くなります。

              2デルタ移動の使用:

              using UnityEngine;
              using UnityEngine.EventSystems;
              using System.Collections.Generic;
              
              [RequireComponent(typeof(Camera))]
              public class SceneViewCamera_2 : MonoBehaviour
              {
              	[SerializeField] private float pinchSpeed;
              	[SerializeField] private float dragThreshold;
              	[SerializeField] private float dragSpeed = 3f; // 新しく追加:ドラッグ速度調整用
              
              	private Vector2 touchStartPos;
              	private float initialFingersDistance;
              	private Vector3 initialCameraPosition;
              	private bool isPinching = false;
              	private int? activeTouchId = null;
              	private bool canMoveCamera = false;
              
              	private Camera mainCamera;
              	private Transform cameraTransform;
              
              	private RaycastHit[] raycastHitCache = new RaycastHit[1];
              	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();
              
              	private void Start()
              	{
              		mainCamera = Camera.main;
              		cameraTransform = transform;
              	}
              
              	private void Update()
              	{
              		TouchUpdate();
              	}
              
              	private void TouchUpdate()
              	{
              		if (Input.touchCount == 1)
              		{
              			HandleSingleTouch(Input.GetTouch(0));
              		}
              		else if (Input.touchCount == 2)
              		{
              			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
              		}
              		else
              		{
              			ResetTouchState();
              		}
              	}
              
              	private void HandleSingleTouch(Touch touch)
              	{
              		switch (touch.phase)
              		{
              			case TouchPhase.Began:
              				if (!activeTouchId.HasValue)
              				{
              					activeTouchId = touch.fingerId;
              					touchStartPos = touch.position;
              					touchPositions[touch.fingerId] = touch.position;
              					canMoveCamera = CheckIfCanMoveCamera(touch.position);
              					Debug.Log($"Touch began: canMoveCamera = {canMoveCamera}");
              				}
              				break;
              
              			case TouchPhase.Moved:
              				if (activeTouchId == touch.fingerId && canMoveCamera)
              				{
              					TouchDrag(touch);
              					Debug.Log("Camera moved");
              				}
              				break;
              
              			case TouchPhase.Ended:
              			case TouchPhase.Canceled:
              				if (activeTouchId == touch.fingerId)
              				{
              					ResetTouchState();
              				}
              				break;
              		}
              	}
              
              	private void HandlePinch(Touch touch1, Touch touch2)
              	{
              		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
              		{
              			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			initialCameraPosition = cameraTransform.position;
              			isPinching = true;
              		}
              		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
              		{
              			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			float scaleFactor = initialFingersDistance / currentFingersDistance;
              			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
              			cameraTransform.position = newPosition;
              		}
              		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
              		{
              			isPinching = false;
              		}
              	}
              
              	private bool CheckIfCanMoveCamera(Vector2 touchPos)
              	{
              		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;
              
              		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
              		{
              			return touchedObject.CompareTag("Ground");
              		}
              		return false;
              	}
              
              	private void TouchDrag(Touch touch)
              	{
              		if (!canMoveCamera) return;
              
              		Vector2 deltaPosition = touch.deltaPosition;
              		Vector3 worldSpaceDelta = mainCamera.ScreenToViewportPoint(new Vector3(deltaPosition.x, deltaPosition.y, 0)) - mainCamera.ScreenToViewportPoint(Vector3.zero);
              		worldSpaceDelta.z = 0; // z軸の移動を無視
              
              		// カメラの右方向と上方向のベクトルを取得
              		Vector3 cameraRight = cameraTransform.right;
              		Vector3 cameraUp = cameraTransform.up;
              
              		// 移動量を計算(x軸とy軸を反転)
              		Vector3 movement = (-worldSpaceDelta.x * cameraRight + -worldSpaceDelta.y * cameraUp) * dragSpeed;
              
              		Debug.Log($"Delta position: {deltaPosition}, World space delta: {worldSpaceDelta}, Movement: {movement}");
              
              		// カメラの位置を更新
              		cameraTransform.position += movement;
              	}
              
              	private void ResetTouchState()
              	{
              		activeTouchId = null;
              		isPinching = false;
              		touchPositions.Clear();
              		canMoveCamera = false;
              	}
              }

              Touch.deltaPositionを使用して、フレーム間の指の動きを直接反映させます。
              利点:
              フレーム間の細かい動きを捉えられるため、滑らかな動きを実現できます。
              Touch.deltaPositionを直接使用するため、計算が比較的シンプルです。
              連続的な動きに対して効果的です。
              欠点:
              フレームレートに依存するため、デバイスによって動きが異なる可能性があります。
              急激な動きに対しては精度が落ちる可能性があります。
              累積誤差が生じる可能性があり、長時間の操作で精度が低下することがあります。

              3ビューポートスペースでの移動:

              using UnityEngine;
              using UnityEngine.EventSystems;
              using System.Collections.Generic;
              
              [RequireComponent(typeof(Camera))]
              public class SceneViewCamera_3 : MonoBehaviour
              {
              	[SerializeField] private float pinchSpeed = 0.1f;
              	[SerializeField] private float dragThreshold = 5f;
              	[SerializeField] private float dragSpeed = 1f;
              
              	private Vector2 touchStartPos;
              	private float initialFingersDistance;
              	private Vector3 initialCameraPosition;
              	private bool isPinching = false;
              	private int? activeTouchId = null;
              	private bool canMoveCamera = false;
              
              	private Camera mainCamera;
              	private Transform cameraTransform;
              
              	private RaycastHit[] raycastHitCache = new RaycastHit[1];
              	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();
              
              	private void Start()
              	{
              		mainCamera = Camera.main;
              		cameraTransform = transform;
              	}
              
              	private void Update()
              	{
              		TouchUpdate();
              	}
              
              	private void TouchUpdate()
              	{
              		if (Input.touchCount == 1)
              		{
              			HandleSingleTouch(Input.GetTouch(0));
              		}
              		else if (Input.touchCount == 2)
              		{
              			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
              		}
              		else
              		{
              			ResetTouchState();
              		}
              	}
              
              	private void HandleSingleTouch(Touch touch)
              	{
              		switch (touch.phase)
              		{
              			case TouchPhase.Began:
              				if (!activeTouchId.HasValue)
              				{
              					activeTouchId = touch.fingerId;
              					touchStartPos = touch.position;
              					touchPositions[touch.fingerId] = touch.position;
              					canMoveCamera = CheckIfCanMoveCamera(touch.position);
              					Debug.Log($"Touch began: canMoveCamera = {canMoveCamera}");
              				}
              				break;
              
              			case TouchPhase.Moved:
              				if (activeTouchId == touch.fingerId && canMoveCamera)
              				{
              					TouchDrag(touch);
              					Debug.Log("Camera moved");
              				}
              				break;
              
              			case TouchPhase.Ended:
              			case TouchPhase.Canceled:
              				if (activeTouchId == touch.fingerId)
              				{
              					ResetTouchState();
              				}
              				break;
              		}
              	}
              
              	private void HandlePinch(Touch touch1, Touch touch2)
              	{
              		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
              		{
              			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			initialCameraPosition = cameraTransform.position;
              			isPinching = true;
              		}
              		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
              		{
              			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			float scaleFactor = initialFingersDistance / currentFingersDistance;
              			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
              			cameraTransform.position = newPosition;
              		}
              		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
              		{
              			isPinching = false;
              		}
              	}
              
              	private bool CheckIfCanMoveCamera(Vector2 touchPos)
              	{
              		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;
              
              		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
              		{
              			return touchedObject.CompareTag("Ground");
              		}
              		return false;
              	}
              
              	private void TouchDrag(Touch touch)
              	{
              		if (!canMoveCamera) return;
              
              		Vector2 viewportDelta = mainCamera.ScreenToViewportPoint(touch.position) - mainCamera.ScreenToViewportPoint(touchStartPos);
              
              		// カメラの右方向と上方向のベクトルを取得
              		Vector3 cameraRight = cameraTransform.right;
              		Vector3 cameraUp = cameraTransform.up;
              
              		// 移動量を計算(x軸とy軸を反転し、y軸の符号を変更)
              		Vector3 move = (-viewportDelta.x * cameraRight - viewportDelta.y * cameraUp) * dragSpeed;
              
              		// カメラの位置を更新
              		cameraTransform.position += move;
              
              		Debug.Log($"Viewport delta: {viewportDelta}, Movement: {move}");
              
              		touchStartPos = touch.position;
              	}
              
              	private void ResetTouchState()
              	{
              		activeTouchId = null;
              		isPinching = false;
              		touchPositions.Clear();
              		canMoveCamera = false;
              	}
              }

              ビューポート座標を使用して、画面サイズに依存しない移動を実現します。
              利点:
              画面サイズに依存しない一貫した動きを提供します。
              異なる解像度のデバイスでも同じ感覚で操作できます。
              スケーリングが容易で、カメラの動きの調整が簡単です。
              欠点:
              ワールド座標系との変換が必要で、やや複雑になる可能性があります。
              3D空間での深度の違いによる見かけの移動速度の差を考慮する必要があります。
              特定のシーン構造に依存する場合、調整が必要になることがあります。

              4補間を使用したスムーズな移動:

              using UnityEngine;
              using UnityEngine.EventSystems;
              using System.Collections.Generic;
              
              [RequireComponent(typeof(Camera))]
              public class SceneViewCamera_4 : MonoBehaviour
              {
              	[SerializeField] private float pinchSpeed = 0.1f;
              	[SerializeField] private float dragThreshold = 5f;
              	[SerializeField] private float dragSpeed = 5f;
              	[SerializeField] private float smoothTime = 0.2f; // スムージング時間
              
              	private Vector2 touchStartPos;
              	private float initialFingersDistance;
              	private Vector3 initialCameraPosition;
              	private bool isPinching = false;
              	private int? activeTouchId = null;
              	private bool canMoveCamera = false;
              
              	private Camera mainCamera;
              	private Transform cameraTransform;
              
              	private RaycastHit[] raycastHitCache = new RaycastHit[1];
              	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();
              
              	private Vector3 targetPosition;
              	private Vector3 velocity = Vector3.zero;
              
              	private void Start()
              	{
              		mainCamera = Camera.main;
              		cameraTransform = transform;
              		targetPosition = cameraTransform.position;
              	}
              
              	private void Update()
              	{
              		TouchUpdate();
              		SmoothCameraMovement();
              	}
              
              	private void TouchUpdate()
              	{
              		if (Input.touchCount == 1)
              		{
              			HandleSingleTouch(Input.GetTouch(0));
              		}
              		else if (Input.touchCount == 2)
              		{
              			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
              		}
              		else
              		{
              			ResetTouchState();
              		}
              	}
              
              	private void HandleSingleTouch(Touch touch)
              	{
              		switch (touch.phase)
              		{
              			case TouchPhase.Began:
              				if (!activeTouchId.HasValue)
              				{
              					activeTouchId = touch.fingerId;
              					touchStartPos = touch.position;
              					touchPositions[touch.fingerId] = touch.position;
              					canMoveCamera = CheckIfCanMoveCamera(touch.position);
              					Debug.Log($"Touch began: canMoveCamera = {canMoveCamera}");
              				}
              				break;
              
              			case TouchPhase.Moved:
              				if (activeTouchId == touch.fingerId && canMoveCamera)
              				{
              					TouchDrag(touch);
              					Debug.Log("Camera moved");
              				}
              				break;
              
              			case TouchPhase.Ended:
              			case TouchPhase.Canceled:
              				if (activeTouchId == touch.fingerId)
              				{
              					ResetTouchState();
              				}
              				break;
              		}
              	}
              
              	private void HandlePinch(Touch touch1, Touch touch2)
              	{
              		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
              		{
              			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			initialCameraPosition = cameraTransform.position;
              			isPinching = true;
              		}
              		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
              		{
              			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			float scaleFactor = initialFingersDistance / currentFingersDistance;
              			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
              			targetPosition = newPosition;
              		}
              		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
              		{
              			isPinching = false;
              		}
              	}
              
              	private bool CheckIfCanMoveCamera(Vector2 touchPos)
              	{
              		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;
              
              		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
              		{
              			return touchedObject.CompareTag("Ground");
              		}
              		return false;
              	}
              
              	private void TouchDrag(Touch touch)
              	{
              		if (!canMoveCamera) return;
              
              		Vector2 viewportDelta = mainCamera.ScreenToViewportPoint(touch.position) - mainCamera.ScreenToViewportPoint(touchStartPos);
              
              		// カメラの右方向と上方向のベクトルを取得
              		Vector3 cameraRight = cameraTransform.right;
              		Vector3 cameraUp = cameraTransform.up;
              
              		// 移動量を計算(x軸とy軸を反転)
              		Vector3 move = (-viewportDelta.x * cameraRight - viewportDelta.y * cameraUp) * dragSpeed;
              
              		targetPosition = cameraTransform.position + move;
              
              		Debug.Log($"Viewport delta: {viewportDelta}, Target movement: {move}");
              
              		touchStartPos = touch.position;
              	}
              
              	private void SmoothCameraMovement()
              	{
              		cameraTransform.position = Vector3.SmoothDamp(cameraTransform.position, targetPosition, ref velocity, smoothTime);
              	}
              
              	private void ResetTouchState()
              	{
              		activeTouchId = null;
              		isPinching = false;
              		touchPositions.Clear();
              		canMoveCamera = false;
              	}
              }

              直接的な移動が急すぎる場合、補間を使用してスムーズな動きを実現できます。
              利点:
              なめらかで自然な動きを実現できます。
              急激な入力に対してもスムーズな反応を示します。
              ユーザー体験を向上させ、より洗練された印象を与えます。
              欠点:
              実際の指の位置とカメラの位置にわずかな遅延が生じます。
              補間パラメータの調整が必要で、適切な値を見つけるのに時間がかかる場合があります。
              計算量がやや増加し、パフォーマンスに影響を与える可能性があります。

              5シンプル移動:

              using UnityEngine;
              using UnityEngine.EventSystems;
              using System.Collections.Generic;
              
              [RequireComponent(typeof(Camera))]
              public class SceneViewCamera_0 : MonoBehaviour
              {
              	[SerializeField] private float moveSpeed = 0.8f;
              	[SerializeField] private float pinchSpeed;
              	[SerializeField] private float dragThreshold;
              
              	private Vector2 touchStartPos;
              	private float initialFingersDistance;
              	private Vector3 initialCameraPosition;
              	private bool isPinching = false;
              	private int? activeTouchId = null;
              	private bool canMoveCamera = false;
              
              	private Camera mainCamera;
              	private Transform cameraTransform;
              
              	private RaycastHit[] raycastHitCache = new RaycastHit[1];
              	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();
              
              	private void Start()
              	{
              		mainCamera = Camera.main;
              		cameraTransform = transform;
              	}
              
              	private void Update()
              	{
              		TouchUpdate();
              	}
              
              	private void TouchUpdate()
              	{
              		if (Input.touchCount == 1)
              		{
              			HandleSingleTouch(Input.GetTouch(0));
              		}
              		else if (Input.touchCount == 2)
              		{
              			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
              		}
              		else
              		{
              			ResetTouchState();
              		}
              	}
              
              	private void HandleSingleTouch(Touch touch)
              	{
              		switch (touch.phase)
              		{
              			case TouchPhase.Began:
              				if (!activeTouchId.HasValue)
              				{
              					activeTouchId = touch.fingerId;
              					touchStartPos = touch.position;
              					touchPositions[touch.fingerId] = touch.position;
              					canMoveCamera = CheckIfCanMoveCamera(touch.position);
              					//Debug.Log($"Touch began: {activeTouchId}, Position: {touch.position}");
              				}
              				break;
              
              			case TouchPhase.Moved:
              				if (activeTouchId == touch.fingerId && canMoveCamera)
              				{
              					float dragDistance = Vector2.Distance(touchStartPos, touch.position);
              					if (dragDistance > dragThreshold)
              					{
              						TouchDrag(touch.position);
              					}
              					//Debug.Log($"Touch moved: {activeTouchId}, Position: {touch.position}, Distance: {dragDistance}");
              				}
              				break;
              
              			case TouchPhase.Stationary:
              				//Debug.Log($"Touch stationary: {activeTouchId}, Position: {touch.position}");
              				break;
              
              			case TouchPhase.Ended:
              			case TouchPhase.Canceled:
              				if (activeTouchId == touch.fingerId)
              				{
              					//Debug.Log($"Touch ended/canceled: {activeTouchId}");
              					ResetTouchState();
              				}
              				break;
              		}
              	}
              
              	private void HandlePinch(Touch touch1, Touch touch2)
              	{
              		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
              		{
              			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			initialCameraPosition = cameraTransform.position;
              			isPinching = true;
              		}
              		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
              		{
              			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			float scaleFactor = initialFingersDistance / currentFingersDistance;
              			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
              			cameraTransform.position = newPosition;
              		}
              		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
              		{
              			isPinching = false;
              		}
              	}
              	private bool CheckIfCanMoveCamera(Vector2 touchPos)
              	{
              		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;
              
              		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
              		{
              			return touchedObject.CompareTag("Ground");
              		}
              		return false;
              	}
              
              	private void TouchDrag(Vector2 touchPos)
              	{
              		if (!canMoveCamera) return;
              
              		Vector2 diff = touchPos - touchStartPos;
              		if (diff.sqrMagnitude >= Vector2.kEpsilonNormalSqrt)
              		{
              			cameraTransform.Translate(-diff * Time.deltaTime * moveSpeed);
              			touchStartPos = touchPos;
              		}
              	}
              
              	private void ResetTouchState()
              	{
              		activeTouchId = null;
              		isPinching = false;
              		touchPositions.Clear();
              		canMoveCamera = false;
              		//Debug.Log("Touch state reset");
              	}
              }

              6結局採用したやつ:

              using UnityEngine;
              using UnityEngine.EventSystems;
              using System.Collections.Generic;
              using TMPro;
              
              [RequireComponent(typeof(Camera))]
              public class ImprovedSceneViewCamera : MonoBehaviour
              {
              	[SerializeField] private float pinchSpeed = 20f;
              
              	private Vector2 touchStartPos;
              	private Vector3 touchWorldStartPos;
              	private float initialFingersDistance;
              	private Vector3 initialCameraPosition;
              	private bool isPinching = false;
              	private int? activeTouchId = null;
              	private bool canMoveCamera = false;
              
              	private Camera mainCamera;
              	private Transform cameraTransform;
              
              	private void Start()
              	{
              		mainCamera = Camera.main;
              		cameraTransform = transform;
              	}
              
              	private void Update()
              	{
              		TouchUpdate();
              	}
              
              	private void TouchUpdate()
              	{
              		if (Input.touchCount == 1)
              		{
              			HandleSingleTouch(Input.GetTouch(0));
              		}
              		else if (Input.touchCount == 2)
              		{
              			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
              		}
              		else
              		{
              			ResetTouchState();
              		}
              	}
              
              	private void HandleSingleTouch(Touch touch)
              	{
              		switch (touch.phase)
              		{
              			case TouchPhase.Began:
              				if (!activeTouchId.HasValue)
              				{
              					activeTouchId = touch.fingerId;
              					touchStartPos = touch.position;
              					touchWorldStartPos = GetWorldPosition(touchStartPos);
              					canMoveCamera = CheckIfCanMoveCamera(touch.position);
              				}
              				break;
              
              			case TouchPhase.Moved:
              				if (activeTouchId == touch.fingerId)
              				{
              					if (canMoveCamera)
              					{
              						TouchDrag(touch);
              					}
              					else
              					{
              						// ここで他のタッチ処理を行う(必要に応じて)
              					}
              				}
              				break;
              
              			case TouchPhase.Ended:
              			case TouchPhase.Canceled:
              				if (activeTouchId == touch.fingerId)
              				{
              					ResetTouchState();
              				}
              				break;
              		}
              	}
              
              	private void HandlePinch(Touch touch1, Touch touch2)
              	{
              		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
              		{
              			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			initialCameraPosition = cameraTransform.position;
              			isPinching = true;
              		}
              		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
              		{
              			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
              			float scaleFactor = initialFingersDistance / currentFingersDistance;
              			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
              			cameraTransform.position = newPosition;
              		}
              		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
              		{
              			isPinching = false;
              		}
              	}
              
              	private bool CheckIfCanMoveCamera(Vector2 touchPos)
              	{
              		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;
              
              		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider", "GetWorks")))
              		{
              			return touchedObject.CompareTag("Ground");
              		}
              
              		return false;
              	}
              
              	private void TouchDrag(Touch touch)
              	{
              		if (!canMoveCamera) return;
              
              		Vector3 currentTouchWorldPos = GetWorldPosition(touch.position);
              		Vector3 worldSpaceDelta = touchWorldStartPos - currentTouchWorldPos;
              
              		// カメラの位置を更新
              		cameraTransform.position += worldSpaceDelta;
              	}
              
              	private Vector3 GetWorldPosition(Vector2 screenPosition)
              	{
              		Ray ray = mainCamera.ScreenPointToRay(screenPosition);
              		Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
              		if (groundPlane.Raycast(ray, out float distance))
              		{
              			return ray.GetPoint(distance);
              		}
              		return Vector3.zero;
              	}
              
              	private void ResetTouchState()
              	{
              		activeTouchId = null;
              		isPinching = false;
              		canMoveCamera = false;
              	}
              }

              AIにiPhoneの写真アプリみたいにって言ったら、これ出してきた。

              というか、エディタ上でUnity Remoteで動かすときと、Buildして実機で動かすときとじゃ、全然挙動が違う。それ知ってればサクッとできたのに。というお話。

              素材集のブックマーク

              突然ですが、私のブラウザに保存されている素材集のブックマークを共有いたします。
              誰かの参考になれば幸いです。
              めんどくさいので、ガサッとコピペしただけで申し訳無いです...

              ニコニ・コモンズ
              「紙」の画像素材を無料ダウンロード(1)背景フリー素材 BEIZ images
              滑らかな紙の粒子 | 無料テクスチャ
              Free Content
              フリーBGM|無料ゲーム音楽専門ダウンロード-ユーフルカ
              フリーBGMサイト紹介 – 一般社団法人フリーBGM協会
              多彩なコンセプトのフリー音楽素材 BGM「音の園」
              Soundful
              多彩なコンセプトのフリー音楽素材 BGM「音の園」
              フリーBGM素材『なんでしょう?』試聴ページ|フリーBGM DOVA-SYNDROME
              閲覧 | スプライス
              ホーム – フラッシュバックジャパン
              たうろんの!成りあ音楽! | 音を選ぶ楽しさ、きっとみつかる。多分₍⁠₍⁠ ⁠◝⁠(⁠ ゚⁠∀⁠ ゚⁠ ⁠)⁠◟⁠ ⁠⁾⁠⁾
              PSDファイル アーカイブ | PhotoshopVIP
              商用利用OKなフリー動画素材配布サイトおすすめ15選!
              エフェクトの動画|無料の動画素材サイト「動画AC」
              PSDファイル アーカイブ | PhotoshopVIP
              YouTubeから変換MP3 – オンラインコンバータ
              無料の動画素材サイト|動画AC
              200,000+件の最高の鳥のさえずり関連動画 · 100%無料でダウンロード · Pexelのストック動画
              YouTuberのための素材屋さん
              4000無料動画素材, 著作権フリーストックビデオ
              効果音ラボ – フリー、商用無料、報告不用の効果音素材をダウンロード
              App Privacy Policy Generator
              ボタン・システム音[1]|効果音ラボ
              フリーBGM 「あと10分。そしたらセーブして消すから(just10more minutes to go)」/Lo-Fiオルゴール&8bit/free/かわいい/kawaii/cute/作業勉強用 – ねこのまきのBGM – BOOTH
              Cosmic Media
              BGM🎵 | たうろんの!成りあ音楽!
              ボイス(音声)素材 – フリーBGM|無料ゲーム音楽 ユーフルカ
              4.400万点以上の高品質なフリー画像素材 – Pixabay – Pixabay
              ぱくたそ – 会員登録不要、無料の写真素材・AI画像素材
              無料イラスト・フリー素材なら「イラストAC」
              武器素材 破滅の杖-シェア・マテリアル
              「北欧風の素朴な作りの木製額縁」の画像・写真素材を無料ダウンロード(1)背景フリー素材 BEIZ images
              Unityの素材データ 人気の同人グッズ442点を通販!話題のアニメやデザインから個性的で被らないアイテムが見つかる – BOOTH
              8ページ目 – Unityの素材データ 人気の同人グッズ442点を通販!話題のアニメやデザインから個性的で被らないアイテムが見つかる – BOOTH
              Effekseerで作ったエフェクトをUnityで使う|hirokichigamer804
              コツコツエンジニアノート
              VST プラグイン (無料ダウンロード) | 99音
              AzCt Laboratory: » Material Top (利用規約)
              【フリーBGM】Sweet Pop Sweets / 甘くてポップなお菓子【1時間耐久】 kawaii BGM 配信 雑談 vlog – YouTube

              TextMeshPro

              TextMeshProの謎の枠

              Unityでテキストを扱う際にTextMeshProを使用すると思いますが、画像のように枠が2つ表示されます。これ実は重要なんです。



              1つ目は黄色で表示される枠線


              黄色の枠線は、インスペクターでみると左の画像のあたりが関係してきます。

              Alignment の項目で黄色の枠線の中央に表示するか、または左揃えにするか、等を変更することができます。

              枠線からはみ出した場合の処理は、
              Wrapping や Overflow で変更できます。

              2つ目の四隅に青い丸がある枠線


              問題になるのは、外側の方の四隅に青い丸がある枠線です。

              Rect Transform の Width と Height がその大きさなのですが、うっかり大きくしていても気付かない時があります。

              大きくても問題ないと思ったそこのアナタ。これ透明で描写処理されています。


              レンダリングの際に透明として描写される

              つまりその分GPUに負荷がかかっています。透明の描写って結構重いんです。
              何に気をつけないといけないかというとこの枠線がはるか遠くまで巨大に広がっている場合

              左は一見すると大丈夫そうですが、カメラをひいてみると右のようになってます。
              つまり、超巨大な透明をわざわざ描写しています。しかもこれ一つならまだしも、このオブジェクトをコピーして別の文字に変えて作った場合。

              透明の画像を何枚も何枚も描写してしまっています。シーンビューならまだしも、ゲームビューで見てもさっぱりわかりません。これはなかなか気づきません。

              2つ目の枠の設定するところ

              TextMeshPro – Text (UI)コンポーネントの下のほうにある Extra Settings を開くとそこに Margins という項目があって、これが上下左右の隙間の値です。

              おまけにこの枠には Raycast Target の項目があります。
              横に置いたボタンがなぜかクリックできない場合、この透明の板の向こう側にボタンがある可能性があります。

              以上、クリックできないボタンと格闘し、なぜか描写に時間がかかる罠にハマった人の覚書でした。

              待機処理3種紹介+α

              Unityで使うC#プログラムでのそれぞれの待機処理の特徴や違い



              コルーチン

              using UnityEngine;
              using System.Collections;
              
              public class MyScript : MonoBehaviour
              {
                  // コルーチンを呼び出す関数
                  void Start()
                  {
                      StartCoroutine(MyCoroutine());
                  }
              
                  // コルーチン関数
                  IEnumerator MyCoroutine()
                  {
                      // 何かしらの処理
                      Debug.Log("処理開始");
              
                      // 2秒間待つ
                      yield return new WaitForSeconds(2f);
              
                      // コルーチンを終了
                      yield break;
                  }
              }
              • 柔軟
              • using System.Collections;が必要
              • 個人的に読みにくい
              • StartCoroutine(MyCoroutine());←文字列じゃなくて関数で呼び出したほうが便利
              • コルーチン中にデストロイされると、処理が強制終了



              Invoke

              using UnityEngine;
              
              public class MyScript : MonoBehaviour
              {
                  void Start()
                  {
                      // 2秒後にMyFunction関数を呼び出す
                      Invoke("MyFunction", 2f);
                  }
              
                  void MyFunction()
                  {
                      Debug.Log("2秒後に実行されます");
                  }
              }
              • つづり覚えれない(Inボケ)
              • シンプル→引数使えない(単純に待つのみ)
              • デストロイされても、復活できる
              • Invoke(“MyFunction”, 2f);→文字列で渡すのでタイプミス注意



              DOTween

              using UnityEngine;
              using DG.Tweening;
              
              public class MyScript : MonoBehaviour
              {
                  void Start()
                  {
                      // 2秒後にMyFunctionを実行
                      DOVirtual.DelayedCall(2f, () => MyFunction());
                  }
              
                  void MyFunction()
                  {
                      Debug.Log("2秒後に実行されました");
                  }
              }
              • コードがシンプルでよみやすい
              • ほかにも色んなことできる
              • 負荷はおなじぐらい
              • using DG.Tweening;が必要
              • パッケージマネジャーからインストールが必要
              • デストロイされるとエラーになる



              UniTask

              using Cysharp.Threading.Tasks;
              
              async UniTask StartAsync()
              {
                  // 2秒待つ
                  await UniTask.Delay(TimeSpan.FromSeconds(2));
              
                  Debug.Log("2秒経過しました");
              }
              • 使ったことないが、最新式で軽量でおすすめらしい

              なまちゃんと愉快な仲間たち

              うちに住んでいる同居人を紹介します。まずはなまちゃん。
              白文鳥で『なまなま』『なまつか』のゲームの主役でもあります。

              美人ですが、性格は悪いです。なまちゃんについては、これからいっぱい出てきますので、サラッとご紹介。
              グッツ展開もしています。minneというサイトで販売もしてますよ。

              作ってる人のX(Twitter)アカウント
              作ってる人のホームページ(KANAKO TAKEUCHI)



              ツチガエルの”ロボ” と フタホシコオロギの”たかし”

              夏に川遊び行った時に捕まえました。何歳か分からないけど、捕まえてからもう5年ほど経ちました。意外と長生きです。全くなついてくれません。水換えのたびに飛び出して家中をかけまわります。とてもグルメなので人工餌は食べません。

              ”ロボ”と同時に、ロボをアリぐらいに小さくした”チビ”も一緒に捕まえましたが、ご飯を食べてくれず亡くなりました。

              たかしは近所のペットショップで買ってきます。”たかしA”と”たかしB”と”たかしC”とたか... 生まれ変わります。一匹20円。ヨーロッパイエコオロギと悩むのですが、フタホシ派です。ふとしたときに何故か家の中を歩き回ってます。秋には大合唱です。生育環境を確立させるまですぐ死ぬので大変でした。



              昔いた生き物たち


              アイリッシュセッターの”たー”

              ”たー”がいた頃は、生活が”たー”中心にまわってました。毛並みがキレイで大型犬なので、近所でも有名だったようです。”たー”に会いに近所の小学生がよく遊びにきてました。一度アイリッシュセッターを飼うと、もうほかの犬種には目がいかないです。犬がいる生活は楽しかったです。また飼いたいのですが今はちょっと厳しいです。でもまた大型犬飼いたいな。
              他にもボルゾイかサルーキが好きです。やっぱり犬はマズルが長くてなんぼですw

              ミニチュアダックスフンドの”ぬー”

              先住犬の”ぬー”です。2人を散歩させてたら、よく親子と言われてました。いい感じのマズルの長さです。犬は最高の相棒です。今はいないので寂しいです。



              ヒメウズラの”たまちゃん”

              タマゴから温めて生まれてきました。なまちゃんは”たまちゃん”の次の子だから、『た行』の次の『な行』からとって”なまちゃん”なんです。



              ほかにも紹介しきれない子たちがいっぱい

              セキセイインコにうずら、イモリやら何やらいっつも動物に囲まれて過ごしています。



              最後に庭のねむの木の紹介

              十年以上前にお隣さんからねむの木の種をいただきました。はじめはタンポポより小さかったんです。それが今では背丈を超えて、花まで咲かせるようになりました。10月の今週に5匹の蝶(キチョウ)が蛹をつくって飛び立っていきました。
              抜いても抜いても生えてくる雑草は、名前を付けて逆に育てています。その名は”ZASSO”。昨日、花が咲きました。”ZASSO”も色んな種類があって、愛おしいです。

              なまなま ―なまちゃんが生まれる―

              はじめまして

              これから、投稿を始めていきます。X(Twitter)で文字数が足りなくて載せれない時、不意にいいアイディアが思いついた時、共有したい情報、手法、Tips。

              皆さんと一緒に続けていければ最高だと考えてます。
              動画配信とともに、少しづつ伸びていって欲しい。よろしくお願いします。

              Unityを触り始めて半年が過ぎました。そしてようやく二作目の『なまなま』がリリースできそうです。
              しかしそれを阻む、”モバイル端末の最適化”。そうです。重すぎて動かないのです。でもこうやって配信を続けて、SNSで繋がった方々に支えられてなんとかなりそうです。もしこれが本当に一人なら、挫折していたでしょう。でも違います。私達は一人じゃないです。なにせ”マルチ集団”ですので!

              なまなま
              なまなま

              1920px 1080pxで作っています。もしよかったらスマホの壁紙にでもしてもらえたら喜びます。