Unity3d / VectorField Physic

2011.04.30 | unity3d

前回のものをちょっと変更。
前回のものはvectorFieldからの力を vel += force; みたいな感じで、計算で処理していたのですが、せっかくunityでやっているので物理エンジンを使用して動きをつけて動かすものをCubeにしています。
Left Shiftキーとマウスで若干カメラのアングルを変更。中央の四角は移動可能です。

[ demo ]

物理エンジンをつかったことで、それぞれのCubeにも当たり判定がついて動き方にも表情がでたような。
前回のものは、
updateVel(Vector2 force, float w, float h) の中で

        vel *= drag;
        vel += force;
        pos_x += vel.x;

としていたものを、

rigid.AddForce(new Vector3(force.x, force.y, 0f) * 3000f);

のような感じで、rigidbodyにvectorFieldからの力を与えています。
上下左右つなげるために、物理エンジン影響下にあるオブジェクトを任意の位置に移動するには、
rigidbody.MovePosition(position);
です。

using UnityEngine;
using System.Collections;


public class MainCube: MonoBehaviour {
	
	/**
		lineMaterial 
		ラインを描画するためのマテリアルとシェーダーの設定
	*/
	static Material lineMaterial ;
	
	float widowSizeHalf;
	
	public int splitW = 30;
	public int splitH = 30;
	
	// ポイントの色
	public Color gridColor  = Color.red;
	
	// 力をうけたポイントの最大の移動距離・円の大きさ
	public float drawPeak = 40f;
	
	public float radius = 0.3f;
	
	// 受けた力の方向のライン、円を描画するか
	public bool drawLine = true;
	public bool enableCircle = true;
	
	public GameObject prefab;
	
	private VectorField field;
	
	static void CreateLineMaterial() {
	    if( !lineMaterial ) {
	        lineMaterial = new Material( "Shader \"Lines/Colored Blended\" {" +
	            "SubShader { Pass { " +
	            "    Blend SrcAlpha OneMinusSrcAlpha " +
	            "    ZWrite On Cull Off Fog { Mode Off } " +
	            "    BindChannels {" +
	            "      Bind \"vertex\", vertex Bind \"color\", color }" +
	            "} } }" );
	        lineMaterial.hideFlags = HideFlags.HideAndDontSave;
	        lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
	    }
	}
	
	public static float ofGetWidth()
	{
		return 600.0f;
	}
	public static float ofGetHeight()
	{
		return 600.0f;
	}
	
	//
	/*****************************
		描画
	******************************/
	
	Vector2 screenOffset;
	
	void _drawPoints()
	{
		lineMaterial.SetPass( 0 );
		
		GL.Begin( GL.LINES );
		if(drawLine){
			GL.Color( gridColor );
			field.draw(-w/2,-h/2,w,h, 10f);
		}
		GL.End();
	}
	
	/*****************************
		vector Field
	******************************/

	void _initVectorField(){
		field = new VectorField(splitW, splitH);
	}
			
	void addIntoField(float x, float y, Vector2 vec, float radius)
	{	
		field.addIntoField(x, y, vec, radius);
	}
	
	public void blur(float amnt){
		field.blur(amnt);
	}
	
	// x,y : 0 - 1
	Vector2 readFromField(float x, float y)
	{
		return field.readFromField(x, y);
	}
	
	public void clear()
	{
		field.clear();			
	}
	
	public static float ofRandom(float min , float max)
	{
		return Random.Range(min, max);
	}
	
	//
	public int NUM_PARTICLES = 5000;
	private particleCube[] p;
	
	public float per = 0.015f;
	
	private float w;
	private float h;
	
	private void _initParticles()
	{
		w = ofGetWidth();
		h = ofGetHeight();
		
		p = new particleCube[NUM_PARTICLES];
		for(int i = 0; i < NUM_PARTICLES; i++){
			p[i] = new particleCube(prefab);
			p[i].setup(ofRandom(0f, w), ofRandom(0f, h));
		}
	}
	
	private void _updateParticles()
	{
		Vector2 point;
		Vector2 fieldForce;
		foreach (particleCube pt in p){
			point = readFromField(pt.pos_x / w, pt.pos_y / h);
			fieldForce  = point * drawPeak;
			pt.updateVel(fieldForce * per, w, h);
		}
		
	}
	
	// Use this for initialization
	void Start () {
		widowSizeHalf = ofGetWidth()/2;
			
		CreateLineMaterial();
		
		_initVectorField();
		
		_initParticles();
	}
	
	void OnPostRender ()
	{
	    _drawPoints();
	}
	void Update()
	{	
		_updateParticles();
	}
	
	void OnGUI()
	{
		Event currentEvent = Event.current;
		if(currentEvent.type == EventType.MouseDown){
			_OnMouseDown(currentEvent);
		}
		if(currentEvent.type == EventType.MouseUp){
			_OnMouseUp();
		}
		
		if(_isMouseDown){
			_OnMouseMove(currentEvent);
		}
	}
	
	private bool _isMouseDown = false;
	private Vector2 previousMouse = new Vector2(0,0);
	private Vector2 currentMouse = new Vector2(0,0);
	 
	void _OnMouseDown(Event currentEvent) {
		float x = currentEvent.mousePosition.x - Screen.width / 2 + ofGetWidth()/2;
		float y = Screen.height - currentEvent.mousePosition.y - Screen.height /2 + ofGetWidth()/2;
		
		previousMouse.x = x / ofGetWidth();
		previousMouse.y = y / ofGetHeight();
		
		_isMouseDown = true;
	}
	
	void _OnMouseUp() {
		_isMouseDown = false;
	}
	
	private void _OnMouseMove(Event currentEvent) {
		/*
		var stageX: float = currentEvent.mousePosition.x;
		var stageY: float = currentEvent.mousePosition.y;
		*/
		float x = currentEvent.mousePosition.x - Screen.width / 2 + ofGetWidth()/2;
		float y = Screen.height - currentEvent.mousePosition.y - Screen.height /2  + ofGetHeight()/2;
		
		//need to get mouse coords into a zero to one ratio
		currentMouse.x = x / ofGetWidth();
		currentMouse.y = y / ofGetHeight();
		
		//the direction of our mouse is the difference between the 
		//current and last position
		Vector2 motionVector = (currentMouse - previousMouse) * 6;	
		
		//we add into our field with a radius of 30%
		addIntoField(currentMouse.x, currentMouse.y, motionVector, radius);
		
		previousMouse = currentMouse;
	}
}


/*****************************
	particle
******************************/
class particleCube{
	
	public float pos_x = 0f;
	public float pos_y = 0f;
	
	private Vector2 _offsetPos;
	
	private GameObject gObj;
	private Vector3 pos;
	private Rigidbody rigid;
	
	public particleCube(GameObject prefab){
		_offsetPos = new Vector2(MainCube.ofGetWidth()/2, MainCube.ofGetWidth()/2);
		
		Quaternion rot = new Quaternion(Random.Range(-90, 90), Random.Range(-90, 90), Random.Range(-90, 90), Random.Range(-90, 90)); 
		gObj = GameObject.Instantiate(prefab, new Vector3(0f, 0f, 0f), rot) as GameObject;
		rigid = gObj.rigidbody;
	}
	
	public void setup(float x, float y)
	{
		pos_x = x;
		pos_y = y;
		
		pos = new Vector3(pos_x, pos_y, 0);
		gObj.transform.position = pos;
	}
	
	public void updateVel(Vector2 force, float w, float h){
		
		rigid.AddForce(new Vector3(force.x, force.y, 0f) * 3000f);
		
		pos = gObj.transform.position;
		pos_x = pos.x + _offsetPos.x;
		pos_y = pos.y + _offsetPos.y;
		
		if(pos.x > w/2){
			pos.x -= w;
			rigid.MovePosition(pos);
		}else if(pos.x < -w/2){
			pos.x += w;
			rigid.MovePosition(pos);
		}
		if(pos.y > h/2){
			pos.y -= h;
			rigid.MovePosition(pos);
		}else if(pos.y < -h/2){
			pos.y += h;
			rigid.MovePosition(pos);
		}
		
	}
}

There are no comments.

Please Leave a Reply

TrackBack URL :

pagetop