Skip to content

Instantly share code, notes, and snippets.

@hacha
Last active August 29, 2015 14:15
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 hacha/3120b6427661a8d68a6f to your computer and use it in GitHub Desktop.
Save hacha/3120b6427661a8d68a6f to your computer and use it in GitHub Desktop.
スプライト上を滑らかにカメラを動かすスクリプト
using UnityEngine;
using System.Collections;
public class CameraControl : MonoBehaviour
{
private enum DragStatus
{
Neutral = 0,
DragStart,
Dragging,
DragEnd,
};
// 動かす対象のカメラ
public Camera camera;
// 操作ステータス
private DragStatus status;
// ドラッグ中の前フレームでのタッチ位置
private Vector3 prevPos;
// ドラッグ時の移動スピード
[SerializeField]
private float speed = 0.03f;
// ドラッグ中に離した際に、慣性で動かすためにRigidbodyを使う
private Rigidbody2D rigidbody;
// rigidbody.velocityへの影響係数
[SerializeField]
private float rigidVelocityRate = 0.1f;
// cameraが写しているフォーカス対象
public SpriteRenderer focusTarget;
// フォーカス対象の最小x,y座標
private Vector2 minPosition;
// フォーカス対象の最大x,y座標
private Vector2 maxPosition;
// 押し戻し幅長さ
[SerializeField]
private float pushbackLength = 0.5f;
// 押し戻し強さ
private float pushbackForce = 30;
private float pushbackForceRate = 10.0f;
private Vector2 pushbackMinPosition;
private Vector2 pushbackMaxPosition;
// スムーズな拡縮をさせるための値を取るために、Rigidbodyを使っている。
// x成分だけを動かして、その値を画角の変動に使用
private Rigidbody2D sizeRigidbody;
// 拡縮スピード
private float sizeMoveSpeed = 0.5f;
private float sizeMoveSpeedRate = 2.0f;
private float orthoSizeMin = 0.6f;
private float orthoSizeMax = 2.4f;
// 拡縮押し戻し
private float pushbackSpeed = 0.08f;
private float pushbackOrthoSizeMin = 0.8f;
private float pushbackOrthoSizeMax = 2.2f;
// ピンチ距離
private float prevPinchLength;
// ピンチ操作量をマウスホイール単位に変換する際の補正割合
private float pinchConvertWheelRate = 0.002f;
// ピンチ操作中に移動しないようにするフラグ
private bool dontMoveInPinch = false;
void Start ()
{
camera = GetComponent<Camera>();
rigidbody = GetComponent<Rigidbody2D>();
// フォーカス対象の最小、最大の世界座標を取っておく
Bounds bounds = focusTarget.sprite.bounds;
Vector3 scale = focusTarget.transform.localScale;
minPosition = new Vector2(bounds.min.x * scale.x, bounds.min.y * scale.y);
maxPosition = new Vector2(bounds.max.x * scale.x, bounds.max.y * scale.y);
pushbackMinPosition = new Vector2(minPosition.x + pushbackLength, minPosition.y + pushbackLength);
pushbackMaxPosition = new Vector2(maxPosition.x - pushbackLength, maxPosition.y - pushbackLength);
// 拡縮動作用のコンポーネントと、それを保持するための仮オブジェクトを生成
GameObject obj = new GameObject();
obj.name = "ForOrthographicSizeMove";
obj.transform.position = new Vector3(camera.orthographicSize, 0, 0);
sizeRigidbody = obj.AddComponent("Rigidbody2D") as Rigidbody2D;
sizeRigidbody.gravityScale = 0;
// 慣性の滑らかさは下記で何となく調整
sizeRigidbody.mass = 3.0f;
sizeRigidbody.drag = 3.0f;
}
void Update ()
{
// ドラッグ開始検出
if (Input.GetMouseButtonDown(0)) {
status = DragStatus.DragStart;
}
// ドラッグ終了検出
if (Input.GetMouseButtonUp(0)) {
status = DragStatus.DragEnd;
}
switch (status) {
case DragStatus.DragStart :
Debug.Log ("drag start");
prevPos = Input.mousePosition;
status = DragStatus.Dragging;
break;
case DragStatus.Dragging :
Vector3 move = prevPos - Input.mousePosition;
// 前フレームからの差の分だけ動かす
// さっと指を離した場合でも滑らかに慣性移動して欲しいので、位置だけではなくRigidbodyも同時に動かしている。
if (!dontMoveInPinch) {
transform.position += move * speed;
rigidbody.velocity = move * rigidVelocityRate;
}
prevPos = Input.mousePosition;
break;
case DragStatus.DragEnd :
Debug.Log ("drag end");
status = DragStatus.Neutral;
break;
case DragStatus.Neutral :
// 画面端での押し戻しチェック
CheckPushback ();
break;
}
// マウスホイール操作での画角変更
float wheelMove = Input.GetAxis ("Mouse ScrollWheel");
// ピンチ操作をマウスホイール操作量として扱わせる
float pinchLength = 0;
if (Input.touchCount >= 2) {
Touch touch0 = Input.GetTouch(0);
Touch touch1 = Input.GetTouch(1);
pinchLength = Vector2.Distance(touch0.position, touch1.position);
if (prevPinchLength > 0) {
wheelMove = -(pinchLength - prevPinchLength) * pinchConvertWheelRate;
}
rigidbody.velocity = Vector3.zero;
dontMoveInPinch = true;
} else {
// ピンチ操作が外れたタイミングで大きくドラッグ位置がズレるようなので、prevPosをタッチ中の位置で更新している
if (dontMoveInPinch) {
if (Input.touchCount >= 1) {
prevPos = Input.GetTouch(0).position;
}
}
dontMoveInPinch = false;
}
prevPinchLength = pinchLength;
// 画角変更用のオブジェクトを動かす
if (wheelMove != 0) {
sizeRigidbody.transform.position += new Vector3(wheelMove * sizeMoveSpeed, 0, 0);
sizeRigidbody.velocity += new Vector2(wheelMove * sizeMoveSpeedRate, 0);
}
// 画角更新
UpdateOrthographicSize();
// 画面端チェック
CheckScreenEnd ();
}
// 画面端チェック
void CheckScreenEnd ()
{
// 最小・最大座標をビューポート座標に変換して、0.0~1.0の範囲内かどうかで画面端を超えているかチェック
// 超えていたqら、画面端の座標を世界座標系にしたものとの差分だけ位置を動かして補正
Vector2 min = camera.WorldToViewportPoint(minPosition);
Vector2 max = camera.WorldToViewportPoint(maxPosition);
Vector3 minEdge = camera.ViewportToWorldPoint(Vector3.zero);
Vector3 maxEdge = camera.ViewportToWorldPoint(Vector3.one);
if (min.x > 0) {
float offset = minPosition.x - minEdge.x;
transform.position += new Vector3(offset, 0, 0);
}
if (max.x < 1) {
float offset = maxEdge.x - maxPosition.x;
transform.position -= new Vector3(offset, 0, 0);
}
if (min.y > 0) {
float offset = minPosition.y - minEdge.y;
transform.position += new Vector3(0, offset, 0);
}
if (max.y < 1) {
float offset = maxEdge.y - maxPosition.y;
transform.position -= new Vector3(0, offset, 0);
}
}
// 画面端での押し戻しチェック
void CheckPushback ()
{
Vector2 min = camera.WorldToViewportPoint(pushbackMinPosition);
Vector2 max = camera.WorldToViewportPoint(pushbackMaxPosition);
Vector2 vel = rigidbody.velocity;
if (min.x > 0) {
rigidbody.AddForce(Vector2.right * pushbackForce);
vel += Vector2.right * pushbackForceRate;
}
if (max.x < 1) {
rigidbody.AddForce(-Vector2.right * pushbackForce);
vel += -Vector2.right * pushbackForceRate;
}
if (min.y > 0) {
rigidbody.AddForce(Vector2.up * pushbackForce);
vel += Vector2.up * pushbackForceRate;
}
if (max.y < 1) {
rigidbody.AddForce(-Vector2.up * pushbackForce);
vel += -Vector2.up * pushbackForceRate;
}
}
void UpdateOrthographicSize ()
{
// 画角値の範囲チェック
float x = sizeRigidbody.transform.position.x;
x = Mathf.Max(orthoSizeMin, x);
x = Mathf.Min(orthoSizeMax, x);
sizeRigidbody.transform.position = new Vector3(x, 0, 0);
// 画角値の押し戻しチェック
if (sizeRigidbody.transform.position.x < pushbackOrthoSizeMin) {
sizeRigidbody.velocity += Vector2.right * pushbackSpeed;
}
if (sizeRigidbody.transform.position.x > pushbackOrthoSizeMax) {
sizeRigidbody.velocity += -Vector2.right * pushbackSpeed;
}
camera.orthographicSize = sizeRigidbody.transform.position.x;
}
void OnDrawGizmos()
{
// 最小、最大座標の位置を確認
Gizmos.DrawWireSphere(minPosition, 0.3f);
Gizmos.DrawWireSphere(maxPosition, 0.3f);
// 押し戻し範囲
Vector2 p1 = new Vector2(pushbackMinPosition.x, pushbackMaxPosition.y);
Vector2 p2 = new Vector2(pushbackMaxPosition.x, pushbackMinPosition.y);
Gizmos.DrawLine(pushbackMinPosition, p1);
Gizmos.DrawLine(pushbackMinPosition, p2);
Gizmos.DrawLine(pushbackMaxPosition, p1);
Gizmos.DrawLine(pushbackMaxPosition, p2);
// 画角調整用のダミーオブジェクト
if (sizeRigidbody) {
Gizmos.DrawSphere(sizeRigidbody.transform.position, 0.2f);
}
Gizmos.DrawSphere(new Vector3(orthoSizeMin, 0, 0), 0.1f);
Gizmos.DrawSphere(new Vector3(orthoSizeMax, 0, 0), 0.1f);
Gizmos.DrawSphere(new Vector3(pushbackOrthoSizeMin, 0, 0), 0.1f);
Gizmos.DrawSphere(new Vector3(pushbackOrthoSizeMax, 0, 0), 0.1f);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment