场景结构,两个普通模型
第一种 脚本所挂载的物体才可以被拖拽 【PC鼠标版本】
using UnityEngine;
// 这个脚本实现了,本脚本所在的游戏物体能够被拖拽
public class DragObjectT : MonoBehaviour
{
private Vector3 screenPoint; // 存储物体在屏幕上的位置
private Vector3 offset; // 存储鼠标点击位置与物体实际位置的偏移量
private bool isDragging = false; // 标志位,表示物体是否正在被拖拽
void Update()
{
// 检测鼠标左键是否按下
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // 从摄像机发射一条射线到鼠标位置
// 使用射线检测是否击中了某个物体
if (Physics.Raycast(ray, out hit))
{
// 检查被击中的物体是否是本脚本所附加的物体
if (hit.collider.gameObject == gameObject)
{
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position); // 将物体的世界坐标转换为屏幕坐标
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z)); // 计算偏移量
isDragging = true; // 设置拖拽标志位为真
}
}
}
// 检测鼠标左键是否持续按下并且物体正在被拖拽
if (Input.GetMouseButton(0) && isDragging)
{
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z); // 获取当前鼠标位置的屏幕坐标
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset; // 将屏幕坐标转换为世界坐标并加上偏移量
transform.position = curPosition; // 更新物体的位置
}
// 检测鼠标左键是否释放
if (Input.GetMouseButtonUp(0))
{
isDragging = false; // 设置拖拽标志位为假
}
}
}
这个脚本通过检测鼠标输入来实现物体的拖拽功能。以下是详细的步骤解释:
-
变量声明:
-
screenPoint
:存储物体在屏幕上的位置。 -
offset
:存储鼠标点击位置与物体实际位置的偏移量。 -
isDragging
:标志位,表示物体是否正在被拖拽。
-
-
Update方法:
-
检测鼠标左键是否按下(
Input.GetMouseButtonDown(0)
)。 -
如果按下,从摄像机发射一条射线到鼠标位置(
Camera.main.ScreenPointToRay(Input.mousePosition)
)。 -
使用射线检测是否击中了某个物体(
Physics.Raycast(ray, out hit)
)。 -
检查被击中的物体是否是本脚本所附加的物体(
hit.collider.gameObject == gameObject
)。 -
如果是,将物体的世界坐标转换为屏幕坐标(
Camera.main.WorldToScreenPoint(gameObject.transform.position)
),并计算偏移量(offset
)。 -
设置拖拽标志位为真(
isDragging = true
)。
-
-
拖拽逻辑:
-
检测鼠标左键是否持续按下并且物体正在被拖拽(
Input.GetMouseButton(0) && isDragging
)。 -
获取当前鼠标位置的屏幕坐标(
curScreenPoint
)。 -
将屏幕坐标转换为世界坐标并加上偏移量(
curPosition
)。 -
更新物体的位置(
transform.position = curPosition
)。
-
-
释放逻辑:
-
检测鼠标左键是否释放(
Input.GetMouseButtonUp(0)
)。 -
设置拖拽标志位为假(
isDragging = false
)。
-
以下是适用于移动端触摸屏的版本:
using UnityEngine;
// 这个脚本实现了,本脚本所在的游戏物体能够被触摸拖拽
public class DragObjectT : MonoBehaviour
{
private Vector3 screenPoint; // 存储物体在屏幕上的位置
private Vector3 offset; // 存储触摸点击位置与物体实际位置的偏移量
private bool isDragging = false; // 标志位,表示物体是否正在被拖拽
void Update()
{
// 检测是否有触摸输入
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0); // 获取第一个触摸点
// 检测触摸开始
if (touch.phase == TouchPhase.Began)
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(touch.position); // 从摄像机发射一条射线到触摸位置
// 使用射线检测是否击中了某个物体
if (Physics.Raycast(ray, out hit))
{
// 检查被击中的物体是否是本脚本所附加的物体
if (hit.collider.gameObject == gameObject)
{
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position); // 将物体的世界坐标转换为屏幕坐标
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, screenPoint.z)); // 计算偏移量
isDragging = true; // 设置拖拽标志位为真
}
}
}
// 检测触摸移动并且物体正在被拖拽
if (touch.phase == TouchPhase.Moved && isDragging)
{
Vector3 curScreenPoint = new Vector3(touch.position.x, touch.position.y, screenPoint.z); // 获取当前触摸位置的屏幕坐标
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset; // 将屏幕坐标转换为世界坐标并加上偏移量
transform.position = curPosition; // 更新物体的位置
}
// 检测触摸结束
if (touch.phase == TouchPhase.Ended)
{
isDragging = false; // 设置拖拽标志位为假
}
}
}
}
这个脚本通过检测触摸输入来实现物体的拖拽功能。以下是详细的步骤解释:
-
变量声明:
-
screenPoint
:存储物体在屏幕上的位置。 -
offset
:存储触摸点击位置与物体实际位置的偏移量。 -
isDragging
:标志位,表示物体是否正在被拖拽。
-
-
Update方法:
-
检测是否有触摸输入(
Input.touchCount > 0
)。 -
获取第一个触摸点(
Touch touch = Input.GetTouch(0)
)。 -
检测触摸开始(
touch.phase == TouchPhase.Began
)。 -
如果触摸开始,从摄像机发射一条射线到触摸位置(
Camera.main.ScreenPointToRay(touch.position)
)。 -
使用射线检测是否击中了某个物体(
Physics.Raycast(ray, out hit)
)。 -
检查被击中的物体是否是本脚本所附加的物体(
hit.collider.gameObject == gameObject
)。 -
如果是,将物体的世界坐标转换为屏幕坐标(
Camera.main.WorldToScreenPoint(gameObject.transform.position)
),并计算偏移量(offset
)。 -
设置拖拽标志位为真(
isDragging = true
)。
-
-
拖拽逻辑:
-
检测触摸移动并且物体正在被拖拽(
touch.phase == TouchPhase.Moved && isDragging
)。 -
获取当前触摸位置的屏幕坐标(
curScreenPoint
)。 -
将屏幕坐标转换为世界坐标并加上偏移量(
curPosition
)。 -
更新物体的位置(
transform.position = curPosition
)。
-
-
释放逻辑:
-
检测触摸结束(
touch.phase == TouchPhase.Ended
)。 -
设置拖拽标志位为假(
isDragging = false
)。
-
第二种 全局脚本,所有有碰撞器的物体都可以被拖拽
using UnityEngine;
public class GlobalDragManager : MonoBehaviour
{
private GameObject draggedObject;
private Vector3 screenPoint;
private Vector3 offset;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
draggedObject = hit.collider.gameObject;
screenPoint = Camera.main.WorldToScreenPoint(draggedObject.transform.position);
offset = draggedObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
}
}
if (Input.GetMouseButton(0) && draggedObject != null)
{
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
draggedObject.transform.position = curPosition;
}
if (Input.GetMouseButtonUp(0))
{
draggedObject = null;
}
}
}
这个脚本的工作原理如下:
-
Update
方法:-
在每一帧中,检查是否按下了鼠标左键(
Input.GetMouseButtonDown(0)
)。 -
如果按下了鼠标左键,发射一条从主摄像机到鼠标位置的射线(
Physics.Raycast(ray, out hit)
)。 -
如果射线击中了某个物体(
hit.collider.gameObject
),则将该物体的引用存储在draggedObject
变量中,并记录物体的屏幕位置和偏移量。
-
-
拖动逻辑:
-
如果鼠标左键保持按下并且
draggedObject
不为空,根据当前鼠标位置计算物体的新位置(curPosition
),并将其应用到物体的变换位置上(draggedObject.transform.position = curPosition
)。
-
-
释放物体:
-
当鼠标左键释放时(
Input.GetMouseButtonUp(0)
),将draggedObject
设置为null
,表示没有物体正在被拖动。
-
通过这种方式,你只需要挂载一个脚本到场景中的某个空游戏对象上,就可以实现对所有带有碰撞器的物体的拖拽功能,而不需要为每个物体单独挂载脚本。
适用于移动端触摸屏交互的版本
using UnityEngine;
public class GlobalDragManager : MonoBehaviour
{
private GameObject draggedObject;
private Vector3 screenPoint;
private Vector3 offset;
void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(touch.position);
if (Physics.Raycast(ray, out hit))
{
draggedObject = hit.collider.gameObject;
screenPoint = Camera.main.WorldToScreenPoint(draggedObject.transform.position);
offset = draggedObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, screenPoint.z));
}
}
if (touch.phase == TouchPhase.Moved && draggedObject != null)
{
Vector3 curScreenPoint = new Vector3(touch.position.x, touch.position.y, screenPoint.z);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
draggedObject.transform.position = curPosition;
}
if (touch.phase == TouchPhase.Ended)
{
draggedObject = null;
}
}
}
}
这个脚本的工作原理如下:
-
Update
方法:-
在每一帧中,检查是否有触摸输入(
Input.touchCount > 0
)。 -
如果有触摸输入,获取第一个触摸点(
Touch touch = Input.GetTouch(0)
)。
-
-
触摸开始:
-
如果触摸开始(
touch.phase == TouchPhase.Began
),发射一条从主摄像机到触摸位置的射线(Physics.Raycast(ray, out hit)
)。 -
如果射线击中了某个物体(
hit.collider.gameObject
),则将该物体的引用存储在draggedObject
变量中,并记录物体的屏幕位置和偏移量。
-
-
触摸移动:
-
如果触摸移动(
touch.phase == TouchPhase.Moved
)并且draggedObject
不为空,根据当前触摸位置计算物体的新位置(curPosition
),并将其应用到物体的变换位置上(draggedObject.transform.position = curPosition
)。
-
-
触摸结束:
-
当触摸结束(
touch.phase == TouchPhase.Ended
),将draggedObject
设置为null
,表示没有物体正在被拖动。
-
通过这种方式,你可以在移动端触摸屏上实现对所有带有碰撞器的物体的拖拽功能,而不需要为每个物体单独挂载脚本。