3d物品阻挡 unity3d - CSDN
  • 转载自:https://blog.csdn.net/sumkee911/article/details/53707148 /* * Trajectory.cs * Author: sumkee911@gmail.... * Date: 2016-12-17 * Brief: Trajectory of arrow * */ ...using System.Collectio...

    转载自:https://blog.csdn.net/sumkee911/article/details/53707148

    /*
     * 	Trajectory.cs
     * 	Author: sumkee911@gmail.com
     *  Date: 2016-12-17
     * 	Brief: Trajectory of arrow
     * 
     */
     
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class Trajectory : MonoBehaviour {
     
    	// Use this for initialization
    	void Start () {
    		// 開始測試
    		Vector3 end = transform.position;
    		end.x = end.x * -1;
    		Fire (transform.position, end);
    	}
    	
    	// Update is called once per fram
    	void Update () {
    		if (_isFiring) {
    			UpdateArrow ();
    		}
    	}
     
    	// 所有變量
    	public float rotateX = 45;		// 箭的最大X軸旋轉角度
    	public float speed = 10;		// 箭的速度
    	public float height = 10;		// 箭的最大高度 
    	private Vector3 _startPos,_stopPos, _curPos;	// 起始位置,目標位置,當前位置
    	private float _angleToStop;		// 從起始點到目標點的角度
    	private float _startHeight,_stopHeight;	// 起始高度,結束高度
    	private bool _isFiring = false;		//判斷箭是否正在移動
    	private float _totalDistance,_curDistance;	// 總距離, 當前距離
    	private Vector3 _curRotation; // 當前的旋轉角度
     
    	// 發射函數,你只要調用這一個函數就能發射箭了
    	public void Fire(Vector3 start, Vector3 stop) {
    		_startPos = start;
    		_stopPos = stop;
    		_angleToStop = GetAngleToStop(start, stop);	// 計算 起始位置 到 目標位置的角度
    		_startHeight = start.y;
    		_stopHeight = stop.y;
    		_curDistance = 0;
     
    		// 計算總距離
    		Vector3 v = _stopPos - _startPos;
    		_totalDistance = Mathf.Sqrt (v.x * v.x + v.z * v.z);
     
    		// 設置當前位置
    		transform.position = start;
    		_curPos = start;
     
    		// 設置當前X,Y軸的旋轉角度
    		Vector3 rotation = transform.eulerAngles;
    		if (rotateX > 0) {
    			rotation.x = -rotateX;
    		}
    		rotation.y = _angleToStop;
     
    		transform.eulerAngles = rotation;
    		_curRotation = rotation;
     
    		// 設置判斷爲發射狀態,讓Update函數能夠更新
    		_isFiring = true;
    	}
     
    	// 計算 起始位置 到 目標位置的角度
    	private float GetAngleToStop(Vector3 startPos, Vector3 stopPos) {
    		stopPos.x -= startPos.x;
    		stopPos.z -= startPos.z;
     
    		float deltaAngle = 0;
    		if (stopPos.x == 0 && stopPos.z == 0) {
    			return 0;
    		} else if (stopPos.x > 0 && stopPos.z > 0) {
    			deltaAngle = 0;
    		} else if (stopPos.x > 0 && stopPos.z == 0) {
    			return 90;
    		} else if (stopPos.x > 0 && stopPos.z < 0) {
    			deltaAngle = 180;
    		} else if (stopPos.x == 0 && stopPos.z < 0) {
    			return 180;
    		} else if (stopPos.x < 0 && stopPos.z < 0) {
    			deltaAngle = -180;
    		} else if (stopPos.x < 0 && stopPos.z == 0) {
    			return -90;
    		} else if (stopPos.x < 0 && stopPos.z > 0) {
    			deltaAngle = 0;
    		}
     
    		float angle = Mathf.Atan(stopPos.x / stopPos.z) * Mathf.Rad2Deg + deltaAngle;
    		return angle;
    	}
    		
    	// 更新箭到下一個位置
    	private void SetNextStep() {
    		// 計算X,Z軸移動向量,然後再把它們乘移動距離,這樣就能移動到下一個位置
    		float deltaX = Mathf.Sin (_angleToStop * Mathf.Deg2Rad);
    		float deltaZ = Mathf.Cos (_angleToStop * Mathf.Deg2Rad);
    		float l = speed * Time.deltaTime;
    		_curPos.x += deltaX * l;
    		_curPos.z += deltaZ * l;
     
    		// 增加當前距離,用來判斷是否到達終點了
    		_curDistance += l;
     
    		/************************************************/
    		// 計算出當前的高度
    		// 這個是一元二次方程(ax^2 + bx),大家都知道它是一條拋物線的方程,也是弓箭軌道最重要的地方。
    		// 我會在下面跟大家詳解如果運用簡單的一元二次方程來做弓箭的拋物線效果
    		/************************************************/
    		float a = -1;
    		float b = _totalDistance;
    		float apex = _totalDistance / 2;
    		float deltaHeight = 1 / ((-apex) * (apex - _totalDistance) / height);
    		float deltaDistance = _curDistance/_totalDistance;
    		float h =  deltaDistance * (_stopHeight - _startHeight) + _startHeight;
    		h += deltaHeight * (a*(_curDistance*_curDistance) + b*_curDistance);
    		_curPos.y = h;
     
    		// 更新當前箭的位置
    		transform.position = _curPos;
     
    		// 旋轉X軸
    		if (rotateX > 0) {
    			_curRotation.x = -rotateX * (1 + -2 * deltaDistance);
    			transform.eulerAngles = _curRotation;
    		}
    	}
     
    	// 判斷是否到達
    	private bool IsArrived() {
    		return _curDistance >= _totalDistance;
    	}
     
    	private void UpdateArrow() {
    		SetNextStep ();
     
    		// 如果到達了目標地點就取消發射狀態
    		if (IsArrived ()) {
    			_isFiring = false;
    		}
    	}
    }
    

     

    展开全文
  • Unity3d之背包系统

    2018-06-06 00:17:27
    Unity3d实战之粒子系统 选题要求 参考unity官网的背包系统例子,实现一个简单的背包系统 实现效果 静态图 动态图 知识准备 摄像机渲染 Clearing Flags: Skybox:天空盒(默认项)。在屏幕空白处显示...

    Unity3d实战之背包系统

    选题要求

    参考unity官网的背包系统例子,实现一个简单的背包系统

    实现效果

    • 静态图
      这里写图片描述
    • 动态图

    知识准备

    • 摄像机渲染
      • Clearing Flags:
        • Skybox:天空盒(默认项)。在屏幕空白处显示当前摄像机的天空盒,如果没有指定天空盒,则会显示默认背景色。
        • Solid Color:空白处将显示默认此处设置的背景色。
        • Depth only:仅深度,该模式用于对象不被裁剪。
        • Don’t Clear:不清除,该模式不清楚任何颜色和或深度缓存,但这样做每帧渲染的结果都会叠加在下一帧之上。
      • Culling Mask: 摄像机渲染的层
      • Layers: 摄像机所在的层
      • Depth: 指定多个摄像机的渲染顺序
      • Rendering Path:渲染路径,设定摄像机的渲染方法
      • Projection:投影方式,分为透视和正交
      • Clipping Planes:剪裁平面,摄像机的渲染范围。Near为最近的点,Far为最远的点
    • 粒子系统
      粒子系统有许多大模块,比如最常用的有初始化模块、发射模块、粒子群形状模块,颜色随存活时间、速度变化的模块等。方便起见这里再把上次的粒子系统贴一遍。

      参数 功能
      持续时间(Duration) 粒子系统发射粒子的持续时间
      循环(Looping) 粒子系统是否循环
      预热(Prewarm) 当looping开启时,才能启动预热(Prewarm),游戏开始时粒子已经发射了一个周期
      初始延迟(Start Delay) 粒子系统发射粒子之前的延迟。注意在prewarm(预热)启用下不能使用此项
      初始生命(Start Lifetime) 以秒为单位,粒子存活数量
      初始速度(Start Speed) 粒子发射时的速度
      初始大小(Start Size) 粒子发射时的大小
      初始旋转(Start Rotation) 粒子发射时的旋转值
      初始颜色(Start Color) 粒子发射时的颜色
      重力修改器(Gravity Modifier) 粒子在发射时受到的重力影响
      继承速度(Inherit Velocity) 控制粒子速率的因素将继承自粒子系统的移动(对于移动中的粒子系统)
      模拟空间(Simulation Space) 粒子系统在自身坐标系还是世界坐标系
      唤醒时播放(Play On Awake) 如果启用粒子系统当在创建时,自动开始播放
      最大粒子数(Max Particles) 粒子发射的最大数量

    实现步骤

    • 第一步,搭建UI界面。新建一个画布(Canvas),再创建一个Panel容器,里面包含UI界面的所有UI控件,比如背包区的九个格子和装备区的三个格子,每个格子都是一个Button控件,背包区和装备区的这些按钮的父级分别是Bag和Equip两个空对象,主要是为了添加GridLayout控件来控制子对象的布局,以及相应的控制脚本。基本的控件创建好之后,将画布设置成UI层,接着再创建一个保存鼠标图片的Image控件,这是为了暂存移动的图片达到交换目的,最后创建一个专门渲染UI层的摄像机,将其Culling Mask设置成UI层。这样UI层的搭建基本完成,剩下的就是对控件位置、大小等的参数调整,以及更改控件的图片。这里要注意的一点是,添加图片时必须先把原来的图片转成Sprite类型才可以被Image组件识别
      搭建完成后的文件结构
      这里写图片描述
      UI Camera设置
      这里写图片描述
      GridLayout组件的设置
      这里写图片描述
    • 第二步,搭建背景界面。这个比布置UI界面容易多了。为了让背景有点简单的动态特效,这里用到了一点粒子系统。首先新建一个空对象scene,然后右键scene->Effects->Particle System,便可把例子系统添加为其子对象。接着再新建一个空对象,用来显示背景图片,修改其Sprite Renderer的Sprite为要添加的背景图片即可。最后把主摄像机放到这个空对象下面,其渲染的层是默认层,无需修改。要注意的是必须确保UI层的渲染要介于背景层渲染和英雄层渲染之间,用摄像机的深度Depth控制。
      搭建完成后的文件结构
      这里写图片描述
      主摄像机设置
      这里写图片描述
    • 第三步,搭建英雄层。这层就是用来渲染英雄的,为了和UI层区分开来以便拓展更多的功能。新建一个摄像机,负责渲染英雄层,将英雄作为该摄像机的子对象,并将英雄的所在层设置成英雄层(自定义的一个层)。
      搭建完成后的总的文件结构
      这里写图片描述
      英雄摄像机的设置

    • 第四步,实现画布随鼠标旋转。这里用的是老师上课提供的一个源码,我外加做了一些修改,原本是整个画布的旋转,但是感觉看起来怪怪的,我将其改成以中轴线为界,两边(背包区和装备区)分别旋转,鼠标在背包区的时候装备区不动,鼠标在装备区的时候背包区不动。因此便有了两份类似的代码,分别挂载在背包区的父级元素Bag上和装备区的父级元素Equip上。
      以控制背包区随鼠标旋转的代码为例

    public class BagTilt : MonoBehaviour {
    
        public Vector2 range = new Vector2(50f, 30f);
    
        Transform mTrans;
        Quaternion mStart;
        Vector2 mRot = Vector2.zero;
    
        // Use this for initialization
        void Start()
        {
            mTrans = transform;
            mStart = mTrans.localRotation;
        }
    
        // Update is called once per frame
        void Update()
        {
            Vector3 pos = Input.mousePosition;
            //Debug.Log(pos);        
    
            float halfWidth = Screen.width * 0.5f;
            float halfHeight = Screen.height * 0.5f;
    
            if (pos.x - halfWidth < 0) return;
    
            float x = Mathf.Clamp((pos.x - halfWidth) / halfWidth, -1f, 1f);
            float y = Mathf.Clamp((pos.y - halfHeight) / halfHeight, -1f, 1f);
            mRot = Vector2.Lerp(mRot, new Vector2(x, y), Time.deltaTime * 5f);
    
            mTrans.localRotation = mStart * Quaternion.Euler(-mRot.y * range.y, -mRot.x * range.x, 0f);
        }
    }
    • 第五步,实现游戏的管理者。挂载到任何一个对象上都行,因为其执行与所挂在的对象无关,是对整个游戏场景的控制。这里我是挂载到Canvas上。游戏的管理者主要负责跟踪装备区的装备情况、装备类型的判断以及鼠标对象的单例化。这里为了方便添加脚本,在构造函数中采用循环为每个Button添加对应的脚本。
    public class Manager : MonoBehaviour {
    
        private MouseImage mouse;
        private int IsWeapon1 = 0;
        private int IsWeapon2 = 0;
        private int IsWeapon3 = 0;
    
        // Use this for initialization
        void Start()
        {
            mouse = (MouseImage)FindObjectOfType(typeof(MouseImage));
            for (int i = 1; i <= 9; i++)
            {
                GameObject.Find("Grid" + i).AddComponent<Bag>();
            }
            for (int i = 1; i <= 3; i++)
            {
                GameObject.Find("Weapon" + i).AddComponent<Equip>();
            }
        }
    
        // Update is called once per frame
        public MouseImage getMouse()
        {
            return mouse;
        }
    
        public void setMouse(MouseImage m)
        {
            if (mouse == null)
            {
                mouse = m;
            }
        }
    
        public int getWeapon1()
        {
            return IsWeapon1;
        }
        public int getWeapon2()
        {
            return IsWeapon2;
        }
        public int getWeapon3()
        {
            return IsWeapon3;
        }
        public void setWeapon1(int w1)
        {
            IsWeapon1 = w1;
        }
        public void setWeapon2(int w2)
        {
            IsWeapon2 = w2;
        }
        public void setWeapon3(int w3)
        {
            IsWeapon3 = w3;
        }
    }
    • 第六步,实现对鼠标对象的维护。新建一个C#脚本MouseImage,挂载在MouseImage这个Image对象上。目的也就是,使得点击装备区或是背包区的时候,如果点击的格子里面有装备,则和鼠标上的图片发生交换,以达到将装备取出的效果,而且实现点击图片,图片跟随鼠标移动的效果。这个脚本主要负责装备类型的检测、鼠标图片的设置和图片跟随鼠标移动。Update部分鼠标坐标减去的值是为了不让鼠标上的图片阻挡了对按钮的点击。
    public class MouseImage : MonoBehaviour {
    
        private Manager GM;
        private Image mouseImage;
        private int mouseType = 0;
        private int z;
    
        public Sprite none;
        public Sprite weapon1;
        public Sprite weapon2;
        public Sprite weapon3;
    
        // Use this for initialization
        void Start()
        {
            GM = (Manager)FindObjectOfType(typeof(Manager));
            GM.setMouse(this);
            mouseImage = GetComponent<Image>();        
            z = -400;
    
            weapon1 = GameObject.Find("Grid1").GetComponent<Image>().sprite;
            weapon2 = GameObject.Find("Grid2").GetComponent<Image>().sprite;
            weapon3 = GameObject.Find("Grid3").GetComponent<Image>().sprite;
            none = GameObject.Find("MouseImage").GetComponent<Image>().sprite;
        }
    
        public int getMouseType()
        {
            return mouseType;
        }
        public void setMouseType(int m)
        {
            mouseType = m;
            switch (m)
            {
                case 0:
                    mouseImage.sprite = none;
                    z = -400;
                    break;
                case 1:
                    mouseImage.sprite = weapon1;
                    z = 100;
                    break;
                case 2:
                    mouseImage.sprite = weapon2;
                    z = 100;
                    break;
                case 3:
                    mouseImage.sprite = weapon3;
                    z = 100;
                    break;
                default:
                    mouseImage.sprite = none;
                    z = -400;
                    break;
            }        
        }
    
        // Update is called once per frame
        void Update()
        {
            transform.position = new Vector3(Input.mousePosition.x - 26, Input.mousePosition.y - 26, z);
        }
    }
    • 第七步,实现背包区的交换逻辑。这里主要是要赋予背包区按钮对点击事件的响应能力。比如做一些基本的判断:不管鼠标图片是否为空,如果点中有装备的格子,那么将发生交换,交换的时候要记录装备类型,其他情况一律不交换。为了避免重复添加的繁琐,我是直接在代码里面绑定点击事件,这样也便于修改。
    public class Bag : MonoBehaviour {
    
        private Manager GM;
        private Image gridImage;
        private int mouseType = 0;
    
        public Sprite none;
        public Sprite weapon1;
        public Sprite weapon2;
        public Sprite weapon3;
    
        // Use this for initialization
        void Start () {
            GM = (Manager)FindObjectOfType(typeof(Manager));
            gridImage = GetComponent<Image>();
            weapon1 = GameObject.Find("Grid1").GetComponent<Image>().sprite;
            weapon2 = GameObject.Find("Grid2").GetComponent<Image>().sprite;
            weapon3 = GameObject.Find("Grid3").GetComponent<Image>().sprite;
            none = GameObject.Find("Grid4").GetComponent<Image>().sprite;
            Debug.Log(gridImage.sprite == weapon1);
            Debug.Log(weapon1);
            Debug.Log(weapon2);
            Debug.Log(weapon3);
            this.GetComponent<Button>().onClick.AddListener(OnBagButton);
        }
    
        // Update is called once per frame
        void Update () {
    
        }
    
        public void OnBagButton()
        {
            //Debug.Log("grid click");
            mouseType = GM.getMouse().getMouseType();
            if (gridImage.sprite == none && mouseType != 0)
            {
                switch (mouseType)
                {
                    case 1:
                        gridImage.sprite = weapon1;
                        break;
                    case 2:
                        gridImage.sprite = weapon2;
                        break;
                    case 3:
                        gridImage.sprite = weapon3;
                        break;
                    default:
                        gridImage.sprite = none;
                        break;
                }
                GM.getMouse().setMouseType(0);          
            }
            else
            {
                //Debug.Log(gridImage.sprite);
                //Debug.Log(mouseType);
                if (gridImage.sprite == none)
                {
                    GM.getMouse().setMouseType(0);
                }
                else if (gridImage.sprite == weapon1)
                {
                    GM.getMouse().setMouseType(1);
                }
                else if (gridImage.sprite == weapon2)
                {
                    GM.getMouse().setMouseType(2);
                }
                else if (gridImage.sprite == weapon3)
                {
                    GM.getMouse().setMouseType(3);
                }
    
                switch (mouseType)
                {
                    case 0:                    
                        gridImage.sprite = none;
                        break;
                    case 1:
                        gridImage.sprite = weapon1;
                        break;
                    case 2:
                        gridImage.sprite = weapon2;
                        break;
                    case 3:
                        gridImage.sprite = weapon3;
                        break;
                    default:
                        gridImage.sprite = none;
                        break;
                }                 
            }
        }
    }
    • 第八步,实现装备区的交换逻辑。这里同样是要赋予装备区按钮对点击事件的响应能力。比如稍有不同的简单判断:类似在背包区交换的原理和基础上,外加检测交换的装备类型是否符合该格子所应装备的类型,如果符合才允许交换。同样的,也是在代码里面绑定点击事件。这里我为了弥补添加装备时没有动画的遗憾,规定每次添加动作时英雄都播放一次攻击动画,播放完成后回到Idle状态。
    public class Equip : MonoBehaviour {
    
        private Manager GM;
        private Image weaponImage;
        private GameObject hero;
        public int mouseType;
        public Sprite weapon1;
        public Sprite weapon2;
        public Sprite weapon3;
        public Sprite none;
    
        // Use this for initialization
        void Start () {
            GM = (Manager)FindObjectOfType(typeof(Manager));
            weaponImage = GetComponent<Image>();
            hero = GameObject.Find("Hero");
            weapon1 = GameObject.Find("Grid1").GetComponent<Image>().sprite;
            weapon2 = GameObject.Find("Grid2").GetComponent<Image>().sprite;
            weapon3 = GameObject.Find("Grid3").GetComponent<Image>().sprite;
            none = GameObject.Find("Grid4").GetComponent<Image>().sprite;
            Debug.Log(weapon1);
            Debug.Log(weapon2);
            Debug.Log(weapon3);
            Debug.Log(none);
            this.GetComponent<Button>().onClick.AddListener(OnEquipButton);
            mouseType = this.name[this.name.Length - 1] - '0';
            Debug.Log(mouseType);
        }
    
        // Update is called once per frame
        void Update () {
            if (hero.GetComponent<Animation>().IsPlaying("Attack") == false)
            {
                hero.GetComponent<Animation>().Play("idle", PlayMode.StopAll);
            }
            if (mouseType == 1 && GM.getWeapon1() == 1)
            {
                GM.setWeapon1(0);
                weaponImage.sprite = weapon1;
            }
            else if (mouseType == 2 && GM.getWeapon2() == 1)
            {
                GM.setWeapon2(0);
                weaponImage.sprite = weapon2;
            }
            else if (mouseType == 3 && GM.getWeapon3() == 1)
            {
                GM.setWeapon3(0);
                weaponImage.sprite = weapon3;
            }
        }
    
        public void OnEquipButton()
        {
            //Debug.Log("equiping");
            int _mouseType = GM.getMouse().getMouseType();
            Debug.Log(_mouseType);
            if (weaponImage.sprite != null && _mouseType == 0)
            {
                weaponImage.sprite = none;
                GM.getMouse().setMouseType(mouseType);
            }
            else if (weaponImage.sprite == none && _mouseType == mouseType)
            {
                switch (_mouseType)
                {
                    case 0:
                        weaponImage.sprite = none;
                        break;
                    case 1:
                        GM.setWeapon1(1);
                        weaponImage.sprite = weapon1;
                        break;
                    case 2:
                        GM.setWeapon2(1);
                        weaponImage.sprite = weapon2;
                        break;
                    case 3:
                        GM.setWeapon3(1);
                        weaponImage.sprite = weapon3;
                        break;
                    default:
                        weaponImage.sprite = none;
                        break;
                }
                GM.getMouse().setMouseType(0);
                Animation animation = hero.GetComponent<Animation>();
                animation.Play("Attack", PlayMode.StopAll);
                animation.wrapMode = WrapMode.Once;
            }        
        }
    }
    • 第九步,图片加工。在网上进行了一番搜索和筛选之后,选到比较符合心意的图,但是都是白底不透明的,放在界面上感觉很生硬。为了更加逼真地模仿,我用了ps对筛选好的图片进行了简单的抠图处理,使得每个装备除装备实体以外的部分都是透明的,同样美观起见,将没有装备时的鼠标图片也设置成一张全透明的图片。
      效果对比(深色背景下才看得出差别):
    武器 袖箭 匕首 斧子
    处理前 这里写图片描述 这里写图片描述 这里写图片描述
    处理后 这里写图片描述 这里写图片描述 这里写图片描述

    - 最后一步。核对所有代码挂载情况、文件结构以及摄像机的渲染情况,耐心慢慢调参。调好合适的位置后变可以正常的运行了。到此便和一开始展示的效果完全一致了。


    其他

    • 以上为个人理解,可能有误,仅供参考。
    • 如感兴趣,可访问笔者Gayhub地址—传送门
    • 视频演示地址—传送门

    展开全文
  • Unity 开发游戏时,我们希望 player 碰撞体是可以被墙壁遮挡,可以被敌人碰到消灭,但是多个 player 之间又是可以相互穿过,敌人之间也是可以互相穿过。所以问题来了,我们如何是碰撞仅对特定的物体有效? 解决方法...

    Unity 开发游戏时,我们希望 player 碰撞体是可以被墙壁遮挡,可以被敌人碰到消灭,但是多个 player 之间又是可以相互穿过,敌人之间也是可以互相穿过。所以问题来了,我们如何是碰撞仅对特定的物体有效?

    解决方法

    重点在于 PhysicsLayer 的使用。

    吃豆人游戏

    以《史上最难的游戏》的游戏为例,在游戏中,红色的主角有多个,由多人控制。主角可以与 墙壁 产生碰撞效果而被遮挡,也可以与蓝色的 敌人 产生碰撞效果而被消灭,但是多个 主角 之间可以叠加穿过而不产生碰撞。

    1. 设置游戏物体 Layer

    为了实现这种效果,首先我们要设置玩家对象、敌人的 Layer ,如 Player 和 Enemy 。
    (在 Inspector 面板 Layer 中设置 ,如果没有,自行新建 Layer)

    2. 设置 Physics 碰撞矩阵

    找到菜单栏 Edit -> Project Setting -> Physics 并打开。

    Physics Setting

    我们展开 Layer Collision Matrix 部分,可以看到一个矩阵,这个矩阵描述了哪些 Layer 可以跟哪些 Layer 发生碰撞。如图,我们将不希望发生碰撞的 Layer 在矩阵中勾选取消即可。

    Collision Matrix

    参考资料

    【1】https://jingyan.baidu.com/article/48b558e30d18947f38c09a2e.html

    展开全文
  • BagPanel管理着全部 格子,格子管理具体物品,SlotItem是具体物品。 代码: using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 背包容器 /// </...

    BagPanel管理着全部 格子,格子管理具体物品,SlotItem是具体物品。

    代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 背包容器
    /// </summary>
    public class BagPanel : MonoBehaviour, BagInterface
    {
        public GameObject slotItemPrefab;
        //背包全部格子
        private Slot[] slotArr;
    
        private void Start()
        {
            slotArr = transform.GetComponentsInChildren<Slot>();
        }
    
        private void Update()
        {
            //右击添加物体
            if (Input.GetMouseButtonDown(1))
            {
                AddBagItem();
            }
        }
    
        /// <summary>
        /// 添加物品
        /// </summary>
        public void AddBagItem()
        {
            Slot slot = GetEmptySlot();
            if (slot != null)
            {
                GameObject slotItemGo = GameObject.Instantiate(slotItemPrefab);
                slotItemGo.transform.SetParent(slot.transform);
                slotItemGo.transform.localPosition = Vector3.zero;
            }
        }
        
        /// <summary>
        /// 获取空格子
        /// </summary>
        private Slot GetEmptySlot()
        {
            for (int i = 0; i < slotArr.Length; i++)
            {
                if (slotArr[i].transform.childCount == 0)
                {
                    return slotArr[i];
                }
            }
            return null;
        }
    }
    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public interface BagInterface{
    
        /// <summary>
        /// 添加物品
        /// </summary>
        void AddBagItem();    
    }
    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 背包格子
    /// </summary>
    public class Slot : MonoBehaviour {
    
        //可以做一些格子才能做到的事情,因为它管理着具体的物品,可以添加一些使用道具的方法
        //选中后使用道具,选中后销毁道具,选中后升级道具等操作。
        //道具数量可直接放在SlotItem,也可以放在Slot,区别不大,只是放在Slot在移动Item时,还要处理Slot的数量,而放在SlotItem的话 就直接在SlotItem一起处理完毕。
        //反正,目前的小案例是不需要使用到这个Slot去完成BagPanel管理者与SlotItem进行交互的
        
    }
    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    /// <summary>
    /// 背包物品
    /// </summary>
    public class SlotItem : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
    {
        private bool IsHover = false;
        private Image image;     
        private void Start()
        {
            image = GetComponent<Image>();
        }
        private void Update()
        {
            if (IsHover)
            {
                this.transform.position = Input.mousePosition;
            }
        }
        //鼠标按下
        public void OnPointerDown(PointerEventData eventData)
        {
            IsHover = true;
            image.raycastTarget = false;//当鼠标拿起物品后,物品不能接收鼠标射线,为的就是能让下面的方法拿到放下的格子
        }
    
        /// <summary>
        /// 鼠标抬起
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerUp(PointerEventData eventData)
        {
            //拿到物品到放下的格子物体(注意:因为我们在拿起的时候把鼠标上物品的raycastTarget=false,所以现在pointerCurrentRaycast射线是碰不到鼠标上的物品的,而是它下面的物体
            GameObject upGo = eventData.pointerCurrentRaycast.gameObject;
            Debug.Log(upGo.name);
            //若放下的区域已经有物品存在,此时upGo是要放下的格子的道具物体
            if (upGo.GetComponent<SlotItem>() != null)
            {
                //交换
                GameObject upGoChild = upGo;
                Transform mouseGoParent = this.transform.parent;
                this.transform.SetParent(upGoChild.transform.parent);
                this.transform.localPosition = Vector3.zero;//这句代码就是居中显示.
                upGoChild.transform.SetParent(mouseGoParent);
                upGoChild.transform.localPosition = Vector3.zero;            
            }
            else
            {            
                this.transform.SetParent(upGo.transform);//此时upGo是空格子Slot
                this.transform.localPosition = Vector3.zero;
            }
            IsHover = false;
            image.raycastTarget = true;//别忘记恢复物品能检测射线,不然你再按就拿不起来了。。
        }
    }
    

    重要点PointerEventData的pointerCurrentRaycast可理解为一条射向鼠标点的射线,为了防止鼠标上已经拿着的物品 阻挡着射线,而设置了物品身上的Image组件的raycastTarget,若你的物品是很复杂的,建议在物品身上加CanvasGroup,再把Blocks Raycasts取消勾选即可,如下:

    好了,最基本的背包功能差不多就这样,其他的也就是差不多的。。

    展开全文
  • Unity3d】碰撞检测

    2016-07-20 14:50:20
    Unity3d碰撞器 一.碰撞发生的必要条件: 1.产生碰撞效果需要具备两个因素 a.发起碰撞的物体 b.接收碰撞的物体 2发起碰撞的物体 a.Rigidbody b.CharacterController 3.接受碰撞的物体 a.所有的Collider ...
  • Unity3D UGUI User Interface 用户界面 GUI:优点使用简单,有专一性。缺点:代码繁琐,屏幕自适应差。 常用来当调试工具,还有editor编辑器的开发 UGUI:亲儿子,优点:使用灵活。层级清晰。屏幕自适应。缺点:...
  • Unity3D开发之NGUI点击事件穿透响应处理 2013年03月19日 ⁄ 综合 ⁄ 共 300字 ⁄ 字号 小 中 大 ⁄ 评论关闭   在使用NGUI 开发2D项目的时候,发现了一个问题,就是如果点出一个菜单,然后点击...
  • 当场景中包含大量的模型时,势必会造成渲染效率的降低,如果使用遮挡剔除(Occlusion Culling)技术,可以使得那些被阻挡的物体不被 渲染,从而达到提高渲染效率的目的。 在默认的渲染管线中也会根据摄像机的...
  • 在做ui栏滚动的时候,物品上下滚动,当某个物品在顶格或者在底格的时候,这时候需要滚出去,会有一部分在ui上,一部分要消失,如图:箭头指向的部分需要隐藏掉。开始吧,需要两个相机,一个ui相机,一个ui模型相机,...
  • 2、有UI界面(如物品栏)显示后,点击事件穿过UI到小怪身上去了(按道理UI界面显示的时候,后面的应该不响应) 问题: UI系统如何block住raycast? 尝试: 1、给UI系统的canvas增加canvas group,将...
  • 文章写于2016-1-31,后有修改。 本文为本人原创,转载请注明。 以下为正文 …………………………………………………………………………………………………………………………………… ...游戏AI常常分为三大部分...
  •  像是一个简单的背包,用来存储物品对象就OK了,但是那完全满足不了要求,至少像是拖拽、交换、拖入、切换栏目以及再加点炫酷特效啥的这些都要用吧! 拖拽啥的很简单,一会搞定,但是当做到射线检测的时候直接卡住...
  • This chapter discusses broader issues withstructuring unity UIs. 本章更广泛地讨论Unity UI结构问题。 Remediatingfill-rate issues 解决填充率问题 There are two courses of ac
  • 自己在学习UGUI背包系统时用到了,而且遇到一些问题,所以在这里写一下这两个接口的简单说明。 继承IPointerEnterHandler和IpointerExitHandler这两个接口后可以实现两个方法。Void OnPointerEnter...
  • 滑动条对话框用在购买物品和出售物品时的个数选择 ,同时也能有效避免玩家的误碰操作。 该对话框主要使用了滑动条,两个按钮控件以及数个标签控件,它对应的UI文件是scene/slider_dialog.xml。(使用了其他引擎请...
  • 3D游戏制作——AI坦克对战 github地址(码云) ... 本次3D游戏的制作使用了 Unity Assets Store 中的 Kawaii Tank 模型。 AI坦克建模——感知-思考-行为模型 感知 在游戏中,程序是...
  • 1.LOD技术 层次细节(LOD),它是根据物体在游戏画面中所占视图的百分比来调用不同复杂度的模型的。简单而言,就是当一个物体距离摄像机比较远的时候使用低模,当物体距离摄像机比较近的时候使用高模。...
  • 怎样自己用素材做一个装备系统:包括背包面板、物品格子、物品装备;装备放入背包;在背包内移动、交换、叠加装备. 恩,事实证明这不是B站UP主李三影原创,完全照抄自GameGrind却提都没提,Shame On You!改标题! ...
  • 网站导出20190118

    2019-01-18 11:07:02
    Bookmarks   书签栏   重要网站 ...Artlist.io - Music ...unity3d插件免费下载 商业资源代购 团购 unity外包 Unity时空 淘宝网 - 淘!我喜欢 Unity - Scripting API: AudioClip 3D模型/环境 unity3...
  • 一.为什么要设计任务系统 1. 体现世界观世界观 指主线剧情,历史背景,塑造主角的成长历程。...WOW中的任务虽然不是必须完成的,但是顺着部落主线的剧情延伸至南海镇的任务却是很明显的主线剧情,从亡灵新手村...
1 2
收藏数 25
精华内容 10
热门标签
关键字:

3d物品阻挡 unity3d