unity3d游戏_unity3d游戏血条 - CSDN
精华内容
参与话题
  • Unity3D游戏开发——塔防小游戏

    万次阅读 2017-08-07 11:22:35
    游戏效果图: 本文参照siki学院的塔防游戏教程写的。http://www.sikiedu.com,搜索塔防游戏登入即可观看。 游戏流程: 1.首先创建cube调整其大小(以便计算),然后将其设成预设体(以便之后统一操作),利用...

    游戏效果图:


    本文参照siki学院的塔防游戏教程写的。http://www.sikiedu.com,搜索塔防游戏登入即可观看。

    游戏流程:

    1.首先创建cube调整其大小(以便计算),然后将其设成预设体(以便之后统一操作),利用ctrl+D复制弄出地形,在Hierarchy视图上创建一个map文件夹保存其文件。然后在地形内删除cube,创出自己想要的敌人行走路径。

    2.在每个转折处设置一个Gameobject文件夹,然后在Transform上放修改一种颜色(以便区分),

    将其命名为Waypoint并设置成预设体,创建一个Waypoint文件夹保存所有的Waypoint。在预设体上加上脚本Waypoint:

    public class Waypoint : MonoBehaviour {
        public static Transform[] p;//定义数组
        private void Awake()//在脚本执行时执行
        {
            //获取每个数组的参数,也就是节点位置
            p = new Transform[transform.childCount];
            for (int i = 0; i < p.Length; i++) {
                p[i] = transform.GetChild(i);
            }
        }
    }

    在Scence场景上新建一个Sphere(当成敌人)然后将其放在起点,加上脚本Enemy:

    public class Enemy : MonoBehaviour {

        public float speed = 10;//设置敌人的速度
        private Transform[] p;//定义数组

    void Start () {
            p = Waypoint.p;//调用Waypoint脚本获取节点的位置信息
        }

    void Update () {
            Move();//每一帧执行方法
    }

    void Move() {
            transform.Translate((p[index].position-transform.position).normalized*Time.deltaTime*speed);//移动,节点到当前位置的向量差的单位差*完成上一帧的时间*速度

            if (Vector3.Distance(p[index].position, transform.position) < 0.2f)//三维坐标,距离(节点,当前位置)小于0.2f的时候执行
            {
                index++;//增加索引,也就获取到下个节点坐标
                if (index > p.Length - 1)//如果大于最后一个节点时执行
                {
                    Destroy(this.gameObject);//销毁物体
                }
            }
        }

    }

    这样就能让物体按照指定的坐标移动起来。

      3. 控制游戏的视野(设置摄像机),首先把摄像机调整到一个合适的状态(向上移动一定的位置,x轴旋转45°),之后来用脚本控制摄像机的移动,添加脚本Move():

    public class move : MonoBehaviour {
    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
            float a = Input.GetAxis("Horizontal");//当按下的左右方向(a,d 方向键的左右 4,6)时获取到一个-1到1的值
            float b = Input.GetAxis("Vertical");//当按下的上下方向(w,s 方向键的上下 8,2)时获取到一个-1到1的值
            float m = Input.GetAxis("Mouse ScrollWheel")*-8;//鼠标滚轮缩放
            transform.Translate(new Vector3(a,m,b)*Time.deltaTime*50,Space.World);//转为世界坐标移动
    }
    }

    4.创建一个Gameobject命名为fuhuaqi代表敌人孵化器(用来控制敌人的生成),首先写一个封装类来保存每一波敌人的类型,总数,速度,封装类命名为Bo:

    [System.Serializable]//可序列化,就是能被其他代码引用的意思
    public class Bo {
        public GameObject e;//敌人的类型
        public int count;//敌人的总数
        public float rate;//每个敌人的间隔
    }

    之后再fuhuaqi上写上控制敌人生成的脚本Enemyfuhuaqi:

    public class Enemyfuhuaqi : MonoBehaviour {

        public Bo[] b;//封装类
        public Transform start;//定义开始位置
        public float jiange = 3;//每波的间隔

        private Coroutine coroutine;//定义协同,方便控制协同的启动和停止

        void Start () {
           coroutine= StartCoroutine(Move());//启动协程
        }

        public void Stop()
        {
            StopCoroutine(coroutine);//停止协程
        }

    //协程
        IEnumerator Move() {
            foreach (Bo b in b)
            {
                for (int i = 0; i < b.count; i++)//循环生成
                {
                    GameObject.Instantiate(b.e,start.position,Quaternion.identity);//创建(生成种类,生成位置,不旋转)
                    if (i != b.count - 1)
                    {
                        yield return new WaitForSeconds(b.rate);//协程中的等待(同样敌人的间隔)
                    }
                }    
               yield return new WaitForSeconds(jiange);//完成一波后等待间隔的时间
        }

    }

    写好脚本后记得给相对应的东西赋值!

    5.右键点击Assets->import package->custom package选择载好的材料包,将建筑模型拖入Scence然后在Transform的右侧的齿轮Reset,调整位子(注:选中模型里面所有子物体进行调整,因为之后要按照模型定位与地图方块的地位相同,不让其陷入地板),给对应的位置上材质。做好后设置成Prefab。

    6.开始设置UI界面,首先创建一个Canvas(画布),点击Scence上的2D按钮界面会变成2D界面比较容易操作,在画布里在创建一个Gameobject(名称:Switch)在其下创建3个Canvas存放炮塔的图标在其下再创建image(名:background)和text(用来存放炮塔的图标图片和价格)在其background下创建image(名:Checkmark 用来表示被选中状态)将其中Soure image 属性改成Knob然后改变颜色改变透明度

    给Switch添加属性Toggle group将每个炮塔添加属性Toggle并is on属性都取消,将Checkmark拖入Graphic,将Group都设置成Switch(表示在一个组里面)

    7.在主Canvas下创建Text(名:money)用来显示当前的钱,设置一段动画让钱不够时会闪烁,选择菜单栏上的windows->animation->create->选择保存到Animations文件夹(文件夹自己定义),点击红点开始录制,然后按照喜好变化就好。双击动画进入编辑界面:


    再fuhuaqi上添加脚本buildguanliqi,将定义好的文本和动画赋值上去

    8.创建炮塔,首先选中右侧建造的炮塔,检查mapcube上是否为空,并且鼠标点击mapcube,即可建造。加上粒子效果,建造后money减少。

    9.创建子弹,在头部定义子弹的位置实例化子弹,然后给炮塔加一个Shpere collider用来检测进入的敌人并用数组存放,并且默认攻击第一个,超出范围或者敌人死亡移除该物体在数组中的位置

    10.升级炮塔,检测mapcube上是否有物体存在,物体是否升级过,钱是否够,满足条件这摧毁先前物体,新建升级物体并播放特效。

    11.敌人全部死亡,显示胜利,到达终点则显示失败;

    展开全文
  • 在两个月前曾写了一篇《【Unity3D实战】零基础一步一步教你制作跑酷类游戏(1)》,里面一步一步演示了制作跑酷类游戏,然而由于时间原因,只写到了让角色往前移动为止。这个坑一直没有时间去填,(虽然也没多少人看...

    在两个月前曾写了一篇《【Unity3D实战】零基础一步一步教你制作跑酷类游戏(1)》,里面一步一步演示了制作跑酷类游戏,然而由于时间原因,只写到了让角色往前移动为止。这个坑一直没有时间去填,(虽然也没多少人看啦),今天刚好有时间完成了一个跑酷类游戏的Demo。放上来给有兴趣的朋友看看。

    Demo源码及对应素材下载:链接: https://pan.baidu.com/s/1smnQFt7 密码: ptcw

    游戏简要说明

    游戏类型:跑酷类游戏(Demo,非完整游戏)

    操作方式:左右方向键(可自己移植到手机端)

    游戏要素:

    1.游戏角色会自动向前跑,玩家可通过左右方向键让其左右移动

    2.游戏中存在障碍物,玩家需避开这些障碍物,否则会因为被障碍物阻挡的原因无法前进

    3.当游戏角色因为被阻挡而消失在视野中时,视为失败

    4.当游戏角色因为被阻挡而处于偏后方时,会提高移动速度直到回到原本所处的屏幕位置

    游戏场景搭建

    使用准备好的素材(路面、人物、障碍物),将这些素材制作成Prefab,然后根据自己喜好搭建好场景(如何搭建请看上一篇教程:《【Unity3D实战】零基础一步一步教你制作跑酷类游戏(1)》)。如下图:

    游戏脚本编写

    游戏角色控制器moveController:
    新建一个C#文件,命名为moveController,然后将其打开。
    由于角色需要向前、左、右三个方向移动,所以我们需要有其在前进方向上的速度左右方向上的速度,分别命名为:moveVSpeed、moveHSpeed,
    同时由于玩家在落后的情况下需要加速,所以我们声明两个变量:前进方向上的最小移动速度minVSpeed前进方向上的最大移动速度maxVSpeed
    于是我们可以得到以下脚本:
    // 前进移动速度
    float moveVSpeed;
    // 水平移动速度
    public float moveHSpeed = 5.0f;
    // 最大速度
    public float maxVSpeed = 10.0f;
    // 最小速度
    public float minVSpeed = 5.0f;
    其中moveHSpeed、maxVSpeed、minVSpeed声明为public,方便在面板上修改。

    错误修改:感谢 jewis123 朋友提出的,这里漏了jumpHeight与m_jumpState的定义,前者代表最大高度,后者代表当前是向上跳跃,还是从高处落下,详细可查看源码。

    接下来,在Start()函数中定义moveVSpeed的初始值:
            moveVSpeed = minVSpeed;
    在Update()中使人物能移动起来:
            float h = Input.GetAxis("Horizontal");
            Vector3 vSpeed = new Vector3(this.transform.forward.x, this.transform.forward.y, this.transform.forward.z) * moveVSpeed ;
            Vector3 hSpeed = new Vector3(this.transform.right.x, this.transform.right.y, this.transform.right.z) * moveHSpeed * h;
            Vector3 jumpSpeed = new Vector3(this.transform.up.x, this.transform.up.y, this.transform.up.z) * jumpHeight * m_jumpState;
            this.transform.position += (vSpeed + hSpeed + jumpSpeed) * Time.deltaTime;
    保存一下cs文件,切换到Unity,将该脚本挂载在角色对象的身上,保留默认值或手动设置:


    运行游戏,看看是否能成功跑起来,并且能通过左右键控制人物左右移动。

    看着人物越跑越远越跑越远,最后消失在远方......诶!教练,这和说好的不一样啊!人物咋不见了?

    咳咳,这是因为我们没有让摄像机跟随它的原因,接下来,我们让摄像机与人物一起移动~

    打开刚才的C#文件,声明一个public的变量

        // 摄像机位置
        public Transform cameraTransform;

    在Update()函数中,添加以下代码:

    // 设置摄像机移动速度
    Vector3 vCameraSpeed = new Vector3(this.transform.forward.x, this.transform.forward.y, this.transform.forward.z) * minVSpeed;
    // 让摄像机跑起来
    cameraTransform.position += (vCameraSpeed) * Time.deltaTime;

    注意到没,这里我们所定义的摄像机的移动速度与人物移动速度有点差别:
    1.摄像机没有左右移动
    2.摄像机的速度恒定为minVSpeed,也就是我们所定义的人物的最小移动速度(当然这个时候人物也一直是以这个速度在移动)

    转到Unity,查看人物身上的Move Controller组件,现在这里应该多了一个变量等你设置:

    我们将摄像机拖动到camera Transform处,再运行游戏。这时候你应该能看到人物在不断往前走,但在屏幕上的位置是没有变化的,因为摄像机一起移动了。

    人物走着走着 哎呀 前面怎么没路了?别急,让我们来让路无限延长起来~

    首先我们将道路的GameObject复制几个,我这里是总共有3个道路的GameObject,分别命名为Road1,Road2,Road3

    然后在每一个Road下,添加一个Cube,将Cube的Mesh Renderer关闭,并将其Box Collider的Is Trigger勾上。命名为ArrivePos。(我才不会告诉你们这一步应该在上一行之前做呢!)

    多条道路拼好,连成一条笔直的公路。

    然后新建一个空物体,命名为GameManager,为其新建C#Script  GameManager.cs,然后打开该脚本。

    声明一下多个变量:(注意引用命名空间using System.Collections.Generic;
        // 生成障碍物点列表
        public List<Transform> bornPosList = new List<Transform>();
        // 道路列表
        public List<Transform> roadList = new List<Transform>();
        // 抵达点列表
        public List<Transform> arrivePosList = new List<Transform>();
        // 障碍物列表
        public List<GameObject> objPrefabList = new List<GameObject>();
        // 目前的障碍物
        Dictionary<string, List<GameObject>> objDict = new Dictionary<string, List<GameObject>>();
        // 道路间隔距离
        public int roadDistance;
    并定义函数:
        // 切出新的道路
        public void changeRoad(Transform arrivePos)
        {
            int index = arrivePosList.IndexOf(arrivePos);
            if(index >= 0)
            {
                int lastIndex = index - 1;
                if (lastIndex < 0)
                    lastIndex = roadList.Count - 1;
                // 移动道路
                roadList[index].position = roadList[lastIndex].position + new Vector3(roadDistance, 0, 0);
    
                initRoad(index);
            }
            else
            {
                Debug.LogError("arrivePos index is error");
                return;
            }
        }
    
        void initRoad(int index)
        {
            
            string roadName = roadList[index].name;
            // 清空已有障碍物
            foreach(GameObject obj in objDict[roadName])
            {
                Destroy(obj);
            }
            objDict[roadName].Clear();
    
            // 添加障碍物
            foreach(Transform pos in bornPosList[index])
            {
                GameObject prefab = objPrefabList[Random.Range(0, objPrefabList.Count)];
                Vector3 eulerAngle = new Vector3(0, Random.Range(0, 360), 0);
                GameObject obj = Instantiate(prefab, pos.position, Quaternion.EulerAngles(eulerAngle)) as GameObject;
                obj.tag = "Obstacle";
                objDict[roadName].Add(obj);
            }
        }

    在Start()中:
        void Start () {
            foreach(Transform road in roadList)
            {
                List<GameObject> objList = new List<GameObject>();
                objDict.Add(road.name, objList);
            }
            initRoad(0);
            initRoad(1);
        }
    然后打开之前的moveController.cs,声明变量:
        // 游戏管理器
        public GameManager gameManager;
    定义函数:
        void OnTriggerEnter(Collider other)
        {
            // 如果是抵达点
            if (other.name.Equals("ArrivePos"))
            {
                gameManager.changeRoad(other.transform);
            }
            // 如果是透明墙
            else if (other.tag.Equals("AlphaWall"))
            {
                // 没啥事情
            }
            // 如果是障碍物
            else if(other.tag.Equals("Obstacle"))
            {
    
            }
        }
      呼,一大串代码,大家敲的累不累,什么!你是copy过去的?太过分了!我要拿刀子了!

    嗯,切换回Unity中,点击GameManager这个物体,设置其GameManager组件的值:


    这里的BornPos指的是障碍物出生点,以下图所示为每一条道路定义一个或多个出生点,每条路的出生点用一个BornPos的空物体进行管理:
    然后将出生点按其所处道路的序号一一拖入(先设置size的值,3条就设置为3)
    RoadList也是一样,将道路按序号一一拖入。

    这里的ArrivePosList要注意一下,并不是直接按道路序号拖入,而是往后一位,即:
    road2
    road3
    ........
    roadn
    road1
    这样的顺序将其对应的ArrivePos拖入列表

    然后将需要生成的障碍物的Prefab文件拖入ObjPrefabList
    设置道路的间隔距离(即一条道路的中心点到接下来一条道路中心点的距离 distance = road1.length / 2 + road2.length / 2 大概这么计算)

    到这一步为止,GameManager的设置基本完成。点击人物的GameObject,设置moveController,将GameManager的游戏对象拖入到指定位置:


    对了,还有一步非常重要的设置:
    为人物添加Collider与RightBody,为所有障碍物和路面添加Collider(注意不要勾上Is Trigger)

    然后运行游戏。

    呼,这时候没有问题的话应该是能看到有障碍物出现了,人物走到障碍物处会被挡住,并且道路会自动拼接移动,无止境的走下去、走下去、走下去。。。

    这个Demo也基本进入尾声了,接下来,做最后的游戏失败判断和让角色赶回正常位置。

    打开GameManager.cs,声明变量:

        public bool isEnd = false;

    打开moveController.cs 声明变量:

        // 摄像机距离人物的距离
        public float cameraDistance;

    在Update()函数中 添加以下代码:
    // 当人物与摄像机距离小于cameraDistance时 让其加速
            if(this.transform.position.x - cameraTransform.position.x < cameraDistance)
            {
                moveVSpeed += 0.1f;
                if (moveVSpeed > maxVSpeed)
                {
                    moveVSpeed = maxVSpeed;
                }
            }
            // 超过时 让摄像机赶上
            else if(this.transform.position.x - cameraTransform.position.x > cameraDistance)
            {
                moveVSpeed = minVSpeed;
                cameraTransform.position = new Vector3(this.transform.position.x - cameraDistance, cameraTransform.position.y, cameraTransform.position.z);
            }
            // 摄像机超过人物
            if(cameraTransform.position.x - this.transform.position.x > 0.0001f)
            {
                Debug.Log("你输啦!!!!!!!!!!");
                gameManager.isEnd = true;
            }

    定义OnGUI()函数:
    void OnGUI()
        {
            if (gameManager.isEnd)
            {
                GUIStyle style = new GUIStyle();
    
                style.alignment = TextAnchor.MiddleCenter;
                style.fontSize = 40;
                style.normal.textColor = Color.red;
                GUI.Label(new Rect(Screen.width / 2 - 100, Screen.height / 2 - 50, 200, 100), "你输了~", style);
    
            }
        }

    到这一步,Demo编写完成。(由于现在是凌晨4点 实在太疲惫,所以本篇基本都是直接贴代码,如果有朋友有什么问题的话 可以直接留言哈~)

    展开全文
  • unity3D汽车游戏

    热门讨论 2020-07-19 23:34:16
    unity3D做的一个简单的汽车游戏,这是初级版~~~~大家可以下来看一下哦
  • Unity3D-----简易游戏项目开发01

    千次阅读 2020-06-07 10:25:38
    城市激斗一、简介1、所需知识点2、游戏需求 一、简介 1、所需知识点 (1)射线检测 (2)Mecanim动画系统 (3)Navigation寻路系统 (4)OGUI (5)欧拉角与四元数、向量 (6)持久化数据 2、游戏需求 (1)、开始...

    一、简介

    1、所需知识点

    (1)射线检测
    (2)Mecanim动画系统
    (3)Navigation寻路系统
    (4)UGUI
    (5)欧拉角与四元数、向量
    (6)持久化数据

    2、游戏需求

    (1)开始界面(人物换装),到游戏场景角色诞生,诞生的角色穿着换装界面存储的服装。

    (2)随机在3个诞生点,一共产生3波怪(每波怪2-3个即可)。

    (3)怪物头顶有血条,随着波数的累加怪物越来越难打(血量多)。

    (4)角色与怪之间动画互动(Mecanim动画系统),如:角色射线打到怪物,角色播放攻击动画,怪播放受到攻击的动画。

    (5)敌人,角色血条效果。

    (6)打敌人,随机产生掉装备,吃到掉的装备可实现例如加血的效果。

    (7)打死3波怪后胜利画面,自己血条值为0时GameOver画面 。

    二、开始界面

    先上图,看看最终完成是什么样的!
    在这里插入图片描述
    在点击不同的按钮有不同的事件响应,按钮功能就不进行说明了。
    按钮功能实现逻辑: 以上按钮可以分为四种按钮,分别是角色选择、服装选择、武器选择、动作预览。
    那么我们就可以按这四种分类将功能进行实现,创建一个空物体,将一个种类的按钮作为此空物体的孩子,编写的脚本就给予空物体,那么给按钮添加事件就需要遍历所有的子物体,然后添加按钮点击事件。而点击按钮需要实现功能,我就拿角色选择按钮来举例,另外三种按钮的脚本可以仿照此逻辑进行编写;
    角色选择按钮功能实现: 在点击按钮后,我需要进行角色物体的创建,那么按钮和预制件之间就需要有响应,那么如何根据我们点击的按钮来创建指定的角色呢?我们可以通过按钮名字与预制件名字来进行联系,将按钮名字设置成为预制件的名字 (按钮名字也可以不和预制件名字相同,但是必须包含预制件名字),那么功能的实现就比较简单了,可以创建字典,key值为按钮名字,value值为gameobject类型,存储角色预制件,那么我们在点击按钮的时候就可以根据按钮名字直接获取预制件进行创建角色物体了。另三种按钮功能请自行类推了~
    温馨提示:代码编写当中的细节问题在代码注释中有说明

    1、开始界面按钮功能代码

    • 角色选择功能
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    
    public class GenerateRole : MonoBehaviour
    {
        public GameObject[] gameRole;
        public Transform vec;
        private Dictionary<string,GameObject> dic;
        public static GameObject Role { get; set; }
        public GenerateRole() { }
        private void Start()
        {
            //初始化字典
            dic = new Dictionary<string, GameObject>();
            //遍历所有的孩子,给按钮添加点击事件
            AddEevent();
        }
        //因按钮和预制件的名字不一样
        //所以需要对name进行切割
        private void GetButtonName()
        {
            var button = EventSystem.current.currentSelectedGameObject;
            CreateRole(button.name.Substring(4));      
        }
        //遍历所有孩子添加,给按钮添加点击时间
        private void AddEevent()
        {
            string name;
            for (int i=0;i<transform.childCount;i++)
            {
                name = transform.GetChild(i).name.Substring(4);
                //将游戏物体添加至字典当中
                //每次点击按钮,就将按钮的名字和游戏物体存入字典
                //避免重复点击按钮时,需要重复遍历
                for (int x=0;x<gameRole.Length;x++)
                {
                    if (gameRole[x].name == name)
                    {
                        dic.Add(name,gameRole[x]);
                    }
                }
                transform.GetChild(i).GetComponent<Button>().onClick
                    .AddListener(new UnityAction(GetButtonName));
            }
        }
        //创建游戏物体
        private void CreateRole(string name)
        {
            //如果vec有孩子,则销毁后再创建,如果没有则直接创建
            GameObject deleteClone;
            int childCount = vec.childCount;
            if (childCount==1)
            {
                //若是创建的游戏物体就是这个孩子,则不进行任何代码执行
                //因名字包含Clone,所以还需要对名字进行改变再判断
                //Debug.Log(vec.GetChild(0).name);
                if (vec.GetChild(0).name==(name+"(Clone)"))
                {
                    return;
                }
                deleteClone = vec.GetChild(0).gameObject;
                Destroy(deleteClone);
                SetParent(name);
            }
            else if (childCount == 0)
            {
                SetParent(name);
            }       
        }
        private void SetParent(string name)
        {
            GameObject clone = Instantiate(dic[name], vec.position, Quaternion.identity);
            Role = clone;
            //将创建的游戏物体设置为vic的子类
            clone.transform.SetParent(vec);
        }
    }
    
    • 武器选择功能
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    public class WeaponChose : MonoBehaviour
    {
        //创建武器位置
        private Transform weaponLocal;
        public GameObject[] weapons;
        private Dictionary<string, GameObject> dic;
        private void Start()
        {
            //字典进行初始化
            dic = new Dictionary<string, GameObject>();
            AddEvent();
            DicAddWeapon();
        }
        //遍历所有孩子,添加按钮点击事件
        /// <summary>
        /// 添加点击事件
        /// </summary>
        private void AddEvent()
        {
            for (int i = 0; i < transform.childCount; i++)
            {
                transform.GetChild(i).GetComponent<Button>().onClick
                    .AddListener(new UnityAction(CreateWeapon));
            }
        }
        //将所有武器类型添加进入字典当中
        private void DicAddWeapon()
        {
            string name;
            for (int i = 0; i < transform.childCount; i++)
            {
                name = transform.GetChild(i).name.Substring(4);
                for (int index = 0; index < transform.childCount; index++)
                {
                    if (name == weapons[index].name)
                    {
                        dic.Add(name, weapons[index]);
                    }
                }
            }
        }
        //点击事件
        //根据按钮的名字来创建武器
        /// <summary>
        /// 创建武器
        /// </summary>
        private GameObject clone;
        private void CreateWeapon()
        {
            //按钮名字
            string buttonName = EventSystem.current.currentSelectedGameObject.name.Substring(4);
            //给武器寻找位置
            weaponLocal = GameObject.Find("wphand").transform;
            if (weaponLocal != null)
            {
                //如果wphand不存在孩子,则直接创建,否则进行二次判断
                if (weaponLocal.childCount == 1)
                {
                    //如果孩子的名字就是所点击按钮的名字,那么就直接结束程序
                    if (weaponLocal.GetChild(0).name == (buttonName + "(Clone)"))
                    {
                        return;
                    }
                    //否则进行武器的创建,并销毁原来的物体
                    Destroy(clone);
                    SetParent(buttonName);
                }
                else
                    //进行名字切割并创建武器
                    SetParent(buttonName);
            }
            else Debug.Log("请先创建游戏角色");
        }
        private void SetParent(string buttonName)
        {
            clone = Instantiate(dic[buttonName], weaponLocal.position, Quaternion.Euler(180, -105, 0));
            clone.transform.SetParent(weaponLocal);
        }
    }
    
    • 服装选择功能
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    public class ChoseCloth : MonoBehaviour
    {
        /*
         * 需要先知道目前所选择的角色是谁,才能够进行衣服的选择
         *1、去HereCreate中获取创建的角色是谁
         *2、在人物创建时,给一个人物返回值Role即可
         *可用二维字典进行存储,第一个参数为角色,第二个参数为衣服号码
         */
        //获取的名字是带有Clone的,需要进行处理
        private GameObject role;
        public Texture[] cloths;
        private Dictionary<string, Dictionary<string, Texture>> dic;
       // private Renderer rend;
        //数据初始化
        private void Start()
        {
            dic = new Dictionary<string, Dictionary<string, Texture>>();       
            DicAddCloth();
            AddButtonEvent();
        }
        private void DicAddCloth()
        {
            int index = 0;
            //存储的种类名字,四种衣服
            string[] clothname=new string[4];
            string[] name;
            string newName = null;
            //遍历cloths数组,将其添加至二维数组
            foreach (Texture cloth in cloths)
            {
                //衣服名字格式为mon_goblinWizard_c2_df
                //将名字切割,取第二个goblinWizard,再加上(Clone),再为其添加衣服
                name = cloth.name.Split('_');
                if (Array.IndexOf(clothname, name[1])==-1)
                {
                    clothname[index++] = name[1];
                    dic.Add(name[1], new Dictionary<string, Texture>());
                    //Debug.Log("clothname:"+name[1]);
                }            
                dic[name[1]].Add((dic[name[1]].Count+1)+"", cloth);
               // Debug.Log(newName[1]);
            }
        }
        private void AddButtonEvent()
        {
            for (int i=0;i<transform.childCount;i++)
            {
                transform.GetChild(i).GetComponent<Button>().onClick.AddListener
                    (new UnityAction(ButtonEvent));
            }
        }
        /// <summary>
        /// 触发事件,更换衣服
        /// </summary>
        private void ButtonEvent()
        {
            //获取角色
            role = GenerateRole.Role;
            //根据按钮名字来更换衣服
            string buttonName = EventSystem.current.currentSelectedGameObject.name;
            //按钮名字格式为btn_col_02
            //获取最后一个数字即可        
            string clothName = buttonName.Substring(buttonName.Length-1);
            if (role != null)
            {
                //将role.name的名字进行切割
                string[] RoleName = role.name.Split('(');
                string[] RoleName01 = RoleName[0].Split('_');
                //Debug.Log("衣服名字"+clothName);
                //Debug.Log("角色名字" + role.name);
                //Debug.Log("种类名字:"+ RoleName01[1]);
                role.GetComponentInChildren<SkinnedMeshRenderer>().material.mainTexture
                = dic[RoleName01[1]][clothName];
            }
            else { Debug.Log("请先创建游戏角色"); }        
        }
    }
    
    • 动作预览功能
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    public class ActionPlay : MonoBehaviour
    {
        /*
         * 动作按钮的播放设置
         */
        //获取游戏对象
        private GameObject role;
        private Animation ani;
        private void Start()
        {
            AddEvent();
        }
        //给每个按钮添加点击事件
        private void AddEvent()
        {
            for (int i=0;i<transform.childCount;i++)
            {
                transform.GetChild(i).GetComponent<Button>().onClick.
                    AddListener(new UnityAction(PlayAction));
            }
        }
        /// <summary>
        /// 播放动画
        /// </summary>
        private void PlayAction()
        {
            role = GenerateRole.Role;
            string buttonName = EventSystem.current.currentSelectedGameObject.name;
            string[] newName = null;
            if (role!=null)
            {
                ani = role.GetComponent<Animation>();
                newName = buttonName.Split('_');
                ani.Play(newName[newName.Length-1]);//字符串为按钮名字切割后的字符串
                ani.CrossFadeQueued("Idle");
            }
        }
    }
    

    人物模型连接(含UI贴图)------MonsterBaseTeam.rar
    其他功能的实现请见 Unity3D-----简易游戏项目开发02
    Unity3D-----简易游戏项目开发02

    展开全文
  • 游戏会为玩家呈现一个“故事卡”。故事卡上包含一些文字,其中一部分是用于描述玩家当前的状态,另外一部分是在当前情况下玩家可以做出的一系列选择。 根据玩家的不同选择,剧情也会按照不同的分支向前发展,并持续...

    推荐阅读

    一、前言

    游戏灵感来自于“火柴人亨利(Henry Stickmin)”系列游戏,以及一些上世纪80年代的《惊险岔路口》冒险丛书。游戏根据玩家的不同选择来展开故事情节,通常会拥有多重结局。

    效果图
    在这里插入图片描述

    二、示例工程下载

    https://download.csdn.net/download/q764424567/12472942

    三、程序设计

    3-1、基本程序设计(故事卡)

    游戏会为玩家呈现一个“故事卡”。故事卡上包含一些文字,其中一部分是用于描述玩家当前的状态,另外一部分是在当前情况下玩家可以做出的一系列选择。

    在这里插入图片描述
    根据玩家的不同选择,剧情也会按照不同的分支向前发展,并持续出现新的卡片与选择,直到最终的卡片不再有新的选择,则游戏结束。

    制作一张“故事卡”很简单。根据上诉需求,我们新建StoryItemBase脚本,脚本代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class StoryItemBase : MonoBehaviour
    {
        // Use this for initialization
        void Start()
        {
        }
    
        // Update is called once per frame
        void Update()
        {
        }
    
        public virtual void Activate(GameManager gm)
        {
        }
    }
    

    我们新建StoryCard脚本,脚本代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class StoryCard : StoryItemBase
    {
        public string Description;
    
        public string[] Options;
        public StoryItemBase[] Items;
    
        public StoryState[] StatesToSetTrue;
        public StoryState[] StatesToSetFalse;
    
        public override void Activate(GameManager gm)
        {
            gm.SetCardDetails(Description, Options, Items);
    
            UpdateStates();
        }
    
        private void UpdateStates()
        {
            if (StatesToSetTrue != null)
            {
                foreach (StoryState s in StatesToSetTrue)
                    s.Value = true;
            }
    
            if (StatesToSetFalse != null)
            {
                foreach (StoryState s in StatesToSetFalse)
                    s.Value = false;
            }
        }
    }
    
    

    StoryCard在检视面板中显示如下:
    在这里插入图片描述

    您需要在StoryCard脚本:
    Description:输入卡片描述(玩家可以在屏幕上看到的文本)
    Options:玩家在选项按钮上看到的文字(目前该程序最多支持4个按钮)
    Items:以及按下对应按钮后跳转的故事卡(即为分支,稍后会介绍)

    StoryCard脚本还包含两个故事状态属性“States to Set True”以及“States to Set False”,这两个属性分别有何作用呢?下面就来看看。

    3-2、故事状态与分支

    其实整个系统可以完全使用“故事卡”来制作,但仅使用“故事卡”的话,游戏流程就变得很枯燥无味。
    假设有某个选项,玩家点击了该按钮,但该选项所导致的后果并不会立即在剧情中呈现,而是在随后的剧情中缓慢展开。
    假使仅使用“故事卡”,就需要立即从该选项开始出现分支,并且直至该选项导致的最终影响出现之前,都要在所有剧情分支上重复同样的步骤。

    因此,我们需要一个更好的解决办法。

    前面提出了“故事状态”的概念用于存储状态值,这其实只是一个布尔值容器。
    卡片在被激活时可以根据需要对特定的状态进行赋值。新建StoryState脚本,代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class StoryState : MonoBehaviour 
    {
      public bool Value;
    }
    
    

    StoryState脚本在检视面板中显示如下图:
    在这里插入图片描述

    该方法解决了记住状态值的问题,下面通过“剧情分支(Story Branch)”来应用这些状态值。
    一个分支会引用一个状态以及剧情发展的两个不同方向(可以是“故事卡”或者剧情分支),被引用的状态值用于决定剧情走向何种结果。

    3-3、游戏管理器

    这个管理器用于承载整个剧情的发展,其作用是将目前的“故事卡”状态更新到UI上,在不同按钮按下时做出对应的动作,并引导剧情前进。
    这个管理器也需要一个“故事卡”来作为故事的开端。以下是GameManager脚本的内容:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using System;
    
    public class GameManager : MonoBehaviour
    {
        public Text Description;
        public Button[] OptionButtons;
    
        public StoryItemBase CurrentItem;
    
        private int _numButtons;
        private Text[] _buttonTexts;
        private string[] _optionTexts;
        private StoryItemBase[] _optionItems;
    
        // Use this for initialization
        void Start()
        {
            _numButtons = OptionButtons.GetLength(0);
    
            GetButtonTexts();
    
            CurrentItem.Activate(this);
        }
    
        // Update is called once per frame
        void Update()
        {
    
        }
    
        private void GetButtonTexts()
        {
            _buttonTexts = new Text[_numButtons];
    
            for (int i = 0; i < _numButtons; i++)
            {
                _buttonTexts[i] =
                  OptionButtons[i].GetComponentInChildren<Text>(true);
            }
        }
    
        public void SetCurrentStoryItem(StoryItemBase item)
        {
            CurrentItem = item;
            CurrentItem.Activate(this);
        }
    
        public void OnButton(int index)
        {
            SetCurrentStoryItem(_optionItems[index]);
        }
    
        public void SetCardDetails(string desc, string[] optionTexts,
                                   StoryItemBase[] optionItems)
        {
            Description.text = desc;
            _optionTexts = optionTexts;
            _optionItems = optionItems;
    
            UpdateButtons();
        }
    
        public void UpdateButtons()
        {
            int numOptionTexts = _optionTexts == null ? 0 :
                                                   _optionTexts.GetLength(0);
            int numOptionItems = _optionItems == null ? 0 :
                                                   _optionItems.GetLength(0);
    
            int numActiveButtons = Math.Min(numOptionItems, numOptionTexts);
    
            for (int i = 0; i < _numButtons; i++)
            {
                if (i < numActiveButtons)
                {
                    OptionButtons[i].gameObject.SetActive(true);
                    _buttonTexts[i].text = _optionTexts[i];
                }
                else
                {
                    OptionButtons[i].gameObject.SetActive(false);
                }
            }
        }
    
    }
    
    

    其中SetCurrentStoryItem函数用于设置当前显示的剧情节点。
    SetCardDetails函数用于设置“故事卡”的细节,例如剧情描述,选项按钮及描述等。

    UpdateButtons函数用于更新所有选项按钮及其响应事件。

    GameManager脚本在检视面板中显示如下图:
    在这里插入图片描述

    展开全文
  • 2019学unity3d游戏开发必看

    千次阅读 2019-02-11 15:34:11
    因此,有很多人选择自学unity3d加入到这个行业中来。 大家在进行选择的时候,一定要看是老师教得细心不细心。这里面有一个行业常识,业内为了保证教学质量,每个机构的课程都是有一帮大牛研发的,教课的老师也是按照...
  • Unity3D游戏引擎最详尽基础教程

    万次阅读 2018-06-27 15:23:06
    首先是因为专业,Unity3D非常强大,用它创建一个类似MiniGore这样的3D平面射击游戏简直轻而易举,而就连使命召唤这样的大型3d游戏,如果素材得当也不在话下。二是因为易用,他的操作非常容易,而使用的脚本语言又是...
  • Unity3D】Helloworld

    万次阅读 2017-04-24 10:22:40
    这个游戏引擎大名鼎鼎,容易学,能很快弄出很多好玩的游戏Unity3D有个好处,是兼容往下的版本。这一点起码比起隔壁的Cocos2dx好多了,Cocos2dx现在都不知道更到什么版本了,3.x只能用VS2012以上的版本玩就算了,还...
  • Unity3D手游开发实践

    万次阅读 2018-04-29 10:58:53
    虽然基于Unity3D,很多东西同样适用于Cocos。本文从以下10大点进行阐述:架构设计、原生插件/平台交互、版本与补丁、用脚本,还是不用?这是一个问题、资源管理、性能优化、异常与Crash、适配与兼容、调试及开发工具...
  • 《新仙剑OL》采用跨平台Unity3D引擎,耗资数千万,历时三年多,由台湾大宇正版授权,“仙剑之父”姚壮宪监制的全球首款Unity3D航母级双端(网页和客户端)中国风MMORPG网络游戏巨作。主打温情牌并且延续了仙剑系列的...
  • Unity3D开发小游戏】《战棋小游戏》Unity开发教程

    万次阅读 多人点赞 2020-04-10 16:49:52
    这次想要做的一个小游戏,或者说一个小Demo,其实是一个简单且传统的战棋战斗场景。初步的设计是:在2D世界里创建一张由六边形地块组成的战斗地图,敌我双方依据体力在地图上轮流行动并向对方发动攻击,先消灭掉所有...
  • 深入浅出Unity3D——第一篇

    万人学习 2019-07-01 10:35:43
    Unity3D基础知识、游戏算法一网打尽。
  • 基于Unity游戏开发(上)

    万人学习 2019-06-24 11:55:37
    本课程是Unity游戏开发的入门课程,课程分为上、下两个部分。上篇主要讲述游戏的基本概念、Unity的开发环境、游戏资源的创建和使用等基础内容。
  • Unity游戏开发入门教程之C#集合

    万人学习 2015-04-21 11:49:17
    该套视频主要针对初级的想学习Unity的学生,主讲语言的基本,简单语法。从数据的类型到方法的重载再到构造方法和析构方法再到后事件的概念与本质,学习难度进一步加深,对于初级的学生来说是一个非常好的,也非常...
  • Unity3D着色器程序设计-CG版

    万人学习 2018-10-22 21:38:06
    本课程将带领大家学习Unity3D中的着色器程序
  • 基于Unity游戏开发(下)

    万人学习 2020-02-26 11:51:26
    本课程是Unity游戏开发的入门课程,课程分为上、下两个部分。下部分主要介绍JavaScript脚本程序开发、动画、粒子、网络和GUI系统
  • 本课程主要讲解了 C# 语言的面向对象特性,是进行 Unity 3D 开发的基础。大部分的语言都支持面向对象,学好面向对象,能极大地提高我们的开发效率。面向对象相关的知识点本身就会有些抽象,概念很多,所以需要认真...
  • 实战进阶学习Unity3d游戏开发

    万人学习 2019-04-23 13:29:26
    零起步,快进阶,基础+算法融汇到项目实战中,细节+核心直到上线,一步步引领菜鸟做出大虾级的开发。
  • Unity3D实战进阶教程—第二篇

    万人学习 2019-04-23 13:28:54
    继续第一篇的实战项目学习,完成游戏“弹道精英”后期开发,特效、音效的控制等至打包上线。
  • 移动端游戏UI设计-二部曲

    万人学习 2018-10-22 21:38:03
    主要实现了移动端游戏的UI架构设计,分两部分,第一部分采用的是有限状态机,第二部分采用传统的模式架构设计。
1 2 3 4 5 ... 20
收藏数 46,864
精华内容 18,745
关键字:

unity3d游戏