读一读

2D中,随机一个位置产生物体(如:Sprite),而产生的这个物体能够被看到,那么这个物体就必须要生成在可视的范围中。

这个范围怎么确定呢?通过视口空间转变为世界坐标就行了。(0,0)表示相机视口的最下方,(1,1)表示相机视口的最上方。

Vector3 up = Camera.main.ViewportToWorldPoint(new Vector3(1, 1, 0));
Vector3 down =  Camera.main.ViewportToWorldPoint(Vector3.zero);

那么x的范围为[down.x,up.x]

y的范围为[down.y,up.y]


不知道原因的,使用CaptureScreenshot不能保存到截图到安卓的文件系统中

所以使用另一种方式,成功了。

public IEnumerator CaptureScreenShow()
{
    yield return new WaitForEndOfFrame();
    string fileName = DateTime.Now.Ticks.ToString();
    string tagerFolder = DateTime.Now.ToString("yyyy-MM-dd");
    string pathName = Path.Combine(Application.persistentDataPath, tagerFolder);
    if (!Directory.Exists(pathName))
    {
        Directory.CreateDirectory(pathName);
    }

    string path = pathName+"/"+fileName + ".png";
    //Application.CaptureScreenshot(path);
    
    //截全屏,当然你可以控制大小
    Texture2D t = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, true);
    t.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0, false);
    t.Apply();

    byte[] byt = t.EncodeToPNG();//转换为字节
    File.WriteAllBytes(path, byt);//保存到路径的文件中

    yield return null;

    //判断是否截图成功
    if (File.Exists(path))
    {
        Debug.Log("截图成功!");
    }
    else {
        Debug.Log("截图失败!");
    }

        
}

其实应该就是读取屏幕的像素保存到Texture中,然后将Texture保存到文件系统中。

读取屏幕的像素,应该是渲染完成后再读取,所以要先等待到帧结束时再读取保存。


void Update () {
    if (Input.GetKeyDown(KeyCode.C))
    {
        string fileName = DateTime.Now.Ticks.ToString();
        string tagerFolder = DateTime.Now.ToString("yyyy-MM-dd");
        string pathName = Path.Combine(Application.persistentDataPath, tagerFolder);
        if (!Directory.Exists(pathName))
        {
            Directory.CreateDirectory(pathName);
        }

        string path = Path.Combine(pathName, fileName + ".png");
        //Application.CaptureScreenshot(path);Unity2017弃用了
        ScreenCapture.CaptureScreenshot(path);
        Debug.Log(path);
    }
}

如果不写路径只写文件名时,截图就会在保存在Unity工程的根目录中。


using UnityEngine;
using System.Collections;
using System.Diagnostics;
using System;
public class TestBatch : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {
        try
        {
            Process myProcess = new Process();
            myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            myProcess.StartInfo.CreateNoWindow = true;
            myProcess.StartInfo.UseShellExecute = false;
            myProcess.StartInfo.FileName = "C:\\Windows\\system32\\cmd.exe";
            string path = "C:\\Users\\Brian\\Desktop\\testFile.bat";
            myProcess.StartInfo.Arguments = "/c" + path;
            myProcess.EnableRaisingEvents = true;
            myProcess.Start();
            myProcess.WaitForExit();
            int ExitCode = myProcess.ExitCode;
            //print(ExitCode);
        }
        catch (Exception e)
        {
            print(e);
        }
    }
}

using UnityEngine;

public class CameraFollow : MonoBehaviour {

    private Transform target;
    public float offsetY = 3f;
    public float offsetZ = 6f;
    public float speed = 10f;

    void Awake()
    {
        //默认跟随标签为Player的物体
        target = GameObject.FindGameObjectWithTag("Player").transform;
    }

    public void SetTarget(Transform t)
    {
        target = t;
    }

    void LateUpdate()
    {
        if (target != null)
        {
            transform.LookAt(target);
            Vector3 tar = target.TransformPoint(0, offsetY, -offsetZ);
            transform.position = Vector3.Lerp(transform.position, tar,Time.deltaTime * speed);
        }
    }
}


根据跟随目标,获取它向后面和上面的指定长度的世界位置,作为相机的滑动目标位置。


确保摄像机有Physics Raycaster组件


using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class testDrawLine : MonoBehaviour, IDragHandler, IEndDragHandler
{
    public Color color = Color.red;
    public float thickness = 0.02f;
    private List<Vector3> points = new List<Vector3>();
    private List<Vector3> normals = new List<Vector3>();
    private List<int> splits = new List<int>();//分割索引 
    static Material lineMaterial;


    static void CreateLineMaterial()
    {
        if (!lineMaterial)
        { // Unity has a built-in shader that is useful for drawing 
          // simple colored things. 
            var shader = Shader.Find("Hidden/Internal-Colored");
            lineMaterial = new Material(shader);
            lineMaterial.hideFlags = HideFlags.HideAndDontSave;
            // Turn on alpha blending 
            lineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
            lineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
            // Turn backface culling off 
            lineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
            // Turn off depth writes 
            lineMaterial.SetInt("_ZWrite", 0);
        }
    }

    public void OnRenderObject() {
        
        CreateLineMaterial();
        lineMaterial.SetPass(0);
        GL.PushMatrix();
        GL.MultMatrix(transform.localToWorldMatrix);
        GL.Begin(GL.LINES);
        int index = 0;
        for (int i=1; i<points.Count; i++) {
            if (index < splits.Count && i == splits[index]){
                index++; continue;
            }

            GL.Color(color);
            var from = points[i-1] + normals[i-1] * thickness;
            GL.Vertex3(from.x, from.y, from.z);
            var worldNormal = transform.TransformDirection(normals[i]);
            var to = points[i] + worldNormal * thickness;
            Debug.Log(worldNormal);
            GL.Vertex3(to.x, to.y, to.z); }
            GL.End();
            GL.PopMatrix();
        }

    public void OnBeginDrag(PointerEventData eventData) { }

    public void OnDrag(PointerEventData eventData) {
        if (!eventData.pointerCurrentRaycast.isValid) {
            SplitPoints();
            return;
        }
        var localPosition = transform.InverseTransformPoint(eventData.pointerCurrentRaycast.worldPosition);
        points.Add(localPosition);
        var localNormal = transform.InverseTransformDirection(eventData.pointerCurrentRaycast.worldNormal);
        normals.Add(localNormal);
    }

    public void OnEndDrag(PointerEventData eventData) {
        SplitPoints();
    }

    void SplitPoints() {
        if (splits.Count == 0 && points.Count != 0 || splits[splits.Count - 1] != points.Count)
            splits.Add(points.Count);

    }

}


在3D物体上挂上这个组件脚本就可以用鼠标在物体上划线了。


using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class ScrollTest : MonoBehaviour,IBeginDragHandler,IEndDragHandler {

    //滚动内容
    public RectTransform content;
    //填充类容单元
    public GameObject image;
    //滚动脚本
    public ScrollRect rect;
    //总共的单元个数
    public int AllItemNum;
    //一页放多少个单元
    public int PageItemNum;

    //总页数
    private int PageNum;
    //一页的长度
    private float peerPageLength;

    public float targer = 0;
    public bool isDrag = false;

	// Use this for initialization
	void Awake() {

        for (int i = 0; i < AllItemNum; i++)
        {
            GameObject go = Instantiate(image);
            go.transform.parent = content;
        }

        GridLayoutGroup g = content.GetComponent<GridLayoutGroup>();

        //计算滚动内容的总水平长度,然后设置
        float itemLength = g.cellSize.x + g.spacing.x;
        int PageRowNum = PageItemNum / g.constraintCount;
        float pageLength = itemLength * PageRowNum;
        PageNum = Mathf.CeilToInt( AllItemNum / PageItemNum) + 1;
        content.sizeDelta = new Vector2(pageLength * PageNum,content.sizeDelta.y);

        //计算一页的长度,19个,8个每页,共3页,就是0,0.5,13段
        peerPageLength = 1f / (PageNum - 1);
	}
	
	// Update is called once per frame
	void Update () {

        if (isDrag) return;

        rect.horizontalNormalizedPosition = Mathf.Lerp(rect.horizontalNormalizedPosition, targer, Time.deltaTime * 30);

	}

    public void OnBeginDrag(PointerEventData eventData)
    {
        isDrag = true;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        isDrag = false;
        if (eventData.delta.x > 0f || targer < rect.horizontalNormalizedPosition)
            targer += peerPageLength;
        else {
            targer -= peerPageLength;
        }
            

        targer = Mathf.Clamp01(targer);
    }
}



如果是在Unity中单单的用脚本类来封装Debug,添加一个全局控制的变量的话,是可以通过设置这个变量来解决Unity打包后不输出这些Debug。但是在Editor中双击输出日志就会定位到封装的Debug类中,就显然的就很不理想了。解决办法就是把这个封装的类变成dll文件后再导入。

一、dll文件的制作

新建dll类库项目,修改项目目标框架为.Net3.5,引入UnityEngine.dll(可以在Unity安装目录下搜索找到),然后新建public的类进行封装。

using UnityEngine;

namespace DebugLog
{
    public class DebugLog
    {
        public static DebugLog UI = new DebugLog("UI");

        private string module;
        public bool IsOut = true;

        public DebugLog(string module)
        {
            this.module = module;
        }

        public void Log(string mes)
        {
            if(IsOut)
            Debug.Log(module+ ":" + mes);
        }

    }
}

二、使用

将生成的dll拉进Unity项目中,使用这个类输出日志,具体的其他实际使用的细节就忽略了。

using UnityEngine;

public class TestDebugLog : MonoBehaviour {
    
	void Start () {
        DebugLog.DebugLog.UI.Log("Hello");
        DebugLog.DebugLog.UI.IsOut = false;
        DebugLog.DebugLog.UI.Log("world");
    }
}

只输出了前面的Hello,只要将IsOut的设置放在全部输出的前面,就可以实现控制了。

当然还可以自定义输出日志模块的文字样式等。

缺点就是,每次添加模块或则做一些修改,都需要重新生成dll,引入。


using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class Proc : MonoBehaviour {

    UnityWebRequest web;
    
    void Start () {
        StartCoroutine(WebDown());
	}
	
	void Update () {
        if(web != null)
        Debug.Log(web.downloadProgress);
	}

    IEnumerator WebDown()
    {
        web = UnityWebRequest.Get("http://down.sandai.net/thunder9/Thunder9.1.47.1020.exe");
        yield return web.SendWebRequest();
    }
}

以静态方法来获取下载的实例的,UnityWebRequest对网络操作都采取这种方式了


using System.Collections;
using UnityEngine;

public class Proc : MonoBehaviour {

    WWW www;
    
    void Start () {
        StartCoroutine(Down());
	}
	
	void Update () {
        if(www != null)
        Debug.Log(www.progress);
	}

    IEnumerator Down()
    {
        www = new WWW("https://store.unity.com/cn/download/thank-you?thank-you=personal&os=win&nid=528");
        yield return www;
    }
    
}

当然,下载进度其实是对大型文件才有用处的,不然只能看到0直接变成1了。