2017-05-29 20:46:05 oilcode 阅读数 8684
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22609 人正在学习 去看看 姜雪伟

我学习Unity3D一小段时间了,第一个制作目标就是实现一个自由漫游的摄像机。

使用WSAD键控制摄像机的前后左右移动,使用鼠标右键控制摄像机的旋转。

这个功能比较简单,代码也一目了然,不做过多解释了,直接上代码。

这个脚本不只可以用在摄像机上,也可以用在一般的GameObject上。

//-----------------------------------------------------------------
//1,把本类作为一个组件,包含在 GameObject 中。
//2,左手坐标系。
//-----------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-----------------------------------------------------------------
public class FiCameraControl : MonoBehaviour
{
    public float moveSpeed = 30.0f;
    public float rotateSpeed = 0.2f;


    public static Vector3 kUpDirection = new Vector3(0.0f, 1.0f, 0.0f);


    //控制摄像机旋转的成员变量。
    private float m_fLastMousePosX = 0.0f;
    private float m_fLastMousePosY = 0.0f;
    private bool m_bMouseRightKeyDown = false;


    //-----------------------------------------------------------------
    void Start()
    {


    }
    //-----------------------------------------------------------------
    void Update()
    {
        //判断旋转
        if (Input.GetMouseButtonDown(1)) //鼠标右键刚刚按下了
        {
            if (m_bMouseRightKeyDown == false)
            {
                m_bMouseRightKeyDown = true;
                Vector3 kMousePos = Input.mousePosition;
                m_fLastMousePosX = kMousePos.x;
                m_fLastMousePosY = kMousePos.y;
            }
        }
        else if (Input.GetMouseButtonUp(1)) //鼠标右键刚刚抬起了
        {
            if (m_bMouseRightKeyDown == true)
            {
                m_bMouseRightKeyDown = false;
                m_fLastMousePosX = 0;
                m_fLastMousePosY = 0;
            }
        }
        else if (Input.GetMouseButton(1)) //鼠标右键处于按下状态中
        {
            if (m_bMouseRightKeyDown)
            {
                Vector3 kMousePos = Input.mousePosition;
                float fDeltaX = kMousePos.x - m_fLastMousePosX;
                float fDeltaY = kMousePos.y - m_fLastMousePosY;
                m_fLastMousePosX = kMousePos.x;
                m_fLastMousePosY = kMousePos.y;


                Vector3 kNewEuler = transform.eulerAngles;
                kNewEuler.x += (fDeltaY * rotateSpeed);
                kNewEuler.y += -(fDeltaX * rotateSpeed);
                transform.eulerAngles = kNewEuler;
            }
        }


        //判断位移
        float fMoveDeltaX = 0.0f;
        float fMoveDeltaZ = 0.0f;
        float fDeltaTime = Time.deltaTime;
        if (Input.GetKey(KeyCode.A))
        {
            fMoveDeltaX -= moveSpeed * fDeltaTime;
        }
        if (Input.GetKey(KeyCode.D))
        {
            fMoveDeltaX += moveSpeed * fDeltaTime;
        }
        if (Input.GetKey(KeyCode.W))
        {
            fMoveDeltaZ += moveSpeed * fDeltaTime;
        }
        if (Input.GetKey(KeyCode.S))
        {
            fMoveDeltaZ -= moveSpeed * fDeltaTime;
        }
        if (fMoveDeltaX != 0.0f || fMoveDeltaZ != 0.0f)
        {
            Vector3 kForward = transform.forward;
            Vector3 kRight = Vector3.Cross(kUpDirection, kForward);
            Vector3 kNewPos = transform.position;
            kNewPos += kRight * fMoveDeltaX;
            kNewPos += kForward * fMoveDeltaZ;
            transform.position = kNewPos;
        }
    }
}
//-----------------------------------------------------------------


2016-11-18 13:40:11 qq_15267341 阅读数 1772
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22609 人正在学习 去看看 姜雪伟

首先说明一下,今天将的手动漫游方式需要借助Unity的手势插件: FingerGestures


具体插件如何使用,请看文章:
http://blog.csdn.net/qq_15267341/article/details/51878844?locationNum=1&fps=1


三步搞定手动漫游:


1 场景中建立一个相机
2 相机上挂一个角色控制器脚本
3 相机上挂如下代码脚本(shouDongManYou.cs)

最后调整相机的参数以确定相机的初始位置,调整角色控制器的Center、Radius、Height


这里写图片描述


这里写图片描述


public class shouDongManYou : MonoBehaviour {
    private float a01;  //a01和a02控制左右旋转
    private float a02;

    private float b01;  //b01和b02控制上下旋转
    private float b02;

    // Use this for initialization
    void Start () {

    }
    void Update()
    {
    }
    public void jieshu() //退出漫游手动漫游时取消事件
    {
        FingerGestures.OnDragMove -= dragMove;
        FingerGestures.OnFingerStationary -= onFingerStationary;
    }
    void OnEnable()
    {
        a01=a02 = transform.localEulerAngles.y;
        b01=b02 = transform.localEulerAngles.x;
        FingerGestures.OnDragMove += dragMove;
        FingerGestures.OnFingerStationary += onFingerStationary;
    }
    // Update is called once per frame
    Vector2 previousPos;
    void dragMove(Vector2 fingerPos, Vector2 delta)
    {
        a01 += delta.x * 0.06f;
        a02 = Mathf.Lerp(a02, a01, Time.deltaTime * 30f);
        b01 += delta.y * 0.5f;
        b02 = Mathf.Lerp(b02, b01, Time.deltaTime * 30f);
        b02 = Mathf.Clamp(b02, -3, 3);
        transform.rotation = Quaternion.Euler(b02, a02, transform.localEulerAngles.z);               

    }

    void onFingerStationary(int fingerIndex, Vector2 fingerPos, float elapsedTime)
    {
        if (elapsedTime>0.5f)
        {
            GetComponent<CharacterController>().SimpleMove(transform.forward);
        }
    }
}

一定要注意墙和地板都要添加碰撞体


特别注意如下:


这里写图片描述



FR:海涛高软(QQ技术交流群:386476712)

2017-10-13 17:38:27 qq_21397217 阅读数 1929
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22609 人正在学习 去看看 姜雪伟

将该脚本添加到相机上,可实现相机在场景中的自由移动,相机具有防穿墙功能(可选)。

输入控制:
使用 WSADEQ 控制相机前后左右上下移动;
使用 鼠标右键 控制视角旋转。

参数控制:
变量 minDistance 设为小于等于 0 的值时相机能够穿透碰撞体表面(设为大于0的值时,相机到碰撞体前停住时的距离会略小于设定值)。

using UnityEngine;

public class TourCamera : MonoBehaviour
{
    // 在场景中游览的相机(不要给相机加碰撞器!)
    public Transform tourCamera;

    #region 相机移动参数
    public float moveSpeed = 1.0f;
    public float rotateSpeed = 90.0f;
    public float shiftRate = 2.0f;// 按住Shift加速
    public float minDistance = 0.5f;// 相机离不可穿过的表面的最小距离(小于等于0时可穿透任何表面)
    #endregion

    #region 运动速度和其每个方向的速度分量
    private Vector3 direction = Vector3.zero;
    private Vector3 speedForward;
    private Vector3 speedBack;
    private Vector3 speedLeft;
    private Vector3 speedRight;
    private Vector3 speedUp;
    private Vector3 speedDown;
    #endregion

    void Start()
    {
        if (tourCamera == null) tourCamera = gameObject.transform;

        // 防止相机边缘穿透
        //if (tourCamera.GetComponent<Camera>().nearClipPlane > minDistance / 3)
        //{
        //    tourCamera.GetComponent<Camera>().nearClipPlane /= 3;
        //}
    }

    void Update()
    {
        GetDirection();

        // 检测是否离不可穿透表面过近
        RaycastHit hit;
        while (Physics.Raycast(tourCamera.position, direction, out hit, minDistance))
        {
            // 消去垂直于不可穿透表面的运动速度分量
            float angel = Vector3.Angle(direction, hit.normal);
            float magnitude = Vector3.Magnitude(direction) * Mathf.Cos(Mathf.Deg2Rad * (180 - angel));
            direction += hit.normal * magnitude;
        }

        tourCamera.Translate(direction * moveSpeed * Time.deltaTime, Space.World);
    }

    private void GetDirection()
    {
        #region 加速移动
        if (Input.GetKeyDown(KeyCode.LeftShift)) moveSpeed *= shiftRate;
        if (Input.GetKeyUp(KeyCode.LeftShift)) moveSpeed /= shiftRate;
        #endregion

        #region 键盘移动
        // 复位
        speedForward = Vector3.zero;
        speedBack = Vector3.zero;
        speedLeft = Vector3.zero;
        speedRight = Vector3.zero;
        speedUp = Vector3.zero;
        speedDown = Vector3.zero;

        // 获取按键输入
        if (Input.GetKey(KeyCode.W)) speedForward = tourCamera.forward;
        if (Input.GetKey(KeyCode.S)) speedBack = -tourCamera.forward;
        if (Input.GetKey(KeyCode.A)) speedLeft = -tourCamera.right;
        if (Input.GetKey(KeyCode.D)) speedRight = tourCamera.right;
        if (Input.GetKey(KeyCode.E)) speedUp = Vector3.up;
        if (Input.GetKey(KeyCode.Q)) speedDown = Vector3.down;

        direction = speedForward + speedBack + speedLeft + speedRight + speedUp + speedDown;
        #endregion

        #region 鼠标旋转
        if (Input.GetMouseButton(1))
        {
            // 转相机朝向
            tourCamera.RotateAround(tourCamera.position, Vector3.up, Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime);
            tourCamera.RotateAround(tourCamera.position, tourCamera.right, -Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime);

            // 转运动速度方向
            direction = V3RotateAround(direction, Vector3.up, Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime);
            direction = V3RotateAround(direction, tourCamera.right, -Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime);
        }
        #endregion
    }

    /// <summary>
    /// 计算一个Vector3绕旋转中心旋转指定角度后所得到的向量。
    /// </summary>
    /// <param name="source">旋转前的源Vector3</param>
    /// <param name="axis">旋转轴</param>
    /// <param name="angle">旋转角度</param>
    /// <returns>旋转后得到的新Vector3</returns>
    public Vector3 V3RotateAround(Vector3 source, Vector3 axis, float angle)
    {
        Quaternion q = Quaternion.AngleAxis(angle, axis);// 旋转系数
        return q * source;// 返回目标点
    }
}
2017-10-21 15:40:34 x13804709 阅读数 8688
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22609 人正在学习 去看看 姜雪伟

脚本MouseLook(在主相机上):

using UnityEngine;
using System.Collections;

public class Mouselook : MonoBehaviour {
    public enum RotationAxes{
        MouseXAndY = 0,
        MouseX =1,
        MouseY =2
    }
    public RotationAxes axes = RotationAxes.MouseXAndY;
    public float sensitivityHor = 9f;
    public float sensitivityVert = 9f;

    public float minmumVert = -45f;
    public float maxmumVert = 45f;

    private float _rotationX = 0;
    // Use this for initialization
    void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
        if (axes == RotationAxes.MouseX)
        {
            transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityHor, 0);
        }
        else if (axes == RotationAxes.MouseY)
        {
            _rotationX = _rotationX - Input.GetAxis("Mouse Y") * sensitivityVert;
            _rotationX = Mathf.Clamp(_rotationX, minmumVert, maxmumVert);
      
            float rotationY = transform.localEulerAngles.y;

            transform.localEulerAngles = new Vector3(-_rotationX, rotationY, 0);
        } 
        else
        {
            _rotationX-= Input.GetAxis("Mouse Y") * sensitivityVert;
            _rotationX = Mathf.Clamp(_rotationX, minmumVert, maxmumVert);

            float delta = Input.GetAxis("Mouse X") * sensitivityHor;
            float rotationY = transform.localEulerAngles.y + delta;

            transform.localEulerAngles = new Vector3(-_rotationX, rotationY, 0);
        }
	
	}
}

 

move脚本:

using UnityEngine;
using System.Collections;

//[RequireComponent(typeof(CharacterController))]
//[AddComponentMenu("Control Script/move")]
public class move : MonoBehaviour
{
    public CharacterController controller;
    public Rigidbody rigidbody;
    public float speed = 1;

    // Use this for initialization
    void Start()
    {
        rigidbody = this.GetComponent<Rigidbody>();
        controller = this.GetComponent<CharacterController>();
    }

    //Move
    

    // Update is called once per frame
    void Update()
    {
        //Move
        if (Input.GetKey("a"))
            controller.SimpleMove(transform.right * -speed);
        if (Input.GetKey("d"))
            controller.SimpleMove(transform.right * speed);
        if (Input.GetKey("w"))
            controller.SimpleMove(transform.forward * speed);
        if (Input.GetKey("s"))
            controller.SimpleMove(transform.forward * -speed);
    }
}

 

 

2017-05-27 10:55:54 hb707934728 阅读数 760
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22609 人正在学习 去看看 姜雪伟

本例实现,鼠标点击场景中任何一点,场景中的正方体即移动到鼠标指定点,右键按住不放,旋转场景,鼠标滚轮实现场景缩放

核心实现:

1,相机类  (摄像机根据输入事件改变自己的观察矩阵)

	//相机类
	class CELL3RDCamera
	{
	public:
		float3 _eye;
		float3 _up;
		float3 _right;
		float3 _target;
		float3 _dir;
		float _radius;
		matrix4 _matView;
		matrix4 _matProj;
		matrix4 _matWorld;
		float2 _viewSize;

		float _yaw;//偏离度

	public:
		CELL3RDCamera()
		{
			_radius = 400;
			_yaw = 0;
			_viewSize = float2(100,100);
			_matView.identify();//初始化为单位矩阵
			_matProj.identify();
			_matWorld.identify();
		}

		float getRadius() const
		{
			return _radius;
		}

		void setRadius(float val)
		{
			_radius = val;
		}

		CELL::float3 getEye() const
		{
			return _eye;
		}

		//设置眼睛位置
		void setEye(CELL::float3 val)
		{
			_eye = val;
		}

		//计算方向
		void calcDir()
		{
			_dir = _target - _eye;//得到运动方向向量
			_dir = normalize(_dir);//归一化  
		}

		CELL::float3 getTarget() const
		{
			return _target;
		}

		void    setTarget(CELL::float3 val)
		{
			_target = val;
		}

		CELL::float3 getUp() const
		{
			return _up;
		}
		void    setUp(CELL::float3 val)
		{
			_up = val;
		}
		float3  getDir() const
		{
			return  _dir;
		}

		float3  getRight() const
		{
			return  _right;
		}

		void update()
		{
			//归一化
			float3 upDir = normalize(_up);
			_eye = _target - _dir*_radius;
			_right = normalize(cross(_dir,upDir));

			//设置摄像机观察矩阵
			_matView = CELL::lookAt(_eye,_target,_up);
		}

		void    setViewSize(const float2& viewSize)
		{
			_viewSize = viewSize;
		}
		void    setViewSize(float x, float y)
		{
			_viewSize = float2(x, y);
		}

		float2  getViewSize()
		{
			return  _viewSize;
		}

		void setProject(const matrix4& proj)
		{
			_matProj = proj;
		}

		const matrix4& getProject() const
		{
			return _matProj;
		}

		const matrix4& getView() const
		{
			return _matView;
		}

		void perspective(float fovy, float aspect, float zNear, float zFar)
		{
			_matProj = CELL::perspective<float>(fovy,aspect,zNear,zFar);
		}


		/**
		*   世界坐标转化为窗口坐标
		*/
		bool    project(const float4& world, float4& screen)
		{
			screen = (_matProj * _matView * _matWorld) * world;
			if (screen.w == 0.0f)
			{
				return false;
			}
			screen.x /= screen.w;
			screen.y /= screen.w;
			screen.z /= screen.w;

			// map to range 0 - 1
			screen.x = screen.x * 0.5f + 0.5f;
			screen.y = screen.y * 0.5f + 0.5f;
			screen.z = screen.z * 0.5f + 0.5f;

			// map to viewport
			screen.x = screen.x * _viewSize.x;
			screen.y = _viewSize.y - (screen.y * _viewSize.y);
			return  true;
		}


		/**
		*   世界坐标转化为窗口坐标
		*/
		float2  worldToScreen(const float3& world)
		{
			float4  worlds(world.x, world.y, world.z, 1);
			float4  screens;
			project(worlds, screens);
			return  float2(screens.x, screens.y);
		}

		/**
		*   窗口坐标转化为世界坐标
		*/
		float3  screenToWorld(const float2& screen)
		{
			float4  screens(screen.x, screen.y, 0, 1);
			float4  world;
			unProject(screens, world);
			return  float3(world.x, world.y, world.z);
		}

		float3  screenToWorld(float x, float y)
		{
			float4  screens(x, y, 0, 1);
			float4  world;
			unProject(screens, world);
			return  float3(world.x, world.y, world.z);
		}


		/**
		*   窗口坐标转化为世界坐标
		*/
		bool    unProject(const float4& screen, float4& world)
		{
			float4 v;
			v.x = screen.x;
			v.y = screen.y;
			v.z = screen.z;
			v.w = 1.0;

			// map from viewport to 0 - 1
			v.x = (v.x) / _viewSize.x;
			v.y = (_viewSize.y - v.y) / _viewSize.y;
			//v.y = (v.y - _viewPort.Y) / _viewPort.Height;

			// map to range -1 to 1
			v.x = v.x * 2.0f - 1.0f;
			v.y = v.y * 2.0f - 1.0f;
			v.z = v.z * 2.0f - 1.0f;

			CELL::matrix4  inverse = (_matProj * _matView * _matWorld).inverse();

			v = v * inverse;
			if (v.w == 0.0f)
			{
				return false;
			}
			world = v / v.w;
			return true;
		}

		Ray createRayFromScreen(int x, int y)
		{
			float4  minWorld;
			float4  maxWorld;

			float4  screen(float(x), float(y), 0, 1);
			float4  screen1(float(x), float(y), 1, 1);

			unProject(screen, minWorld);
			unProject(screen1, maxWorld);
			Ray     ray;
			ray.setOrigin(float3(minWorld.x, minWorld.y, minWorld.z));

			float3  dir(maxWorld.x - minWorld.x, maxWorld.y - minWorld.y, maxWorld.z - minWorld.z);
			ray.setDirection(normalize(dir));
			return  ray;
		}
		/**
		*   下面的函数的功能是将摄像机的观察方向绕某个方向轴旋转一定的角度
		*   改变观察者的位置,目标的位置不变化
		*/
		void    rotateView(float angle)
		{
			_dir = rotateY<float>(_dir, angle);
		}
	};

场景角色类(响应输入事件的角色)

	//场景中的角色类
	class Role
	{
	public:
		float3 _pos;//当前位置
		float3 _target;//目的位置
		float _speed;//速度
	public:
		Role()
		{
			_speed = 5;
		}

		//设置移动的目标点
		void setTarget(float3 target)
		{
			_target = target;
		}

		//更新位置
		void setPosition(float3 pos)
		{
			_pos = pos;
			_pos.y = 1;
		}

		void moveCheck(const float elasped)
		{
				//目标位置不能是当前位置
			if (_target==_pos)
			{
				return;
			}

			//获取当前位置与目标位置的偏移量
			float3 offset = _target - _pos;
			//获取移动方向
			float3 dir = normalize(offset);//单位向量

			if (distance(_target,_pos)>1)
			{
				float speed = elasped*_speed;//时间乘以速度
				//最新位置=当前位置+移动的偏移量
				_pos += float3(dir.x*speed, 0, dir.z*speed);
			}
			else
			{
				_target = _pos;
			}
		}

		void render(float fElapsed)
		{
			moveCheck(fElapsed);
		}
	};

事件响应代码()

		/*
			鼠标移动,含鼠标滚轮
		*/

		virtual void onMouseMove(int absx, int absy, int absz)
		{
			if (absz>0)
			{
				_camera._radius = _camera._radius*1.1f;//相机焦距变大,观察的物体缩小
			}
			else if (absz<0)
			{
				_camera._radius = _camera._radius*0.9f;//相机焦距变小,观察的物体变大
			}
			else if (_rightButtonDown)//按下右键不放,移动鼠标,旋转整个场景,相当于旋转摄像机
			{
				float2 curPos(absx,absy);
				float2 offset = curPos - _mousePos;
					   _mousePos = curPos;
					   _camera.rotateView(offset.x*0.1f);
					   _camera.update();
			}
		}

 

		/*
			鼠标按下 
		*/
		virtual void onMousePress(int absx, int absy, CELL::MouseButton id)
		{
			if (id==CELL::MouseButton::Left)//如果按下是是左键 则开始运动
			{
				//创建一条由物体当前位置到目标位置的射线(即以角色当前位置为起点,鼠标按下点为终点的向量)
				Ray ray = _camera.createRayFromScreen(absx,absy);

				//射线的起点
				float3 pos = ray.getOrigin();
				//获取起始点和结束点坐标值的比例系数
				float tm = abs((pos.y)/ray.getDirection().y);
				//目标点向量,射线的终点,也就是物体要运动到的终点
				float3 target = -ray.getPoint(tm);
				//设置当前角色的运动目的地
				_role.setTarget(float3(target.x,0,target.z));
			}
			else if (id==CELL::MouseButton::Right) //如果按下的是右键,右键保持现状
			{
				_mousePos = float2(absx,absy);
				_rightButtonDown = true;
			}
		}
      
        /**
        *   鼠标释放
        */
        virtual void    onMouseRelease(int /*absx*/, int /*absy*/, CELL::MouseButton id)
        {
            if( id == CELL::MouseButton::Right)
            {
                _rightButtonDown    =   false;
            }
        }

完整代码参考:http://download.csdn.net/detail/hb707934728/9853933



没有更多推荐了,返回首页