bate's blog

調べたこと実装したことなどを取りとめもなく書きます。

オブジェクトを置く位置を制限する

平面から外れた位置でマウスボタンを放すと平面から離れる直前の位置に戻す。

https://dl.dropbox.com/u/67579260/Unity/Flick02/Flick02.html

using UnityEngine;
using System.Collections;

public class cMain : MonoBehaviour {

	// Use this for initialization
	void Start () {
		StartCoroutine(Flick());
	}
	
	// Update is called once per frame
	void Update () {
	}
	
	/**
	 * @brief 無限ループ.
	 */
	IEnumerator Flick() {
		
		Vector3 LiftUp = 1.0f*Vector3.zero;
		Vector3 LastOnPlane = Vector3.zero;
		while(true) {
			GameObject target = null;
			bool isEnd = false;
			while(!isEnd) {
				if(Input.GetMouseButtonDown(0)) {
					Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
					RaycastHit hit;
					int layer = 1<<LayerMask.NameToLayer("Flick");
					if(Physics.Raycast(ray, out hit, Mathf.Infinity, layer)) {
						target = hit.collider.gameObject;
						if(target != null) {
							isEnd = true;
							target.renderer.material.color = Color.red;
							target.transform.position += LiftUp;
						}
					}
				}
				yield return 0;
			}
			
			bool isOnField = false;
			while(Input.GetMouseButton(0)) {
				yield return 0;
				Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
				Vector3 planeNormal = Vector3.up;
				float planeDistance = 0.0f;
				Vector3 p = IntersectRayPlane(ray, planeNormal, planeDistance) + LiftUp;
				target.transform.position = p;
				isOnField = UpdateLastOnPlane(ref LastOnPlane, p);
			}
			
			target.renderer.material.color = Color.white;
			target.transform.position -= LiftUp;
			if(!isOnField) {
				target.transform.position = LastOnPlane;
			}
		}
	}
	
	/**
	 * @brief	直線と平面の交点.
	 */
	Vector3 IntersectRayPlane(Ray ray, Vector3 planeN, float planeD) {
		float t = -planeD-Vector3.Dot(planeN, ray.origin)/Vector3.Dot(planeN, ray.direction);
		return ray.origin + t * ray.direction;
	}
	
	/**
	 * @brief	平面上を離れる直前を捉える.
	 */
	bool UpdateLastOnPlane(ref Vector3 save, Vector3 pos) {
		Ray ray = new Ray(pos+10.0f*Vector3.up, -Vector3.up);
		RaycastHit hit;
		int layer = 1<<LayerMask.NameToLayer("Field");
		if(Physics.Raycast(ray, out hit, Mathf.Infinity, layer)) {
			GameObject obj = hit.collider.gameObject;
			if(obj != null) {
				save = hit.point;
				return true;
			}
		}
		return false;
	}
}