赞
踩
我们如何在游戏中实现拖拽物体呢,如果仅仅是让拖拽坐标,可能没有物理效果,这里可以使用Joint来实现。
首先我们在场景中放置道具。
如图,我们放置一个圆柱体Cylinder,一个Sphere球体,和地面。
圆柱体就是我们要拖动的物体,红色球体是我们点击的位置,白色的地面放置圆柱体掉下去。
我们在圆柱体上增加刚体,球体上也增加刚体,球体的Rig需要勾选运动学,因为Joint组件需要。
我们要实现鼠标点击圆柱体,拖拽,圆柱体跟随鼠标左右上下移动。
我们添加一个脚本CDrag挂在球体上。
变量HandRig就是球体的刚体。
变量Target就是圆柱体。
在Update中,我们先写鼠标点击事件。我们要做的事情就是鼠标按下后,我们发射射线检测是否碰到圆柱体,然后把红色的球体移动过去,并且给圆柱体增加ConfigurableJoint,把他们两个联系起来,这样圆柱体就跟随球体了。代码如下:
void Hand(float x, float y)
{
Vector3 at = new Vector3(x, y, myCamera.transform.position.z);
Ray ray = myCamera.ScreenPointToRay(at);
RaycastHit hit;
Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red, 1f);
bool b = Physics.Raycast(ray, out hit, 100f, 1 << LayerMask.NameToLayer("Default"));
if (b && hit.collider != null && hit.collider.name.Equals("Cylinder"))
{
HandRig.transform.position = hit.point;
if (joint != null)
Destroy(joint);
joint = target.gameObject.AddComponent<ConfigurableJoint>();
joint.connectedBody = HandRig;
joint.xMotion = ConfigurableJointMotion.Locked;
joint.yMotion = ConfigurableJointMotion.Locked;
joint.zMotion = ConfigurableJointMotion.Locked;
handupdis = Vector3.Distance(hit.point, myCamera.transform.position);
}
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Hand(Input.mousePosition.x,Input.mousePosition.y);
}
}
我们看到,在射线碰到圆柱体后,我们把红球改到了碰撞点位置,并且给target(圆柱体)增加了ConfigurableJoint,并且让他connectedBody到红球,并且设置x,y,z可以自由移动。最后handupdis是为了下面的移动准备的。
然后我们再来处理移动
当我们移动的时候,我们只要移动球体,那么因为Joint被绑定到球体了,他也会跟着移动了。
if (Input.GetMouseButton(0))
{
Move(Input.mousePosition);
}
private void Move(Vector3 pos)
{
pos.z = handupdis;
Vector2 world = myCamera.ScreenToWorldPoint(pos);
HandRig.transform.position = world;
}
我们来看看效果。
有没有发下一个问题,红球点击圆柱体下面的时候,被拾取的点还是在顶部,我们需要计算锚点。
增加这行代码就舒服多了。
joint.anchor = joint.transform.InverseTransformPoint(hit.point);
我们把鼠标放开也一起写了,放上全部代码。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//UTF8支持
public class CDrag : MonoBehaviour
{
[SerializeField] Rigidbody HandRig;
[SerializeField] Transform target;
Camera myCamera;
ConfigurableJoint joint;
float handupdis;
Vector2 startpos;
// Start is called before the first frame update
void Start()
{
myCamera = Camera.main;
}
void Hand(float x, float y)
{
Vector3 at = new Vector3(x, y, myCamera.transform.position.z);
Ray ray = myCamera.ScreenPointToRay(at);
RaycastHit hit;
Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red, 1f);
bool b = Physics.Raycast(ray, out hit, 100f, 1 << LayerMask.NameToLayer("Default"));
if (b && hit.collider != null && hit.collider.name.Equals("Cylinder"))
{
HandRig.transform.position = hit.point;
if (joint != null)
Destroy(joint);
joint = target.gameObject.AddComponent<ConfigurableJoint>();
joint.connectedBody = HandRig;
joint.xMotion = ConfigurableJointMotion.Locked;
joint.yMotion = ConfigurableJointMotion.Locked;
joint.zMotion = ConfigurableJointMotion.Locked;
joint.anchor = joint.transform.InverseTransformPoint(hit.point);
handupdis = Vector3.Distance(hit.point, myCamera.transform.position);
}
}
private void Move(Vector3 pos)
{
pos.z = handupdis;
Vector2 world = myCamera.ScreenToWorldPoint(pos);
HandRig.transform.position = world;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Hand(Input.mousePosition.x,Input.mousePosition.y);
}
if (Input.GetMouseButton(0))
{
Move(Input.mousePosition);
}
if (Input.GetMouseButtonUp(0))
{
Destroy(joint);
}
}
}
最终效果如下:
最后,Joint家族里还可以使用其他的Joint来实现,例如SpringJoint,那就带有弹簧效果了,原理都是一样和一个刚体链接起来就可以了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。