Unity 默认Inspector支持的一些属性
[HideInInspector]:使用了该属性的变量不显示在inspector 但是被序列化。即不会显示,也不会被外部类调用。
[SerializeField]:将不会被序列化的非公共变量可以序列化,这么在下次读取时,就是上次赋值的值。
[ExecuteInEditMode()]:这个函数可以使代码在编辑模式下运行,不需要运行游戏;
[ExecuteInEditMode]: 编辑环境中该功能(类)生效,简单讲就是。不运行游戏。就可你让你的功能起作用,比如:NGUI中的Slider
[MenuItem(“”)]:导航条中加入自定义菜单。
[CustomEditor(typeof(EButton))]:绑定使用该类。必须依赖EButton类。
[RequireComponent (typeof (ClassName))]:添加该类时。自动会加入ClassName类。
[ContextMenu (“XXX”)]:加入Inspector面板右键菜单。点击执行该功能。
[AddComponentMenu(“XXX/XX/XXX”)]:菜单中出现定义的该类。
Unity3d 实现移动端的触摸屏操作-场景的缩放移动
通过Input.touchCount来判断触控点位,通过Input.GetTouch(0).phase来判断移动的类型。
其中phase(状态)有以下这几种:
Began:手指刚刚触摸屏幕
Moved:手指在屏幕上移动
Stationary:手指触摸屏幕,但自最后一阵没有移动
Ended:手指离开屏幕
Canceled:系统取消触控跟踪,原因如把设备放在脸上或同时超过5个触摸点
代码中主要用到的是TouchPhase.Began和TouchPhase.Moved。
完整代码如下,放置到主摄像机上即可:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MobileTouch : MonoBehaviour
{
//是否缩放
private bool IsZoom = false;
//当前双指触控间距
private float DoubleTouchCurrDis;
//过去双指触控间距
private float DoubleTouchLastDis;
//记录手指触碰的位置
Vector2 m_screenPos = new Vector2();
void Start()
{
}
void Update()
{
if ((Input.touchCount > 1) && (Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(1).phase == TouchPhase.Moved))
{
// 多点触控
Touch touch1 = Input.GetTouch(0);
Touch touch2 = Input.GetTouch(1);
DoubleTouchCurrDis = Vector2.Distance(touch1.position, touch2.position);
if (!IsZoom)
{
DoubleTouchLastDis = DoubleTouchCurrDis;
IsZoom = true;
}
float distance = DoubleTouchCurrDis - DoubleTouchLastDis;
Camera.main.fieldOfView += (distance > 0 ? -1 : 1) * 1;//更改了摄像头的高度
DoubleTouchLastDis = DoubleTouchCurrDis;
}
else if (Input.touchCount == 1)
{
// 单点移动
if (Input.touches[0].phase == TouchPhase.Began)
{
//记录手指刚触碰的位置
m_screenPos = Input.touches[0].position;
}
if (Input.touches[0].phase == TouchPhase.Moved) //手指在屏幕上移动,移动摄像机
{
transform.Translate(new Vector3(Input.touches[0].deltaPosition.x * Time.deltaTime * -1, Input.touches[0].deltaPosition.y * Time.deltaTime * -1, 0));
}
}
}
}
转:Unity相机跟随多种实现方式
转自:https://blog.csdn.net/qq_37310110/article/details/94007394
一:设置目标物为相机的父节点
描述:最简单,最基础,效果最不理想,锁死跟随视角
二:常规设置固定相对向量偏移
描述:推荐指数***,代码实现简,效果比较生硬
public Transform target;
private Vector3 offset;
void Start()
{
//设置相对偏移
offset = target.position - this.transform.position;
}
void Update()
{
//更新位置
this.transform.position = target.position - offset;
}
三:添加旋转角度
描述:推荐指数***,在二的基础上添加距离差值和旋转角度差值,效果流畅
private Vector3 offset;//相机相对于玩家的位置
public Transform target;
private Vector3 pos;
public float speed = 2;
private void Start()
{
offset = transform.position - target.position;
}
// Update is called once per frame
void Update()
{
pos = target.position + offset;
this.transform.position = Vector3.Lerp(transform.position, pos, speed * Time.deltaTime);//调整相机与玩家之间的距离
Quaternion angel = Quaternion.LookRotation(target.position - transform.position);//获取旋转角度
transform.rotation = Quaternion.Slerp(transform.rotation, angel, speed * Time.deltaTime);
}
四: 第三背后视角
描述:推荐指数*****,流畅参数可调。对相机的位置实时计算
public Transform target;
public float distanceUp = 10f;//相机与目标的竖直高度参数
public float distanceAway = 10f;//相机与目标的水平距离参数
public float smooth = 2f;//位置平滑移动插值参数值
public float camDepthSmooth = 20f;
void Update()
{
// 鼠标轴控制相机的远近
if ((Input.mouseScrollDelta.y < 0 && Camera.main.fieldOfView >= 3) || Input.mouseScrollDelta.y > 0 && Camera.main.fieldOfView <= 80)
{
Camera.main.fieldOfView += Input.mouseScrollDelta.y * camDepthSmooth * Time.deltaTime;
}
}
void LateUpdate()
{
//计算出相机的位置
Vector3 disPos = target.position + Vector3.up * distanceUp - target.forward * distanceAway;
transform.position = Vector3.Lerp(transform.position, disPos, Time.deltaTime * smooth);
//相机的角度
transform.LookAt(target.position);
}
五:自由 视角
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class target_control : MonoBehaviour {
public Transform _target;
public float distance = 50.0f;
public float xSpeed = 250.0f;
public float ySpeed = 120.0f;
public int yMinLimit = -20;
public int yMaxLimit = 80;
private bool orbit = false;
private bool pan = false;
private bool zoom = false;
private float zoomValue = 0;
public float orbitDampX = 0.0f;
public float orbitDampY = 0.0f;
float panDampX = 0.0f;
float panDampY = 0.0f;
public float zoomDamp = 0.0f;
public float dampingTime = 0.0f;
public float x = 180.0f;
public float y = 0.0f;
public int planFactor = 5;
public float zoomFactor = 2.0f;
public Vector2 distLimit;
public static Quaternion _rotation;
public static Vector3 _position;
public static target_control _target_control;
public float _z_distance;
private Vector3 angles;
private Vector2 oldPosition1;
private Vector2 oldPosition2;
public float _target_distance = 5;
private float target_x;
private float target_y;
private Vector3 _target_pos = Vector3.zero;
public bool change_distance()
{
distance = Mathf.Lerp(distance, _target_distance, 0.04f);
Debug.Log(distance + "/" + _target_distance);
updateCamera();
if (Mathf.Abs(distance - _target_distance) < 0.01f)
return false;
return true;
}
public bool change_distance(float _dis)
{
distance = Mathf.Lerp(distance, _dis, 0.004f);
updateCamera();
if (Mathf.Abs(distance - _dis) < 0.01f)
return false;
return true;
}
void Start()
{
_target_distance = distance;
_z_distance = distance;
angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
// Make the rigid body not change rotation
if (GetComponent<Rigidbody>())
GetComponent<Rigidbody>().freezeRotation = true;
}
// Update is called once per frame
void LateUpdate () {
if (EventSystem.current.IsPointerOverGameObject()||_target ==null)
{
return;
}
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
if (Input.touchCount == 1)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
orbit = true;
}
else
{
orbit = false;
}
}
else
{
orbit = false;
}
if (Input.touchCount > 1)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(1).phase == TouchPhase.Moved)
{
var tempPosition1 = Input.GetTouch(0).position;
var tempPosition2 = Input.GetTouch(1).position;
if (isEnlarge(oldPosition1, oldPosition2, tempPosition1, tempPosition2))
{
zoomValue = 0.1f;
zoom = true;
}
else
{
zoomValue = -0.1f;
zoom = true;
}
oldPosition1 = tempPosition1;
oldPosition2 = tempPosition2;
}
else
{
zoom = false;
}
}
else
{
zoom = false;
}
}
else if (Application.platform == RuntimePlatform.Android)
{
if (Input.touchCount == 1)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
orbit = true;
}
else
{
orbit = false;
}
}
else
{
orbit = false;
}
if (Input.touchCount > 1)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(1).phase == TouchPhase.Moved)
{
var tempPosition1 = Input.GetTouch(0).position;
var tempPosition2 = Input.GetTouch(1).position;
if (isEnlarge(oldPosition1, oldPosition2, tempPosition1, tempPosition2))
{
zoomValue = 0.1f;
zoom = true;
}
else
{
zoomValue = -0.1f;
zoom = true;
}
oldPosition1 = tempPosition1;
oldPosition2 = tempPosition2;
}
else
{
zoom = false;
}
}
else
{
zoom = false;
}
}
else
{
if (Input.GetMouseButton(1))
{
orbit = true;
}
else
{
orbit = false;
}
if (Input.GetAxisRaw("Mouse ScrollWheel") != null)
{
zoomValue = Input.GetAxisRaw("Mouse ScrollWheel");
zoom = true;
}
else
{
zoom = false;
}
}
if (orbit)
{
orbitDampX = Mathf.Lerp(orbitDampX, Input.GetAxis("Mouse X"), dampingTime * Time.deltaTime);
orbitDampY = Mathf.Lerp(orbitDampY, Input.GetAxis("Mouse Y"), dampingTime * Time.deltaTime);
}
else
{
orbitDampX = Mathf.Lerp(orbitDampX, 0, dampingTime * Time.deltaTime);
orbitDampY = Mathf.Lerp(orbitDampY, 0, dampingTime * Time.deltaTime);
}
if (zoom)
{
zoomDamp = Mathf.Lerp(zoomDamp, zoomValue, dampingTime * Time.deltaTime);
}
else
{
zoomDamp = Mathf.Lerp(zoomDamp, 0, dampingTime * Time.deltaTime);
}
if (!checkLerp(orbitDampX, 0) || !checkLerp(orbitDampY, 0))
{
doOrbit();
}
if (!checkLerp(zoomDamp, 0))
{
doZoom();
}
}
bool isEnlarge(Vector2 oP1,Vector2 oP2 , Vector2 nP1, Vector2 nP2 )
{
var leng1 =Mathf.Sqrt((oP1.x-oP2.x)*(oP1.x-oP2.x)+(oP1.y-oP2.y)*(oP1.y-oP2.y));
var leng2 =Mathf.Sqrt((nP1.x-nP2.x)*(nP1.x-nP2.x)+(nP1.y-nP2.y)*(nP1.y-nP2.y));
if(leng1<leng2)
{
//big
return true;
}else
{
//small
return false;
}
}
bool checkLerp(float a,float b)
{
if (Mathf.Approximately(a, b))
{
return true;
}
return false;
}
void doOrbit()
{
if (_target)
{
x += orbitDampX * xSpeed * 0.02f;
y -= orbitDampY * ySpeed * 0.02f;
y = ClampAngle(y, yMinLimit, yMaxLimit);
updateCamera();
}
}
void doZoom()
{
distance -= zoomDamp * zoomFactor;
distance = Mathf.Clamp(distance, -distLimit.x, distLimit.y);
updateCamera();
}
void updateCamera()
{
var rotation = Quaternion.Euler(y, x, 0);
var position = rotation * new Vector3(0.0f, 0.0f, -distance) + _target.position;
transform.rotation = rotation;
transform.position = position;
}
static float ClampAngle (float angle,float min,float max)
{
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp(angle, min, max);
}
}
关于 “SetDestination can only be called on an active agent that has been placed on a NavMesh” 真正的解决方案
最近碰到了 "SetDestination can only be called on an active agent that has been placed on a NavMesh" 的问题,关键点不在于不会用Navmesh,而是真的他就这么报错了。
找了很多办法,耗时1天,终于在国外论坛上看到真正的解决方案了。
常规解决方案:
- 检查场景是否烘焙。
- 检查目标或自己是否位于navmesh上,不是在半空。
- 尝试使用NavMesh.SamplePosition方法。
GameObject go = new GameObject("Target");
Vector3 sourcePostion = new Vector3( 100, 20, 100 );//The position you want to place your agent
NavMeshHit closestHit;
if( NavMesh.SamplePosition( sourcePostion, out closestHit, 500, 1 ) ){
go.transform.position = closestHit.position;
go.AddComponent<NavMeshAgent>();
//TODO
}
else{
Debug.Log("...");
}
如果常规方法没解决,且寻路是时好时坏,对象和自己均是代码生成的,那八九不离十肯定碰到了我碰到的问题。
解决方法很简单:
在prefab里就添加了NavMeshAgent组件的,把他勾掉,然后在物体的start里面agent.enabled = true;
如果是在awake代码生成的,AddComponent后把enabled设置成false,然后在物体的start里面agent.enabled = true;
示例:
void Awake () {
// 添加寻路组件
agent = this.gameObject.AddComponent<NavMeshAgent> ();
agent.speed = 3.5f;
agent.enabled = false;
// ...
}
// Use this for initialization
void Start () {
agent.enabled = true;
}
Updating Homebrew… 一直卡住怎么处理?
brew install安装一个东西,然后突然 Updating Homebrew... 卡住了,之前一直公司网好像不卡,现在疫情在自己家,它居然能卡着完全不动。。。
那我就把它换个源吧~ ,换成 aliyun 的源。
替换 / 还原 brew.git 仓库地址
替换成阿里巴巴的 brew.git 仓库地址:
cd "$(brew --repo)"
git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git
=======================================================
还原为官方提供的 brew.git 仓库地址
cd "$(brew --repo)"
git remote set-url origin https://github.com/Homebrew/brew.git
替换 / 还原 homebrew-core.git 仓库地址
替换成阿里巴巴的 homebrew-core.git 仓库地址:
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git
=======================================================
还原为官方提供的 homebrew-core.git 仓库地址
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://github.com/Homebrew/homebrew-core.git
替换 / 还原 homebrew-bottles 访问地址
这个步骤跟你的 macOS 系统使用的 shell 版本有关系
所以,先来查看当前使用的 shell 版本
echo $SHELL
- 如果你的输出结果是 /bin/zsh,参考?的 zsh 终端操作方式
- 如果你的输出结果是 /bin/bash,参考?的 bash 终端操作方式
zsh 终端操作方式
替换成阿里巴巴的 homebrew-bottles 访问地址:
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrc
source ~/.zshrc
=======================================================
还原为官方提供的 homebrew-bottles 访问地址
vi ~/.zshrc
然后,删除 HOMEBREW_BOTTLE_DOMAIN 这一行配置
source ~/.zshrc
bash 终端操作方式
替换 homebrew-bottles 访问 URL:
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.bash_profile
source ~/.bash_profile
=======================================================
还原为官方提供的 homebrew-bottles 访问地址
vi ~/.bash_profile
然后,删除 HOMEBREW_BOTTLE_DOMAIN 这一行配置
source ~/.bash_profile