Unity3D基于物理的物体拖拽

官方的demo(http://unity3d.com/cn/showcase/live-demos#shadows)中的Room of Shadows,一开始抱着学习室内灯光效果的想法去看的,后来发现这个demo中有一个拖拽物体的脚本,正好最近玩了好多游戏都是这样的,好奇心来了,学习下原理,看了之后发现原理蛮简单的,单纯使用SpringJoint即可实现,这里把脚本的代码沾上了来,做个记录。(这个脚本中不止是拖拽,还有高光,基于重绘Mesh的,一并记了)

DragRigdbodyShadow.js

var spring = 50.0;
var damper = 5.0;
var drag = 10.0;
var angularDrag = 5.0;
var distance = 0.2;
var pushForce = 0.2;
var attachToCenterOfMass = false;

var highlightMaterial : Material;
private var highlightObject : GameObject;

private var springJoint : SpringJoint;

function Update()
{
	var mainCamera = FindCamera();
	
	highlightObject = null;
	if( springJoint != null && springJoint.connectedBody != null )
	{
		highlightObject = springJoint.connectedBody.gameObject;
	}
	else
	{
		// We need to actually hit an object
		var hitt : RaycastHit;
		if( Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition),  hitt, 100 ) ) {
			if( hitt.rigidbody && !hitt.rigidbody.isKinematic ) {
			    highlightObject = hitt.rigidbody.gameObject;
			    //这里通过射线判断选中物体,加入highlightObject中,之后通过OnPostRender函数重绘
			}
		}
	}
	
		
	// Make sure the user pressed the mouse down
	if (!Input.GetMouseButtonDown (0))
		return;

		
	// We need to actually hit an object
	var hit : RaycastHit;
	if (!Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition),  hit, 100)) {
		return;
	}
	// We need to hit a rigidbody that is not kinematic
	if (!hit.rigidbody || hit.rigidbody.isKinematic) {
		return;
	}
	
	if (!springJoint)
	{
		var go = new GameObject("Rigidbody dragger");
		body = go.AddComponent.<Rigidbody>();
		springJoint = go.AddComponent.<SpringJoint>();
		body.isKinematic = true;
	    //建立一个SpringJoint(反弹关节),弹簧,来模拟力
	}
	
	springJoint.transform.position = hit.point;
	if (attachToCenterOfMass)
	{
		var anchor = transform.TransformDirection(hit.rigidbody.centerOfMass) + hit.rigidbody.transform.position;
		anchor = springJoint.transform.InverseTransformPoint(anchor);
		springJoint.anchor = anchor;
	}
	else
	{
	    springJoint.anchor = Vector3.zero;
	}
	//这里判断是否强制连接物体重心,是的话将锚点置为重心
	springJoint.spring = spring;
	springJoint.damper = damper;
	springJoint.maxDistance = distance;
	springJoint.connectedBody = hit.rigidbody;
	
	
	DragObject(hit.distance, hit.point, mainCamera.ScreenPointToRay(Input.mousePosition).direction);
    
}

function DragObject (distance : float, hitpoint : Vector3, dir : Vector3)
{
	var startTime = Time.time;
	var mousePos = Input.mousePosition;
	
	
	var oldDrag = springJoint.connectedBody.drag;
	var oldAngularDrag = springJoint.connectedBody.angularDrag;
	springJoint.connectedBody.drag = drag;
	springJoint.connectedBody.angularDrag = angularDrag;
	var mainCamera = FindCamera();
	while (Input.GetMouseButton (0))
	{
		var ray = mainCamera.ScreenPointToRay (Input.mousePosition);
		springJoint.transform.position = ray.GetPoint(distance);
		yield;
	}
    //这个地方就是拖动弹簧,拉动物体,这个拉动很有意思,这里用的是distance,这样的话拉动的范围是以摄像机为圆心,以点击时记录下来的distance为半径的球,效果还不错,有立体拉动的感觉
	if (Mathf.Abs(mousePos.x - Input.mousePosition.x) <= 2 && Mathf.Abs(mousePos.y - Input.mousePosition.y) <= 2 && Time.time - startTime < .2 && springJoint.connectedBody)
	{
		dir.y = 0;
		dir.Normalize();
		springJoint.connectedBody.AddForceAtPosition(dir * pushForce, hitpoint, ForceMode.VelocityChange);
		ToggleLight( springJoint.connectedBody.gameObject );
	}	
	//这个的作用是点击的时候,做出一个拍打物体的感觉
	
	if (springJoint.connectedBody)
	{
		springJoint.connectedBody.drag = oldDrag;
		springJoint.connectedBody.angularDrag = oldAngularDrag;
		springJoint.connectedBody = null;
	}
}

static function ToggleLight( go : GameObject )
    {	
	var theLight : Light = go.GetComponentInChildren(Light);
	if( !theLight )
		return;
		
	theLight.enabled = !theLight.enabled;
	var illumOn = theLight.enabled;
	var renderers = go.GetComponentsInChildren(MeshRenderer);
	for( var r : MeshRenderer in renderers )
	{
		if( r.gameObject.layer == 1 )
		{
			r.material.shader = Shader.Find(illumOn ? "Self-Illumin/Diffuse" : "Diffuse");
		}
}
//开关灯,场景互动
}

function FindCamera ()
{
	if (GetComponent.<Camera>())
		return GetComponent.<Camera>();
	else
		return Camera.main;
}

function OnPostRender()
{
	if( highlightObject == null )
		return;
		
	var go = highlightObject;
	highlightMaterial.SetPass( 0 );
	var meshes = go.GetComponentsInChildren(MeshFilter);
	for( var m : MeshFilter in meshes )
	{
		Graphics.DrawMeshNow( m.sharedMesh, m.transform.position, m.transform.rotation );
	}
///setPass就是设置通道,走的是Shader中的第一个通道,下面的将网格重新绘制一次,做到高光效果,从实现上看,绘制的时候实用的就是上面的高光贴图
}


Highlight.shader
Shader "Shadows/Drag Highlight" {
Properties {
	_Color ("Main Color", Color) = (1,1,1,1)
}
SubShader {
	Pass {
		ZWrite Off
		Offset -1, -1
		Blend SrcAlpha OneMinusSrcAlpha
		Color [_Color]
	}
} 
}

这里的Blend是一个自身颜色和其他颜色的混合,在设置透明度时候用,这里使用它来设置重绘网格的透明度,表现为高光强度

具体见http://blog.sina.com.cn/s/blog_471132920101d8z5.html

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值