1.协程
协程并不会在Unity中开辟新的线程来执行,其执行仍然发生在主线程中。当我们有较为耗时的操作时,可以将该操作分散到几帧或者几秒内完成,而不用在一帧内等这个操作完成后再执行其他操作。
如我们需要执行一个循环:
IEnumerator CaculateResult()
{
for (int i = 0; i < 10000; i++)
{
//内部循环计算
//在这里的yield会让改内部循环计算每帧执行一次,而不会等待10000次循环结束后再跳出
//yield return null;
}
//如果取消内部的yield操作,仅在for循环外边写yield操作,则会执行完10000次循环后再结束,相当于直接调用了一个函数,而非协程。
//yield return null;
}
协成里的for是把值类型引用化。迭代器局部变量保存再堆上
【注意】
1> 使用WaitForFiexdUpdate类暂停的时间取决于Unity编辑器中的TimeManager的FixedTimestep.TimeScale也是取决于FixedTimestep。
2>WaitForEndOfFrame 用来处理等待帧结束,再恢复执行的代码。作用是等所有的Camera和GUI渲染完成后,再恢复携程的执行。eg:截屏
协程背后的秘密:迭代器
执行:
1>迭代器调用MoveNext() ==> 遇到yield return语句。此时迭代器获取当前的值 ”start“,并且返回true以告诉还有数据。
2>Main使用当前枚举器中的Current属性获取数据并且打印。
3> Main再次调用MoveNext()方法。
4>迭代器再次从上次暂停的yield return的地方开始执行。。。
5>知道MoveNext(0方法返回false.告知没有数据
IEnumerator枚举器详说:【反编译后】
1》创建state【用来标识迭代器状态】和current【标识当前的值】字段。
2》构造函数中初始化标识迭代器的状态state=0。
3》MoveNext(),内部是状态机+goto跳转
IEnumerable
10.12 根据屏幕点击,3D物体位置同步
关于unity Camera.main.ScreenToWorldPoint( Input.mousePosition);
正确: Vector3 _current2= Camera.main.ScreenToWorldPoint(( new Vector3( Input.mousePosition.x, Input.mousePosition.y, 10.0f))); //当z=0时,2D的点转换后的还是一个2D的点【透视】 正交模式下是可以的【正交是2D面转3D面】
//根据鼠标点击屏幕获取点,来移动3D到此点击的位置
//给3D物体添加RectTransform组件
RectTransform currentBoardRect = cube.GetComponent();
Vector3 vecWord = Vector3.zero;
RectTransformUtility.ScreenPointToWorldPointInRectangle(currentBoardRect, Input.mousePosition, Camera.main, out vecWord);
cube.transform.position = vecWord;
11.unity3D场景加载方式的优化
https://www.cnblogs.com/llguanli/p/6824304.html
(1)自己写个场景管理来加载xml或者json ,合并海量场景预制体
https://www.cnblogs.com/alongu3d/p/3192499.html
(2)分割加载,场景中公共的资源或对象放在一个关卡中,把属于某一个独一无二的对象放在某一个关卡中
http://luminesca.blogspot.com/2013/05/sublevels.html
(3)移动式加载,背景移动,
12. 材质贴图缩放和偏移量之间的关系,贴图受缩放影响时,则 tiling+offset=0.5f
//Tiling 显示框的缩放量 offset 是纹理的偏移
offset 是显示框的偏移量
1)拿flappy bird素材来说,起始状态是这样的↓,
注意显示框(黄色),它包括的范围是这样的↓
2)当offset_x设置为0.5的时候,显示框(黄色)包括的范围应该是这样的↓
offset_x设置为0.5的结果状态是这样的↓
3)当offset_x设置为0.8的时候,显示框(黄色)包括的范围是这样的↓
offset_x设置为0.8的结果状态是这样的↓
所以说,offset是显示框的偏移量
Tiling是显示框的缩放量
1)为做对比,再看一次原始的时候↓
2)tiling_x=0.5的时候,显示框(黄色)包括的范围应该是这样的↓
实际显示效果↓(图片也被横向的拉伸了)
3)tiling_x=0.3的时候,显示框(黄色)包括的范围是这样的↓
实际显示效果↓
(对比下tiling_x=0.5, offset=0.5和tiling_x=1, offset=0.5时的区别,前者要“胖”些,这是因为显示框的大小不同导致的)
1.找出5个点中,找出任意两点距离大于1的算法
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class TestNearPoint : MonoBehaviour {
private List _listStar = new List();
private int _rangle=1;
void Start ()
{
_listStar.Add(new Vector3(0,0));
_listStar.Add(new Vector3(0, 1));
_listStar.Add(new Vector3(2, 2));
_listStar.Add(new Vector3(0, 3));
_listStar.Add(new Vector3(1, 0));
_listStar.Add(new Vector3(2, 0));
_listStar.Add(new Vector3(4, 1));
_listStar.Add(new Vector3(6, 6));
_listStar.Add(new Vector3(4, 9));
List _listDif = new List();
for (int row = 0; row < _listStar.Count; row++)
{
for (int cow = 0; cow < _listStar.Count; cow++)
{
if (Vector3.Distance(_listStar[row], _listStar[cow]) > _rangle)
{
}
else
{
_listStar[cow] = _listStar[row];
if (_listDif.Contains(_listStar[cow]) == false)
{
_listDif.Add(_listStar[cow]);
}
}
}
}
for (int row = 0; row < _listDif.Count; row++)
{
Debug.LogError(_listDif[row]);
}
}
}
Animator 倒播
///
/// 倒播
///
public void SetBackPlay_CurrentAnimator(AnimatorInfo _AniInfo)
{
if (GetCurrentPlayingAnimationClip(currentAnimator) !=null)
{
_currentFram -= Time.deltaTime * 0.5f;
currentAnimator.Play(GetCurrentPlayingAnimationClip(currentAnimator), 0, _currentFram);
}
}
///
/// 获取当前的动画
///
public string GetCurrentPlayingAnimationClip(Animator _currentAnimator)
{
if (_currentAnimator == null)
{
return string.Empty;
}
for (int row = 0; row < _currentAnimator.runtimeAnimatorController.animationClips.Length; row++)
{
if (_currentAnimator.GetCurrentAnimatorStateInfo(0).IsName(_currentAnimator.runtimeAnimatorController.animationClips[row].name))
{
return _currentAnimator.runtimeAnimatorController.animationClips[row].name;
}
}
return string.Empty;
}
}
/洗牌算法
随机一个Index,把该index对应的值和当前遍历到的i对应的值进行互换。
Vector3 temp = new Vector3();
int index0;
for (int i = 1; i < _listPositionInfo.Count; i++) //洗牌算法
{
index0 = Random.Range(0, (_listPositionInfo.Count - 1));
temp = _listPositionInfo[index0];
_listPositionInfo[index0] = _listPositionInfo[i];
_listPositionInfo[i] = temp;
}
Physics.Raycast 理解
方法原型与参数说明
其实这个函数有个很藏的很深的地方就是这个layermask, 一般情况我们获取layer的值都会是layermask.nametolayer 这个函数去取得对应的层级,然后把这个int形的参数给到函数使用。但是如果是使用了Physics.Raycast去获取碰撞物的时候,你怎么都获取不到被碰撞的物体。(即使你划线来表示你的射线,也会觉得好像没有任何问题)
最后在unity的官方上找到了说明
Casting Rays Selectively
Using layers you can cast rays and ignore colliders in specific layers. For example you might want to cast a ray only against the player layer and ignore all other colliders.
The Physics.Raycast function takes a bitmask, where each bit determines if a layer will be ignored or not. If all bits in the layerMask are on, we will collide against all colliders. If the layerMask = 0, we will never find any collisions with the ray.
上面说明了一个问题就是,这个值如果是使用物理来进行碰撞的时候是使用的位移操作来进行的,也就是这里的layermask获得的值还要进行位移
第一种情况:表示在第8层上检查碰撞信息
int layerMask = 1 << 8;
(Physics.Raycast(transform.position, Vector3.forward, Mathf.Infinity, layerMask)) Debug.Log("The ray hit the player");
第二种情况:除了第几层其他接受碰撞射线的检查则可以使用下面的方法
int layerMask = 1 << 8;
layerMask = ~layerMask;
Unity 纹理,动画,网格加载分析及优化技巧
https://blog.csdn.net/zphshiwo/article/details/80742976
一个向量旋转angle角度:
Vector3 oldVec=new Vector3();
Vector2 newVec = Quaternion.AngleAxis(angle, Vector3.back) *oldVec;
angle:旋转度数 axis:围绕哪个轴旋转 oriVec:初始向量 oldVec: 要旋转的向量
1.热跟新无法在ios平台实现的原因?
热跟新无法在ios热更的原因并不是ios禁止了JIT编译这种方式。而是苹果处于安全考虑,在ios中封存了内存(或者堆)的可执行权限(PROT_EXEC)。相当于变相的封锁了JIT编译方式。
2.如果对带有相同EdgeColider不产生碰撞,则给其中一个添加SufaceEffector2D,并且使用Colider Mask来屏蔽不想交互的层
3.协程深入研究
(1)开始时迭代器调用MoveNext(),当遇到一个yield reture语句。此时迭代器会获取当前的值,MoveNext的返回值是true(告知还有数据)
(2)使用Current属性获取数据。
(3)再次调用MoveNext()【从上次暂停的(yield reture)的地方开始】,直到返回时false(告知没有数据)
(4)上面代码中i是值类型,但是值其实在保存在堆上的,这样才能保存每次调用MoveNext()时i的值时可用的(而不是又从1开始),说明了迭代器中的局部变量会分配在堆上的原因。
委托深入理解:其实就是一个包装器
协变性: 描述的是返回值类型,简单来说就是绑定在委托上的函数的 返回类型 可以是培生自 委托的返回类型。
逆变性: 描述的是委托的参数类型,简单来说就是绑定在委托上的函数的 参数类型 可以是委托的 参数类型的基类
备注:值类型和void以上都不适用
所有的委托类型都继承自:System,MulticastDelegate MulticastDelegate继承Delegate.
protected MulticastDelegate(object target, string method); //委托实例化的对象 , 和要调用的方法
委托是反编译后是一个完整的类,在可以定义类的地方就可以定义委托。委托对象实际上都是一个包装了方法和调用该方法时要操作的对象的包装器 target【当前类的实例】 method【当前操作的函数】 invocationList【调用列表】
内部结构:
(2)调用多个方法
后边发展了+
事件:
无论申明事件成员时使用的访问修饰符是什么,编辑器最终将该字段申明为private,和委托链一样
匿名方法:
编辑器为源码中的每一个方法创建了一个对应的方法,采用了和创建委托实例时同样的操作
unity中计算正切:
double val = Math.Atan2(_JumpInfo._DisDown, _JumpInfo._DisLeft); // 在坐标轴第一象限中,则 y=对边【参数1】 x=邻边 【参数2】
val = val * 180 / Math.PI;【将val弧度转成角度】
Multiple plugins with the same name 'avprovideo' (found at 'Assets/CoreLibrary/Plugins/WSA/PhoneSDK81/x86/AVProVideo.dll' and 'Assets/CoreLibrary/Plugins/x86_64/AVProVideo.dll'). That means one or more plugins are set to be compatible with Editor. Only one plugin at the time can be used by Editor.
查找:是unity 中DLL重复引用,不能兼容,根据自己的unity版本,如果是64为,则保存x86_x64的DLL,其他的删除掉,可解决
2018.5.11
今天windows跟新后,一直开不了机,重设系统后,导致c盘有的dll丢失了,应用程序打不开,缺少msvcr100.dll,网上查资料,下载了后,放到了指定位置,但是任然有问题,最简单的方法是使用DirectX修复工具来全部检查,修复。此链接https://pan.baidu.com/s/1nvIYAvB,无脑安装,修复即可
2018.2.14
在序列化结构体时,结构体中如果有数组,则报异常:类型GoPosion不能被编组为一个非托管结构
ArgumentException: Type GoPosion cannot be marshaled as an unmanaged structure.
Parameter name: t
System.Runtime.Inter
争论异常:类型GoPosion不能被编组为一个非托管结构。
解决方案:给数组加属性: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)],参考链接http://www.codes51.com/itwd/4119330_2.html
2018.5.6
转一个常见unity问题 解决链接:http://www.xuebuyuan.com/zh-hant/2105551.html
2.18.6.11
解决办法:
在开始调用UDPClient的Receive方法之前对UDPClient.Available属性进行判断,当Available属性大于0时才开始从缓冲区读取网络数据:
public void UDPReciveMore()
{
try
{
while (IsClose) //远程主机不是关闭状态,才进入到while中
{
if (clientRec.Available <= 0) { continue; }
byte[] buf = clientRec.Receive(ref endpointRec);
ReceiveCallBackUDPMore(buf.Length, ref buf);//ReceiveCallBackUDPMore
}
}
catch (Exception e)
{
Debug.LogError("异常: " + e);
}
}
原因:MSDN对Available的解释是:
“Available 属性用于确定在网络缓冲区中排队等待读取的数据的量。 如果有数据可用,可调用 Read 获取数据。 如果无数据可用,则 Available 属性返回 0。
如果远程主机处于关机状态或关闭了连接,则 Available 属性将引发SocketException。如果远程主机处于关机状态或关闭了连接,则 Available 属性将引发SocketException”。
也就是说,错误的原因在于,在调用Close后,线程恰好继续向网络缓冲区中读取数据,所以引发SocketException。
错误文档: 点击打开链接
2018.6.11
git clone操作出现fatal:index-pack failed错误解决方案
该错误是因为当前clone文件夹的属性为“只读”,无法写入。
解决方案:将文件夹属性“只读”取消。
unity 使用Grid Layout Group时,打包除出去不显示内部的text,则把自适应选上
2017.7.17
unity 调用c++ Dll
问题: 打包出去后找不到对应的Dll了,
解决: 包打包是64位,则修改unity的打包设置为86*64 ,再打包。
2019.3.26 Unity中脚本A引用不了脚本B的命名空间的情况?
解决: 如果导入的是Dll,则放在Plugins下,如果是自己写的脚本,则放在要引用的脚本下边。
http://imweirui.com/blog/2017/12/13/%E9%85%8D%E7%BD%AEunity2017%E5%92%8Cvs2015%E4%BD%BF%E7%94%A8c-6-0/
2019.3.29
end = transform.TransformPoint(end);是子物体和父物体之间的转换。
vecWorld= transform.TransformPoint(vecModle); //模型坐标到世界坐标
byte[] by = data.Skip(12).Take(8).ToArray(); //data数组从12位开始取8个给by
2019.4.24
Unity Rigidbody2D 添加一个力后,又完全清除掉力,且只是去掉了添加的力度的影响,也可以避免力的叠加问题?
GetComponent
GetComponent
FairyGUI - 超强UI编辑器,跨平台开源UI解决方案
简介: http://www.fairygui.com/guide/
案例 http://www.sikiedu.com/course/139/tasks(UI编辑器入门)
http://www.sikiedu.com/course/170/tasks(狼人杀)
Unity事件系统
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class EventTriggerListener : UnityEngine.EventSystems.EventTrigger
{
public delegate void EventTriggerDelegate(GameObject go);
public EventTriggerDelegate onClick;
public EventTriggerDelegate onDown;
public EventTriggerDelegate onEnter;
public EventTriggerDelegate onExit;
public EventTriggerDelegate onUp;
///
/// 获取事件监听者
///
public static EventTriggerListener Get(GameObject go)
{
EventTriggerListener listener = go.GetComponent();
if (listener == null)
{
listener = go.AddComponent();
}
return listener;
}
public override void OnPointerClick(PointerEventData eventData)
{
if (onClick != null)
{
onClick(gameObject);
}
}
public override void OnPointerDown(PointerEventData eventData)
{
if (onDown != null)
{
onDown(gameObject);
}
}
public override void OnPointerEnter(PointerEventData eventData)
{
if (onEnter != null)
{
onEnter(gameObject);
}
}
public override void OnPointerExit(PointerEventData eventData)
{
if (onExit != null)
{
onExit(gameObject);
}
}
public override void OnPointerUp(PointerEventData eventData)
{
if (onUp != null)
{
onUp(gameObject);
}
}
}
using Robots.Const.String;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
///
/// 大厅主页事件回调
///
public class MainSenceEventHandle : MonoBehaviour {
public Button btn_LeaveGame;
public Button btn_Fight;
public Button btn_Cooperation;
public Button btn_Ralaxation;
public Button btn_Explain;
public Button btn_ExplainLeave;
///
/// 过度画面
///
public Transform img_CutScene;
private AsyncOperation async;
private float progressValue;
public Slider slider;
public Text text;
private void Start()
{
EventTriggerListener.Get(btn_LeaveGame.gameObject).onClick = OnClick_Home_Leave;
EventTriggerListener.Get(btn_Fight.gameObject).onClick = OnClick_Home_Fight;
EventTriggerListener.Get(btn_Cooperation.gameObject).onClick = OnClick_Home_Cooperation;
EventTriggerListener.Get(btn_Ralaxation.gameObject).onClick = OnClick_Home_Ralaxation;
EventTriggerListener.Get(btn_Explain.gameObject).onClick = OnClick_Home_Explain;
EventTriggerListener.Get(btn_ExplainLeave.gameObject).onClick = OnClick_Home_ExplainLeave;
}
private void OnClick_Home_Leave(GameObject go)
{
Debug.LogError("点击 离开游戏 " + go.name);
Application.Quit();
}
private void OnClick_Home_Fight(GameObject go)
{
Debug.LogError("点击 进行对战 " + go.name);
Set_CutSenceRobots(enGameStyle.Fight);
AgainGameInit();
}
private void OnClick_Home_Cooperation(GameObject go)
{
Debug.LogError("点击 进入合作 " + go.name);
Set_CutSenceRobots(enGameStyle.Cooperration);
AgainGameInit();
}
private void OnClick_Home_Ralaxation(GameObject go)
{
Debug.LogError("点击 进入休闲 " + go.name);
Set_CutSenceRobots(enGameStyle.Ralaxation);
AgainGameInit();
}
private void OnClick_Home_Explain(GameObject go)
{
Debug.LogError("点击 进入说明 " + go.name);
btn_Explain.transform.GetChild(0).localScale = Vector2.one;
}
private void OnClick_Home_ExplainLeave(GameObject go)
{
Debug.LogError("点击 离开游戏说明 " + go.name);
btn_Explain.transform.GetChild(0).localScale = Vector2.zero;
}
///
///
///
///
private void Set_CutSenceRobots(enGameStyle enGOStyle)
{
img_CutScene.localScale = Vector2.one;
//展示机器人
//设置GameSence中的配置数据 UI布局
GameGloble.current.EnCurrentGoStyle = enGOStyle;
GameGloble.current.CurrentNum = Random.Range(1, 6);
if (GameGloble.current.CurrentNum == 1)
{
SetGameRobots(Tags.PlayerTag_Jar, Tags.PlayerTag_Octopus);
}
else if (GameGloble.current.CurrentNum == 2)
{
SetGameRobots(Tags.PlayerTag_Jar, Tags.PlayerTag_OilDrum);
}
else if (GameGloble.current.CurrentNum == 3)
{
SetGameRobots(Tags.PlayerTag_Radio, Tags.PlayerTag_Octopus);
}
else if (GameGloble.current.CurrentNum == 4)
{
SetGameRobots(Tags.PlayerTag_Radio, Tags.PlayerTag_OilDrum);
}
else if (GameGloble.current.CurrentNum == 5)
{
SetGameRobots(Tags.PlayerTag_Radio, Tags.PlayerTag_OilDrum);
}
StartCoroutine(LodeSence());
}
///
/// 设置上场的机器人
///
///
///
private void SetGameRobots(string tag1,string tag2)
{
for (int row = 0; row < img_CutScene.GetChildCount(); row++)
{
if (img_CutScene.GetChild(row).CompareTag(tag1))
{
img_CutScene.GetChild(row).gameObject.SetActive(true);
img_CutScene.GetChild(row).localPosition = new Vector3(360, 0);
}
if (img_CutScene.GetChild(row).CompareTag(tag2))
{
img_CutScene.GetChild(row).gameObject.SetActive(true);
img_CutScene.GetChild(row).localPosition = new Vector3(-360, 0);
}
}
}
private IEnumerator LodeSence()
{
yield return new WaitForSeconds(1);
async = SceneManager.LoadSceneAsync("GameSence");
async.allowSceneActivation = false;
while (!async.isDone)
{
if (async.progress < 0.9f)
{ progressValue = async.progress; }
else { progressValue = 1; }
slider.value = progressValue;
progressValue = (int)(slider.value * 100);
text.text = progressValue + " %";
if (progressValue >= 0.9f)
{
progressValue += Time.deltaTime;
}
if (progressValue >= 1)
{
async.allowSceneActivation = true;
}
yield return null;
}
}
///
/// 再一次开始游戏初始化
///
public void AgainGameInit()
{
GameDataInfo.isGameEnd = false;
GameDataInfo.isGameTimeEnd = false;
GameDataInfo.isRotateFactory = false;
UnitAllData_Control.InitClearDic();
GameGloble.current.CurrentPlayerFactoryA = null;
GameGloble.current.CurrentPlayerFactoryB = null;
GameDataInfo.Count_A = 0;
GameDataInfo.Count_B = 0;
}
}
在ScreenSpace-Camera模式和ScreenSpace-Overlay 模式下都可以使用。而直接使用GameObject.Find("Image").transform.position = Input.mousePosition;方式,则会由深度数值不正确而引发的问题。
对于在canvas下的物件,相机模式是透视的,则要以这种方式来转换的:这种方式避免了深度数据不正确引发的问题
Vector3 vecWord = Vector3.zero;
RectTransformUtility.ScreenPointToWorldPointInRectangle(GameObject.Find("Image").GetComponent(), Input.mousePosition, Camera.main, out vecWord);
GameObject.Find("Image").transform.position = vecWord;
anchoredPosition 和 Position的区别:
已知 e.Position 是触摸或点击事件提供的屏幕坐标(Vector2),Canvas 设置为 Screen Space - Overlay。
如果屏幕是 iPhone7 的大小 667x375,那么点在最右下角的时候,e.Position 的值就是(667, 375)。
如果把按钮的 RectTransform.position 赋值为 e.Position,就能把这个按钮放在屏幕右下角 (667, 375)位置。
如果把按钮的 RectTransform.anchoredPosition 赋值为 e.Position,那么按钮会在哪里取决于 anchor 的位置(参见下图):
如果 anchor 在左上角(0, 0),那么相对 anchor 设置坐标为 (0, 0) + (667, 375) = (667, 375)
如果anchor在右下角(667, 375),那么相对 anchor 设置坐标为 (667, 375) + (667, 375) = (1334, 750),设置到屏幕外了。
其他情况类推。
position 的原点是 Canvas 屏幕空间的原点, anchoredPosition 的原点是元素本身的 anchor。
localposition和position以及模型自身的坐标 区别:
局部坐标,有父物体时时相对于父物体的坐标,没有父物体则和position一样。
孙子层级物体相对爷爷层级物体的坐标;
//其实=孙子层级(x,y,z)+爷爷层级(x,y,z)
Vector3 vec = 爷爷层级.transform.InverseTransformPoint(孙子层级.transform.position);
模型自身的坐标: transform.up 获取的是模型自身的坐标 此时代表是模型本地坐标。
/求: /在A物体下的物体B,放到另一个物体下作为子物体时的坐标:
先算出B的世界坐标,再把世界坐标转为target的目标坐标。
//transform 是B物体,A是B的父物体
//B的世界坐标
Vector3 point = transform.parent.localToWorldMatrix.MultiplyPoint(transform.localPosition);
Debug.Log(point);
//B的世界坐标转换到target的物体下的局部坐标
Vector3 targetPos = target.transform.worldToLocalMatrix.MultiplyPoint(point);
Debug.Log(targetPos);
unity_左手坐标系:
大拇指永远指向是x轴。
Unity不要使用缩放
统一缩放的物体不会和非统一缩放的物体一起批处理
Unity中最好不要使用Linq:
Edit -> Graphics Emulation
调为 no Emulation
https://answers.unity.com/questions/778626/mathfacos-1-return-nan.html
ACos仅为-1和1之间的输入值范围定义。我怀疑结果是由Vector3.Dot返回的。点有时会稍微超出这个范围(即使您的输入向量是标准化的),因为计算不精确-当四舍五入为“-1”时,它仍然可能被打印出来。
Unity常见问题总结:
https://answers.unity.com/index.html
Vector3 vec = current - (Vector3)listVecTest[count];
//取屏幕的原点的Y向量作为参照向量,计算画的线的前后两帧连线和参照向量的夹角。
Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector2(0,0));
worldPos = new Vector3(worldPos.x, worldPos.y,0);
Vector3 vecStart = new Vector3(worldPos.x, worldPos.y, 0)- new Vector3( worldPos.x, worldPos.y+5, 0);
Debug.DrawLine(current, (Vector3)listVecTest[count], Color.green, 5);
Debug.DrawLine(new Vector3(worldPos.x, worldPos.y, 0), new Vector3(worldPos.x, worldPos.y + 5, 0), Color.red, 5);
Vector3 crossVec= Vector3.Cross(vec, vecStart);
float angle = Vector3.Angle(vec, vecStart);
if (crossVec.z > 0)//右手法则,z>0,顺时针旋转
{
Debug.Log("Clockwise Angle " + angle);
playerTest.transform.eulerAngles = new Vector3(0, 0, 90 - angle);
}
else if (crossVec.z == 0)
{
Debug.Log(" Angle "+ angle);//+90 或者 -90
if (angle == 90)
{
playerTest.transform.eulerAngles = new Vector3(0, 0, 90);
}
else if (angle == 180)
{
playerTest.transform.eulerAngles = new Vector3(0, 0, -90);
}
}
else if (crossVec.z < 0)
{
Debug.Log("Antclockwise Angle " + angle); // angle+ 90
playerTest.transform.eulerAngles = new Vector3(0, 0, angle + 90);
}
unity绘制线:
Debug.DrawLine(startPoint, endPoint, Color.red); //绘制两个点之间的线
Debug.DrawRay(startPoint, direct, Color.yellow); //知道一个点和方向绘制线
Step Offset must be less or equal to + * 2
今天实例化一个prefab时,各种报上面这个错。开始以为是实例化prefab传参的问题。
后来发现是因为prefab上挂的Character controller组件导致的,组件上的默认参数,不符合上面报错的要求,修改下就好了。
主要是类似问题网上没有提供解决方法的,写篇博客记录下吧。希望能帮到其他人。
发现父物体的缩放是0.
Unity AssetStore 上下载的插件保存位置路径:
C:\Users\WangYanJie\AppData\Roaming\Unity\Asset Store
点开
Edit / Project Setting / Physics
如下图所示,
给 该Character Controller 所在的对象设置 Layer, 同时取消勾选
Layer 与 Layer 在矩阵 中的 钩, 即可 设置 该 Character Controller 之间不发生不想碰撞
Sprite的阴影问题: drawPlanePar.GetComponent
Rigidbody2D想要是否适用物理学:不要使用isTrigger来设置,最好使用simulated来设置,因为使用simulated比较及时。
勾选CircleCollider2D中的isTrigger=true; 或者激活和触发CircleCollider2D组件,但是都相应比较慢。
通过修改Rigidbody2D中的simulated来是否需要模拟物理学相应比较快。
设置宏定义
菜单:File / Build Settings / Player Settings / Other Settings / Configuration / Scripting Define Symbols
多个宏用分号隔开
#if MY_DEFINE1
Debug.Log("Hello wrold");
#endif
位运算:
方法:n<>1;
可利用右移运算符计算a的第b个二进制位是什么?
(a>>b)&1;
使用OpenCV做简单图形的识别:
方式一:分水岭算法
分水岭算法:
分水岭算法产生的过度分割问题:1. 是利用先验知识去除无关边缘信息 。2. 是修改梯度函数使得集水盆只响应想要探测的目标。当两个水盆聚汇合处构筑大坝,即形成分水岭,把图像分割出来。
如果背景颜色和要比较的图不在灰度上,而是在纹理上,则把纹理的颜色分割出来,设置自动阀值,分割出图像,对图像轮廓点进行多边形拟合,对比顶点个数,优先使用二值法,不行了再考虑这种方法,这种方法误差较大。【分水岭算法提取轮廓】
方式二:模板法
这种方式必须背景颜色为纯色,而且背景不能杂七杂八的东西
差别特征转换为灰度的差别,然后利用阈值选取技术来分割该图像,动态调节阈值实现图像的二值化可动态观察其分割图像的具体结果。一般用在背景是同一种颜色时,如果背景含有多种颜色,则不行
应用: 先制作模板:在透明图片上画画,保存图片,和模板进行比较。
模板一定要是纯色,且图形鲜明,对不是纯色的模板,则需要用方法一做。
下图左侧为模板,右侧为比较后的:
步骤:
<1. 图片颜色模式转换,转为灰度图
<2. 图片高斯模糊处理 ,使得内部有均匀一致的灰度值,而且此图片的背景是在其他等级灰度值的均匀背景.
<3. 图片二值化处理 特征转换为灰度的差别,再利用阀值进行分离背景
基本思想是:
<1. 设置UI缩放模式,为根据屏幕来缩放
<2. 设置Canvas尺寸
<3. 在unity中是基于1280*720屏幕分辨率制作的UI尺寸。
<4.把高度定死,即以屏幕高度为目标高度。改变宽度来自适应。
<5. 因为标准的是16:9,所以计算出异设备上显示全 所需要的理论宽度W-deice。
<6. 异设备的宽度 / 理论宽度W-deice 计算出从理论到实际宽度所需要的 缩放比。高度不变是定死的
//设备理论宽度
public int devWidth;
//设备宽/理论需要宽 = 实际在设备上的宽度值
public float valueWidth;
void Awake ()
{
//比率,unity中创建UI时的宽度是比率是1.77=1280/720,如果打包到设备上设备比率不等于1.77,则需要改变宽度(因为高度是定死了的)
float screenRetio = ((float)devWidth / Screen.height);
if (screenRetio != 1.77) //如果不是16/9时,则需要对宽度进行缩放,重新计算再设备上的画布的宽度,使之满足16:9
{
//设备上画布的宽度
devWidth = (int)(Screen.height * 16f / 9f); //devWidth /16 = Screen.height/9
}
valueWidth = Screen.width * 1.00f / devWidth; //设备上宽度变了后,则不再是 Screen.width,而是valueWidth
}
https://blog.csdn.net/leosheldon/article/details/79055307
说明:我们创建的txt默认是没有设置BOM(Byte Order Mark)。
如果需要设置BOM,则使用UltraEdit.exe来另存为设置为带有BOM的格式。
从一点需要向两边移动时:需要乘以2
float targetValue = 8;
void Update()
{
float posX = Mathf.PingPong(Time.time, targetValue * 2); //-8 8
Vector3 movePos = new Vector3(posX- 16*0.5f, this.transform.localPosition.y);
this.transform.localPosition = movePos;
}
https://blog.csdn.net/narutojzm1/article/details/51291008
Camera 的clear flag = depth only
<1. 丢弃三维位置信息;
<2. 多摄像机时会遮挡depth较小的物体
<3. 简单来说: 只受camera中的depth影响,不受位置影响.
//UICamera下的局部坐标
btnLocalPos = GameObject.Find("btn_function").transform.localPosition;
//<1.UICamera下的世界坐标
btnWord = GameObject.Find("btn_function").transform.position;
//<2.
btnSreen = UICamera.currentCamera.WorldToScreenPoint(btnWord);
btnSreenWord = UICamera.currentCamera.ScreenToWorldPoint(btnSreen);
//UICamera下的屏幕坐标 转为 Camera.main下的世界坐标
btnWordCam3D = Camera.main.ScreenToWorldPoint(btnSreen);
ITween动画的坑:
在使用ITween做动画时,需要注意如果勾选了 Ignore TimeScale,则在测试阶段,如果有暂停编辑器,那么动画可能会出错(快速过度等,闪一下结束)。总结: 暂停编辑器是影响时间缩放的。
屏幕像素抖动:
https://blog.csdn.net/Game_jqd/article/details/82720610 //原因解析
https://www.cnblogs.com/fellow1988/p/6291187.html //奈奎斯特定律说明
经过滤波:
滤波函数: point, bilinear和trilinear三种滤波方式。过滤削弱掉高频分量(高频分量指的是像素间亮度变化大的区域)。
图像的频率: 相邻两点色值差值大,频率就高。高频决定细节,低频率决定轮廓。
波峰之间的距离就是一个采样频率。
Point采样频率应该是小于bilinear的采样频率的。
int 来村粗状态 位: 邪魔boss
public class test : MonoBehaviour {
public bool bool_1=true;
public bool bool_2=false;
public bool bool_3=true;
int stateValue = 0;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
stateValue = setBitComputing(stateValue, 0, bool_1);
stateValue = setBitComputing(stateValue, 1, bool_2);
stateValue = setBitComputing(stateValue, 2, bool_3);
UnityEngine.Debug.Log (stateValue);
UnityEngine.Debug.Log(getBitComputing(stateValue, 0));
UnityEngine.Debug.Log(getBitComputing(stateValue, 1));
UnityEngine.Debug.Log(getBitComputing(stateValue, 2));
}
}
public int setBitComputing(int stateValue, int mask, bool t)
{
if (t)
{
stateValue |= (1 << mask);
int a = stateValue;
}
else
{
stateValue &= ~(1 << mask);//~取反
int a = stateValue;
}
return stateValue;
}
public bool getBitComputing(int stateValue, int mask)
{
return 0 != (stateValue & (1 << mask));
}
}