Skip to content

Instantly share code, notes, and snippets.

@f-space
Created October 15, 2017 10:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save f-space/46f61b3c4f17b5f7d86a99f41d7f8588 to your computer and use it in GitHub Desktop.
Save f-space/46f61b3c4f17b5f7d86a99f41d7f8588 to your computer and use it in GitHub Desktop.
http://filaaas216.hatenablog.com/entry/2017/10/15/021000 へのコメント用サンプルコード
using UnityEngine;
public class Actor : MonoBehaviour
{
// Rigidbodyと大きさを受け取り、画面内に収まるように位置と速度を調節する
protected void EnsureInScreen(Rigidbody2D rigidbody, Vector2 size)
{
// いくつもの前提の下に動作することに注意
// 前提1:メインカメラはZ軸正方向を向いている
// 前提2:画像の中心位置とオブジェクトの位置が一致している
// 前提3:画像は画面に収まる大きさである
// メインカメラの取得
Camera camera = Camera.main;
if (camera) // カメラが存在する場合のみ
{
// 画面の左下端・右上端のワールド座標を計算
// ビューポート座標:画面の左下を(0,0)、右上を(1,1)とする画面上の座標
// ワールド座標:ゲーム空間における座標、Sceneビューにおける座標
Vector2 screenMin = camera.ViewportToWorldPoint(Vector2.zero);
Vector2 screenMax = camera.ViewportToWorldPoint(Vector2.one);
// 画像の大きさを考慮して画面に全体が映る最小・最大の座標を計算
Vector2 halfSize = size * 0.5f;
Vector2 min = screenMin + halfSize;
Vector2 max = screenMax - halfSize;
// 操作しやすいように位置と速度を変数に代入
Vector2 position = rigidbody.position;
Vector2 velocity = rigidbody.velocity;
// 画面内に収まるようにX座標とX方向の速度を調整
// -1を掛ける反転処理はなんらかのミスで反転を繰り返すバグに陥りがちなので注意
if (position.x < min.x)
{
position.x = min.x;
velocity.x = Mathf.Abs(velocity.x);
}
else if (position.x > max.x)
{
position.x = max.x;
velocity.x = -Mathf.Abs(velocity.x);
}
// 画面内に収まるようにY座標とY方向の速度を調整
if (position.y < min.y)
{
position.y = min.y;
velocity.y = Mathf.Abs(velocity.y);
}
else if (position.y > max.y)
{
position.y = max.y;
velocity.y = -Mathf.Abs(velocity.y);
}
// 位置と速度を更新
rigidbody.position = position;
rigidbody.velocity = velocity;
}
}
}
using UnityEngine;
public class CreateEbi : MonoBehaviour
{
// 生成したいPrefab
public GameObject Ebi;
private void Update()
{
if (Input.GetMouseButtonDown(0)) // 左マウスボタン押下時
{
// メインカメラの取得
Camera camera = Camera.main;
if (camera) // カメラが存在する場合のみ
{
// マウスの位置を生成位置とする
Vector2 position = camera.ScreenToWorldPoint(Input.mousePosition);
// Prefabの内容をコピーして新しいゲームオブジェクトを生成
// 変数名はゲームオブジェクトの名前とは無関係なので注意
// 無回転の場合Quaternion.identityとする。new Quaternion()としてはいけない
GameObject go = Instantiate(Ebi, position, Quaternion.identity);
go.name = Ebi.name;
}
}
}
}
using UnityEngine;
// Rigidbody2DとSpriteRendererのアタッチが必要
[RequireComponent(typeof(Rigidbody2D), typeof(SpriteRenderer))]
public class Ebi : Actor
{
private Rigidbody2D m_Rigidbody;
private SpriteRenderer m_Renderer;
// 初期化
private void Awake()
{
// 各コンポーネントの取得
this.m_Rigidbody = GetComponent<Rigidbody2D>();
this.m_Renderer = GetComponent<SpriteRenderer>();
}
// 物理関連の状態更新
// Rigidbodyの操作は基本的にはFixedUpdateでする
private void FixedUpdate()
{
// 画面内に収まるように位置と速度を調節
EnsureInScreen(m_Rigidbody, m_Renderer.bounds.size);
}
// 他の何かと接触したとき
private void OnTriggerEnter2D(Collider2D collider)
{
// Fish2スクリプトがアタッチされていれば魚とみなす
if (collider.GetComponent<Fish2>()) // 魚と接触した場合
{
// このスクリプトがアタッチされているゲームオブジェクトごと削除
Destroy(gameObject);
}
}
}
using UnityEngine;
// Rigidbody2DとSpriteRendererのアタッチが必要
[RequireComponent(typeof(Rigidbody2D), typeof(SpriteRenderer))]
public class Fish2 : Actor
{
private Rigidbody2D m_Rigidbody;
private SpriteRenderer m_Renderer;
// 初期化
private void Awake()
{
// 各コンポーネントの取得
this.m_Rigidbody = GetComponent<Rigidbody2D>();
this.m_Renderer = GetComponent<SpriteRenderer>();
}
// 物理関連の状態更新
// Rigidbodyの操作は基本的にはFixedUpdateでする
private void FixedUpdate()
{
// 画面内に収まるように位置と速度を調節
EnsureInScreen(m_Rigidbody, m_Renderer.bounds.size);
// 最も近いエビに向かって移動
MoveToEbi();
// 魚の速度を更新
UpdateVelocity();
}
// 状態更新
private void Update()
{
// 進行方向に合わせて画像の向きを更新
UpdateImageDirection();
}
// 最も近いエビに向かって移動する
private void MoveToEbi()
{
// 全てのエビのリストを取得
// FindObjectsOfTypeは非常に重い処理のため、本格的にゲームを作る場合には別の方法を使う必要がある
Ebi[] ebiList = FindObjectsOfType<Ebi>();
// 全てのエビの中から最も距離の近いエビを探す
// その時点で最も近いエビとその距離を記録しておき、より近いものが現れたら情報を更新する
Ebi nearest = null; // 最も近いエビ
float minDistance = System.Single.PositiveInfinity; // 最も近いエビまでの距離(初期値は正の無限大)
foreach (Ebi ebi in ebiList) // ebiList内のエビが順番にebiに代入されてループ
{
// エビまでの距離を計算
Vector2 ebiPos = ebi.transform.position;
Vector2 fish2Pos = this.transform.position;
float distance = Vector2.Distance(ebiPos, fish2Pos);
Debug.Log("Distance : " + distance);
// 現時点で最も近いエビよりも距離が近かったら情報更新
if (distance < minDistance)
{
nearest = ebi;
minDistance = distance;
}
}
// 魚とエビの距離が8より小さい時、エビに向かう方向へ力を加える
if (minDistance < 8.0f)
{
// エビに向かう方向を計算
// normalizedプロパティで単位ベクトルにしておく
Vector2 ebiPos = nearest.transform.position;
Vector2 fish2Pos = this.transform.position;
Vector2 direction = (ebiPos - fish2Pos).normalized;
// エビに向かう方向へ力を与える
m_Rigidbody.AddForce(direction * 80.0f);
}
}
// 魚の速度を更新する
private void UpdateVelocity()
{
// 魚を減速させる
m_Rigidbody.velocity *= 0.9f;
// X方向への移動が止まった場合には新たな方向へと動かす
// コンピュータにおける実数の計算では計算誤差があるため完全に一致するとは限らない
// そのためある程度の誤差を許容して一致判定をするMathf.Approximatelyを使う
if (Mathf.Approximately(m_Rigidbody.velocity.x, 0.0f))
{
// ランダムに移動方向と速さを決定
// Random.valueは [0,1] の範囲でランダムな値を返す
float angle = Mathf.PI * 2.0f * Random.value;
Vector2 direction = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
float speed = 10.0f * Random.value;
// 新たな速度を設定
m_Rigidbody.velocity = direction * speed;
}
}
// 進行方向に合わせて画像の向きを更新する
private void UpdateImageDirection()
{
// X方向の速度を取得
float vx = m_Rigidbody.velocity.x;
if (!Mathf.Approximately(vx, 0.0f)) // X方向の速度が0に近い値でないならば
{
// 元画像が左向きであると仮定して進行方向を向くように画像を反転
// m_Renderer.flipX = (vx > 0.0f); と一行で書いてもいい
if (vx > 0.0f)
{
m_Renderer.flipX = true;
}
else
{
m_Renderer.flipX = false;
}
}
}
}
@ryupy
Copy link

ryupy commented Oct 16, 2017

ご親切にありがとうございます!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment