unity3d小游戏csdn_unity3d游戏开发 csdn下载 - CSDN
精华内容
参与话题
  • Unity3D项目小游戏(3D坦克大战),一个Unity3D小游戏
  • 深入浅出Unity3D——第一篇

    万人学习 2019-07-01 10:35:43
    Unity3D基础知识、游戏算法一网打尽。
  • 实现角色动画和移动,场景管理和场景切换,按钮事件,以及对象碰撞等内容,适合刚刚学习unity3D的人
  • 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打飞机游戏

    2020-07-19 23:33:53
    Unity3D打飞机游戏,大家快来下载吧! 实现了基本的功能!
  • 自己在家写的一个案例,希望大家开源一起交流分享,代码全,适合初学者学习,看运行操作,自己也可以拓展学习下
  • Unity3D游戏引擎最详尽基础教程

    万次阅读 2018-06-27 15:23:06
    我一直向所有想做游戏的朋友推荐Unity3D,为什么呢?首先是因为专业,Unity3D非常强大,用它创建一个类似MiniGore这样的3D平面射击游戏简直轻而易举,而就连使命召唤这样的大型3d游戏,如果素材得当也不在话下。二是...

    我一直向所有想做游戏的朋友推荐Unity3D,为什么呢?首先是因为专业,Unity3D非常强大,用它创建一个类似MiniGore这样的3D平面射击游戏简直轻而易举,而就连使命召唤这样的大型3d游戏,如果素材得当也不在话下。二是因为易用,他的操作非常容易,而使用的脚本语言又是JavaScript或者C#,不仅非常简单,也让各个种类的程序员都非常容易上手。再次,就是因为免费,如果你不使用Pro或者Mobile的内容的话,Unity3d就是完全免费的。还有就是对3D模型的兼容性,几乎任何3d模型都可以导入到unity中,可以说是一个很方便的特性。

     

    今天,我就来讲讲Unity3D的基础操作,这可以说是一个新手必读吧,读完之后,你一定会惊叹,原来做一个游戏这么简单。

     

    第一节 加入重力

     

    我们先打开Unity3d,新建一个场景(Scene),新建的时候应该会有对话框要求你加入哪些Asset Package,记得选择Physics Material,因为后面我们一定要用的哦亲。

     

    如果创建的时候没加,你可以再后来的Asset菜单里加:

     

     

    之后,我们建立一个Cude,调整一下x和z的大小,我这里调成了25,让它变成一个地板,你也可以放一个texture上去,看起来更加真实,我这里从简,再创建一个sphere,在component中选择Physics中的RigidBody,前提是选中你的sphere物体,之后会看到这个Sphere的inpector中加入一个component叫做RigidBody,调整好Camera运行一下,你就会发现Sphere受到重力的影响自动掉落到地板上。

     

     

    之后,通过我们之前引入的Physics Materials资源包,你还可以选择这个物体的物理性质,我这里选择Bouncy(跳跳),落下之后,这个物体就会蹦来蹦去的,呵呵

     

     

     

    第二节 检测碰撞

     

    下面我们通过简单的JavaScript语句来检测碰撞,这在制作游戏中是很有用的,比如说检测到子弹和敌人的碰撞之后,可以使用我们后来要讲到destory命令消灭敌人。

     

    这次我们新建一个Terrain项目,在用Grass贴图来覆盖住它,如果你找不到贴图的话,记得在Asset菜单里找找,看看哪些资源你还没有引入进去。

     

    然后再加入一个Cube项目,我这里叫做PlayerCube,为他加上重力,之后选择bouncy性质,然后我们再新建一个Cude,调整y和z的值让他变成一堵墙,放置好,命名为Wall,别忘了给Terrain改名为Terrain,

     

    之后我们在Asset菜单中建立一个JavaScript项目,改名为CollisionDetect,双击打开,如果你使用的是Unity 3.5的话,就会打开MonoDev,这是一个新工具还是很好用的,在其中新建一个函数,别管Start和Update函数,我们待会会讲。

     

    加入以下代码:

     

    function OnCollisionEnter(theCollision : Collision){
    
     
    
    if(theCollision.gameObject.name=="Terrain"){
    
     
    
    Debug.Log("Hit terrain");
    
     
    
    }else if(theCollision.gameObject.name=="Wall"){
    
     
    
    Debug.Log("Hit the wall");
    
     
    
    }
    
     
    
    }
    

     

    如果看不懂这些代码的话,也没关系,JavaScript是最好学的编程语言,Google一下吧,保存这个JS文件,然后拖到我们的PlayerCube上。

     

    这时候我们运行,就会看到PlayerCube到处蹦,碰到Terrain的时候,控制台就会显示Hit Terrain,碰到wall的时候就会显示Hit the wall。

     

    第三节  检测用户输入

     

    下面我们来讲一下如何检测用户的键盘和鼠标的操作。

     

    就用我们上次的那个场景,这次我们给PlayerCube加上我们可以控制的动作。就是通过“wasd”或者上下左右键来控制移动。

     

    请注意,如果要使用这里使用的方法来控制移动,那么所控制的物体不能够是一个物理世界的物体,也就是说你要把RigidBody这个component删掉,如果你想要在物理世界里移动物体的话,你就需要我们在下面会讲到的力(force)。

     

    首先我们新建一个JavaScript文件,这里命名为InputDetect吧,输入下面的代码:

     

    #pragma strict
    
     
    
    var Player : GameObject;
    
     
    
    function Start () {
    
     
    
    }
    
     
    
    function Update () {
    
     
    
    Player = GameObject.Find("PlayerCube");
    
     
    
    if(Input.GetKey(KeyCode.W)){
    
     
    
    Debug.Log("Hit w");
    
     
    
    Player.transform.Translate(Vector3.forward * 2);
    
     
    
    }else if(Input.GetKey(KeyCode.S)){
    
     
    
    Debug.Log("Hit s");
    
     
    
    Player.transform.Translate(Vector3.back * 2);
    
     
    
    }else if(Input.GetKey(KeyCode.A)){
    
     
    
    Debug.Log("Hit a");
    
     
    
    Player.transform.Translate(Vector3.left * 2);
    
     
    
    }else if(Input.GetKey(KeyCode.D)){
    
     
    
    Debug.Log("Hit d");
    
     
    
    Player.transform.Translate(Vector3.right * 2);
    
     
    
    }
    
     
    
     
    
    }
    

     

    这时,我们运行这个游戏,就可以通过“WASD”来控制PlayerCube的移动了。

     

     

    第四节 使用Prefab复制和控制物体

     

    我们可以直接把Prefab看做是个妈,她能生好多小孩,如果妈妈的DNA变了,小孩的跟着变,就是说你可以用Prefab创建物体,然后通过这个Prefab修改所有这类物体的性质,这对于批量生成的敌人或者NPC来说很有用。

     

    首先,先创建一个Prefab,我这里命名为“Mother”,之后新建一个Sphere物体,当然你也可以建一些其他的物体,之后给这个Sphere加上你想要的性质,我加入了RigidBody和Bouncy,之后将Sphere拖到Mother上,你会发现mother变蓝了,之后你就可以随意拖一些mother物体到屏幕上去,你会发现所有的Prefab创建出的物体在清单上都是蓝色的,说明他们都有共同的性质。

     

     

    当然,作用于一个Prefab上的脚本也会作用到它的子物体上去。

     

    第五节 使用Destroy命令消灭物体

     

    我们游戏中怎么能够没有敌人呢?有敌人就得能够消灭他们,这时候,我们就会使用Destroy命令了。

     

    在这里,我们使用上次Mother生出来的小球球作为敌银,一旦我们的PlayerCube碰撞到了小球的话,就是用Destroy让小球消失。

     

    新建一个JavaScript脚本,输入以下代码:

     

    #pragma strict
    
     
    
    var mother : GameObject;
    
     
    
    function Start () {
    
     
    
    }
    
     
    
    function Update () {
    
     
    
    }
    
     
    
    function OnCollisionEnter(theCollision : Collision){
    
     
    
    mother = GameObject.Find("Mother");
    
     
    
    if(theCollision.gameObject.name=="Mother"){
    
     
    
    Debug.Log("Hit mother");
    
     
    
    Destroy(mother);
    
     
    
    }
    
     
    
    }
    

     

    这段代码很好懂吧,就是检验碰撞,然后销毁碰撞到的Mother物体,别忘了把Destroy的JavaScript文件拖到PlayerCube上去。运行一下,就可以看到碰撞到的物体都被消灭了。

     

     

    第六节 使用Instantiate命令创造物体

     

    我们直接在界面创造的物体都只是会在界面被初始化的时候加载,那么,如果为了节约内存或者其他什么事情,我想要在游戏过程中添加物体,那该怎么办呢?你猜对了,就是用instantiate命令。

     

    这个命令就是英文实例化的意思,下面我们给碰撞之后消失的mother物体继续初始化一些,也就是说消灭了一些,又来了一大波···

     

    为什么非要用mother呢?因为只有拥有Prefab的物体才能够使用这个命令哦亲。

     

    function Update () {
    
     
    
    var instance : GameObject = Instantiate (PreFab,transform.position,transform.rotation);
    
     
    
    }
    

     

    注意:这样的话,每次刷新一帧都会出现一个新的mother物体,你的内存也许会受不了哦,更合理的方法是按下空格键,然后出现一个新的物体,你可以自己做吗?试试看

     

    你可能已经注意到了,每一个初始化的脚本都会默认有两个函数,就是:

    Update()函数 —— 每刷新一帧都会检查并执行

    Start()函数 —— 只在场景初始化的时候执行

     

    第七节 使用Timer计时器

     

    这次,我们要让一个计时器倒数,倒数到0的时候创建一个mother物体,来看Javascript代码吧:

     

    #pragma strict
    
     
    
    var myTimer : float = 5.0;
    
     
    
    function Start () {
    
     
    
    }
    
     
    
    function Update () {
    
     
    
    if (myTimer >= 0){
    
    myTimer -= Time.deltaTime;
    
    guiText.text=(""+myTimer);
    
    }
    
     
    
    if (myTimer <= 0){
    
    guiText.text = ("Done");
    
    }
    
     
    
    }
    

     

    把这个脚本拖到GUItext控件上,你会发现我们所期待的效果。

     

     

    第八节 让物体动起来

     

    其实让物体行动的技巧,我们已经会了,不是吗?

     

    如果你觉得不是的话,没有认真的看上面的文章哦,我就再给你讲一次吧。

     

    请特别注意,这种方法不适合物理世界的物体,如果向移动物理世界的物体,请看下一节:

     

    创建一个Cylinder物体,之后将下面的脚本附着在上面。

     

    #pragma strict
    
     
    
    var myObject : GameObject;
    
     
    
    function Start () {
    
     
    
    }
    
     
    
    function Update () {
    
     
    
    myObject.gameObject.Find("Cylinder");
    
    myObject.transform.Translate(Vector3(0,0,1));
    
     
    
    }
    

     

    第九节 使用物理世界的力

     

    这里是我们讲移动物体的重点,因为大部分的物体移动都是在物理世界完成的,而如果想要在物理世界移动东西,除了position和rotation的移动之外,就是使用“力”了,在高中学过经典物理学的人都知道,要使物体用移动,木有力是不行的,那么我们就开始吧,再新建一个什么物体,我新建了一个Capsule。

     

    之后,我会在这个物体的上方加一个力,让它用力的向下飞,触碰到地之后,通过bouncy这个性质再弹回来。新建一个JavaScript文件,就叫做Force吧,加入如下代码:

     

    #pragma strict
    
     
    
    var Power : float = 500.0;
    
     
    
    function Start () {
    
     
    
    rigidbody.AddForce(Vector3(0,Power,0));
    
     
    
    }
    
     
    
    function Update () {
    
     
    
    }
    

     

    运行之后,会发现capsule其实是个很有幽默感的物体。

     

     

    第十节 使用贴图和材质

     

    贴图和材质能够使你的虚拟3D世界看起来更加真实,不幸的是,需要大量在PS和AI中的设计工作,最近我一想到要打开PS就有点烦···呜呜。

     

    闲话少说,我已经做好了一个贴图,怎么使用在材质上呢?之后我们怎么才能通过材质使用到其他物体之上呢?

     

     

    就像你看到的一样,我是直接拖进去的···

     

    之后我们从新建菜单中选择Material这一项,之后选中material,将贴图拖进material的贴图选框里,之后,就可以拖动这个Material赋给任何物体了。

     

     

    第十一节 使用声效和音乐

     

    音效和音乐对于一个游戏来说是非常重要的,一个寂静无声的世界是无聊的,而且不真实,什么?你说声效和音乐是一个东西?那你就错了,声效是,比如说发射子弹的声音,什么东西爆炸的声音等等,而音乐则是背景音乐什么的,不一样的亲。

     

    对于音乐来说,往往使用立体声音乐,而对于生效来说,我们随便使用一个简单的音乐文件就可以了。

     

    想要在Unity3D中播放音乐,你需要两样东西,一个是监听器,一个是音乐源,监听器是Camera的一个组件,所以你不用担心,你唯一需要增加的就是音乐源。

     

    直接将项目中的音乐拖放到Audio Source项就可以播放,但是如果我们想要在某个特定的点上 播放音乐该怎么办呢?答案就是,写一个脚本,新建一个脚本,输入如下代码:

     

    #pragma strict
    
     
    
    var myClip : AudioClip;
    
     
    
    function Start () {
    
     
    
    AudioSource.PlayClipAtPoint(myClip,transform.position);
    
     
    
    }
    
     
    
    function Update () {
    
     
    
    }
    

     

    之后将这个脚本拖放到我们的物体上,最后,将音频文件拖放到AudioSource选项框中。

     

    第十二节 使用关节

     

    关节在3D游戏之中的应用非常广,主要在于物理世界的重力影响,下面我们就通过关节来制作一个钟摆。

     

    这次我们新建一个场景,松了一口气?刚才的场景是不是太乱了?你做的时候可以整理一下嘛,呵呵

     

    新建一个cube作为地面,之后一个cube放在上空作为摆垂,之后用几个capsule分别用component中的fixed joint连接起来,之后最上面的那个capsule与世界相连,使用Hinge Joint,这样的话,他会默认与世界相连,不用担心,看图

     

     

     

    第十三节 使用Axes

     

    在Edit – Project Setting – input 中可以查看各种形式的input,这些input方法在unity中被叫做Axes。

     

    我们创建一个JavaScript,叫做GetAxes,输入以下内容:

     

    #pragma strict
    
     
    
    function Start () {
    
     
    
    }
    
     
    
    function Update () {
    
     
    
    var Honriz : float = Input.GetAxis("Honrizontal");
    
     
    
    Debug.Log(Honriz);
    
     
    
    }
    

     

    在拖放脚本之后,运行这个场景,看看控制台输出了什么,你就明白了。

     

     

    第十四节 使用触发器

     

    触发器一般用于检测一个物体是否处于一个空间内,他是怎么做到的呢?

     

    首先,他创造一个大的物体,之后将他的randerer属性去掉,他就隐形了,这样,我们再把他的isCollide属性去掉,他就不会发生碰撞了,之后,我们只需要用脚本检测物体是否与这个物体碰撞就可以了。

     

    我们新建一个场景,做一个地板,再做一个底座,叠加起来,再在他们的上空做一个方块,设置rigidbody属性,将底座设置成为我们刚才说的那种隐形的状态,之后新建一个JavaScript脚本,输入代码

     

    #pragma strict
    
     
    
    function Start () {
    
     
    
    }
    
     
    
    function Update () {
    
     
    
    }
    
     
    
    function OnTriggerEnter (myTrigger : Collider) {
    
     
    
    if(myTrigger.gameObject.name == "box"){
    
    Debug.Log("Hit");
    
    }
    
     
    
    }
    

     

    按下运行,会发现可以检测出Hit。

     

     

    第十五节 使用GUI

     

    其实我们已经学过了如何使用GUI text,不信,我们就用屏幕上的字代替我们在上面的程序中的Debug.Log现实的内容。

     

    你自己能做吗?

     

    试试看吧,一个下午写了这么多,有点累。

     

    一定要在Unity中加入一个GUI Text,运行一下,就会发现屏幕上的GUI Text会随着你设定的的内容而变化了。

    失败是什么?没有什么,只是更走近成功一步;成功是什么?就是走过了所有通向失败的路,只剩下一条路,那就是成功的路。
    展开全文
  • unity3d 一个特别牛的游戏例子
  • Unity3d制作简单拼图游戏源码+工程

    千次下载 热门讨论 2020-07-28 23:33:34
    Unity3d制作的简单拼图游戏 制作流程可以看我的博客:http://blog.csdn.net/cube454517408/article/details/7907247
  • [Unity3D]Unity3D游戏开发之自由视角下的角色控制

    万次阅读 热门讨论 2014-09-10 12:54:34
    在上一篇文章[Unity3D]Unity3D游戏开发之角色控制漫谈>一文中,博主与大家分享自己在角色控制方面的一些感悟。今天呢,我们继续来探讨Unity3D角色控制的内容,今天博主将解决在上一篇文章中没有解决的问题,即自由...

           各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei。在上一篇文章<[Unity3D]Unity3D游戏开发之角色控制漫谈>一文中,博主与大家分享自己在角色控制方面的一些感悟。今天呢,我们继续来探讨Unity3D角色控制的内容,今天博主将解决在上一篇文章中没有解决的问题,即自由视角下的角色控制。如图是博主非常喜欢的《古剑奇谭》游戏截图,在这款游戏中就使用了博主今天要讲解的自由视角,所谓自由视角是指玩家可以按照自身坐标系向着四个不同的方向移动,当玩家按下鼠标右键时,可以绕Y轴按照一定的角度旋转摄像机,在旋转的过程中,角色将旋转相应的角度。在移动的过程中,摄像机会保持与玩家间的一定距离,然后跟随角色进行移动。好了,下面我们正式开始今天的内容吧!


         

         在开始今天的内容前,首先让我们来学习下Unity3D中较为重要的一部分知识,理解这些知识是我们开始学习今天内容的基础。

         1、Input.GetAxis():该方法用于在Unity3D中根据坐标轴名称返回虚拟坐标系中的值,通常情况下,使用控制器和键盘输入时此值范围在-1到1之间。这段话怎么理解呢?我们来看下面这段脚本:

    using UnityEngine;
    using System.Collections;
    
    public class example : MonoBehaviour {
    
    	//水平速度
    	public float HorizontalSpeed = 2.0F;
    	//垂直速度
    	public float VerticalSpeed = 2.0F;
    
    	void Update() 
    	{
    		//水平方向
    		float h = HorizontalSpeed * Input.GetAxis("Mouse X");
    		//垂直方向
    		float v = VerticalSpeed * Input.GetAxis("Mouse Y");
    		//旋转
    		transform.Rotate(v, h, 0);
    	}
    }
    这段脚本呢是根据鼠标的位置来旋转物体从而实现对物体的观察,从这段脚本中我们可以看出,通过获取输入轴的办法,我们可以获得鼠标移动的方向进而实现对于物体的旋转控制。在Unity3D中我们可以通过Edit->Project Setting->Input来查看项目中的坐标轴名称:


    在后面,我们还将使用这种方式,大家可以对这个方法有进一步的了解。


         2、欧拉角eulerAngles:该值是Vector3类型的值,x、y、z分别代表绕x轴旋转x度,绕y轴旋转y度,绕z轴旋转z度。因此,该值最为直观的形式是可以允许我们直接以一个三维向量的形式来修改一个物体的角度,例如下面的脚本:

    float mY = 5.0;
    
    void Update () 
    {
    	mY += Input.GetAxis("Horizontal");
    	transform.eulerAngles =new Vector3(0,mY, 0);
    }
         如果你已经理解了上面的话,那么不出意外的,这段脚本会如你所愿的,按照鼠标在水平方向上移动的方向绕Y轴旋转。通常情况下,我们不会单独设置欧拉角其中一个轴,例如eulerAngles.x = 10,因为这将导致偏移和不希望的旋转。当设置它们一个新的值时,要同时设置全部。好在我们可以通过Quaternion.Euler()方法将一个Vector3类型的值转化为一个四元数,进而通过修改Transform.Rotation来实现相同的目的。

        

         3、插值:所谓插值是指离散数据的基础上补插连续函数,使得这条连续曲线通过全部给定的离散数据点。插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。在某些情况下,如果我们希望过程中处理得较为平滑,此时我们就可以使用插值的方法来实现对中间过程的模拟。在Unity3D中我们可以使用两种插值方法,即线性插值Lerp,球形插值SLerp。我们来看下面的脚本:

    void Rotating (float horizontal, float vertical)
    	{
    		// Create a new vector of the horizontal and vertical inputs.
    		Vector3 targetDirection = new Vector3(horizontal, 0f, vertical);
    		
    		// Create a rotation based on this new vector assuming that up is the global y axis.
    		Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);
    		
    		// Create a rotation that is an increment closer to the target rotation from the player's rotation.
    		Quaternion newRotation = Quaternion.Lerp(rigidbody.rotation, targetRotation, turnSmoothing * Time.deltaTime);
    		
    		// Change the players rotation to this new rotation.
    		rigidbody.MoveRotation(newRotation);
    	}
    
    插值的方法很简单,只要我们给出初始和结束的状态、时间就可以了,大家可以自己看API。


          好了,有了这三部分的基础,我们就可以开始今天的内容了,今天的脚本分为两个部分,第一部分是角色控制的部分,主要负责的角色在场景中的移动、转身和动画处理。第二部分是相机控制的部分,主要涉及相机旋转、相机缩放的相关内容。下面,我们分别来讲这两个部分,场景依然是博主自己在做的小游戏:


    本次的主角呢,是博主非常喜欢的角色谢沧行,好了,我们回到今天的内容里吧!在第一部分,主要的是完成角色向各个方向的转身,这里博主定义四个方向(其实八个方向是一样的!),脚本如下:

    using UnityEngine;
    using System.Collections;
    
    public class NoLockiVew_Player : MonoBehaviour {
    
    	/*自由视角下的角色控制*/
    	/*作者:秦元培*/
    
    	//玩家的行走速度
    	public float WalkSpeed=1.5F;
    	//重力
    	public float Gravity=20;
    
    	//角色控制器
    	private CharacterController mController;
    	//动画组件
    	private Animation mAnim;
    	//玩家方向,默认向前
    	private DirectionType mType=DirectionType.Direction_Forward;
    
    	[HideInInspector]
    	//玩家状态,默认为Idle
    	public PlayerState State=PlayerState.Idle;
    
    	//定义玩家的状态枚举
    	public enum PlayerState
    	{
    		Idle,
    		Walk
    	}
    
    	//定义四个方向的枚举值,按照逆时针方向计算
    	protected enum DirectionType
    	{
    		Direction_Forward=90,
    		Direction_Backward=270,
    		Direction_Left=180,
    		Direction_Right=0
    	}
    	
    	void Start () 
    	{
    	   //获取角色控制器
    	   mController=GetComponent<CharacterController>();
    	   //获取动画组件
    	   mAnim=GetComponentInChildren<Animation>();
    	}
    	
    	
    	void Update () 
    	{
    		MoveManager();
    		//MouseEvent();
    	}
    
    	//玩家移动控制
    	void MoveManager()
    	{
    		//移动方向
    		Vector3 mDir=Vector3.zero;
    		if(mController.isGrounded)
    		{
    			//将角色旋转到对应的方向
    			if(Input.GetAxis("Vertical")==1)
    			{
    				SetDirection(DirectionType.Direction_Forward);
    				mDir=Vector3.forward * Time.deltaTime * WalkSpeed;
    				mAnim.CrossFade("Walk",0.25F);
    				State=PlayerState.Walk;
    			}
    			if(Input.GetAxis("Vertical")==-1)
    			{
    				SetDirection(DirectionType.Direction_Backward);
    				mDir=Vector3.forward * Time.deltaTime * WalkSpeed;
    				mAnim.CrossFade("Walk",0.25F);
    				State=PlayerState.Walk;
    			}
    			if(Input.GetAxis("Horizontal")==-1)
    			{
    				SetDirection(DirectionType.Direction_Left);
    				mDir=Vector3.forward * Time.deltaTime * WalkSpeed;
    				mAnim.CrossFade("Walk",0.25F);
    				State=PlayerState.Walk;
    			}
    			if(Input.GetAxis("Horizontal")==1)
    			{
    				SetDirection(DirectionType.Direction_Right);
    				mDir=Vector3.forward * Time.deltaTime * WalkSpeed;
    				mAnim.CrossFade("Walk",0.25F);
    				State=PlayerState.Walk;
    			}
    			//角色的Idle动画
    			if(Input.GetAxis("Vertical")==0 && Input.GetAxis("Horizontal")==0)
    			{
    				mAnim.CrossFade("Idle",0.25F);
    				State=PlayerState.Idle;
    			}
    
    		}
    		//考虑重力因素
    		mDir=transform.TransformDirection(mDir);
    		float y=mDir.y-Gravity *Time.deltaTime;
    		mDir=new Vector3(mDir.x,y,mDir.z);
    		mController.Move(mDir);
    	}
    
    	//设置角色的方向,有问题
    	void SetDirection(DirectionType mDir)
    	{
    		if(mType!=mDir)
    		{
    			transform.Rotate(Vector3.up*(mType-mDir));
    			mType=mDir;
    		}
    	}
    }
    
    这里定义四个方向,是按照逆时针方向转的,相邻的两个方向间相差90度,所以我们只需要将当前的角度和目标角度相减就可以转到目标角度的方向(其实这是以前写的代码,现在回头再看,直接用欧拉角似乎更为简单啊,呵呵)。这里主要的内容就是这样了。下面我们来看相机控制部分的代码吧,这里的代码参考了MouseOrbit脚本,主要完成了鼠标右键旋转控制,博主在此基础上增加了相机缩放的代码。提到相机缩放,其实就是根据鼠标滚轮滚动的方向和大小重新计算角色与相机的距离,与之类似地还有小地图的放缩,其实同样是通过修改距离来实现的。博主今天的一个体会是官方的代码能自己写一遍的最好自己写一遍,这样好多东西就能在这个过程中给理解了。我们一起来看脚本
    using UnityEngine;
    using System.Collections;
    
    public class NoLockView_Camera : MonoBehaviour 
    {
    	//观察目标
    	public Transform Target;
    	//观察距离
    	public float Distance = 5F;
    	//旋转速度
    	private float SpeedX=240;
    	private float SpeedY=120;
    	//角度限制
    	private float  MinLimitY = 5;
    	private float  MaxLimitY = 180;
    
    	//旋转角度
    	private float mX = 0.0F;
    	private float mY = 0.0F;
    
        //鼠标缩放距离最值
    	private float MaxDistance=10;
    	private float MinDistance=1.5F;
    	//鼠标缩放速率
    	private float ZoomSpeed=2F;
    
    	//是否启用差值
    	public bool isNeedDamping=true;
    	//速度
    	public float Damping=2.5F;
    
    	void Start () 
    	{
    		//初始化旋转角度
    		mX=transform.eulerAngles.x;
    		mY=transform.eulerAngles.y;
    	}
    	
    	void LateUpdate () 
    	{
    		//鼠标右键旋转
    		if(Target!=null && Input.GetMouseButton(1))
    		{
    		    //获取鼠标输入
    			mX += Input.GetAxis("Mouse X") * SpeedX * 0.02F;
    			mY -= Input.GetAxis("Mouse Y") * SpeedY * 0.02F;
    			//范围限制
    			mY = ClampAngle(mY,MinLimitY,MaxLimitY);
    		}
    
    		//鼠标滚轮缩放
    
    		Distance-=Input.GetAxis("Mouse ScrollWheel") * ZoomSpeed;
    		Distance=Mathf.Clamp(Distance,MinDistance,MaxDistance);
    
    		//重新计算位置和角度
    		Quaternion mRotation = Quaternion.Euler(mY, mX, 0);
    		Vector3 mPosition = mRotation * new Vector3(0.0F, 0.0F, -Distance) + Target.position;
    
    		//设置相机的角度和位置
    		if(isNeedDamping){
    		   //球形插值
    		   transform.rotation = Quaternion.Lerp(transform.rotation,mRotation, Time.deltaTime*Damping); 
    		   //线性插值
    		   transform.position = Vector3.Lerp(transform.position,mPosition, Time.deltaTime*Damping); 
    		}else{
    		   transform.rotation = mRotation;
    		   transform.position = mPosition;
    		}
    		//将玩家转到和相机对应的位置上
    		if(Target.GetComponent<NoLockiVew_Player>().State==NoLockiVew_Player.PlayerState.Walk)
    		{
    			Target.eulerAngles=new Vector3(0,mX,0);
    		}
    	}
    	
    	private float  ClampAngle (float angle,float min,float max) 
    	{
    		if (angle < -360) angle += 360;
    		if (angle >  360) angle -= 360;
    		return Mathf.Clamp (angle, min, max);
    	}
        
    
    
    
    }
    
    
    

    这里很多朋友可能对我设置一个状态很不理解吧,这其实是为了让玩家有一个自由查看角色的机会,否则当玩家按下鼠标右键的话,角色就会转向相机正对着的位置,这样玩家就看不到角色的正面了。当然,这里用到了插值,这样能使角色在转身的时候平滑一点,效果会更好。

    唉,不知不觉已经这个时候了,开学已经一周了,这学期我们只上九周课,然后就是实习、毕设、找工作一大堆事情在等着我们。可是不知道为什么博主宿舍的同学居然还能每天什么事情都不做,从早上一直看电视剧到晚上十点,虽然这件事情和博主没有什么关系吧,可是整个宿舍的人都安安静静地做着自己的事情,就有这么一个人整天声音开得很大在那里外放,这样真的好吗?以前和这个人闹过一次,因为他聚了一帮人在宿舍打麻将,我觉得吵就说了他一顿,结果就和我僵上了。说真的,博主对目前的专业真的没有什么情感,大学四年里最让博主开心的事情就是博主学会了好多自己想要学的东西,认识了几个不错的老师和朋友,仅此而已。或许我们注定要越走越远吧,因为我们根本就不是同一种人。

    前几天网上有人通过博客联系到博主,希望博主能到他哪里工作,可惜博主目前仍然有一大堆的琐事缠身,不然离开这喧嚣吵闹的宿舍,去做博主喜欢的事情,去寻找博主自己的梦想,博主相信,博主一定可以做得更好吧。人生或许就是这样,你越是在乎的可能越让你得不到,你无心插柳可能会得到一片绿荫。对于未来,不管怎么样,坦然面对就好了,博主改变不了周围的这群人,只能努力地去改变自己。好了,晚安吧!

    效果演示(2M的限制让很多展示都无可奈何)



    每日箴言:所有的悲伤,总会留下一丝欢乐的线索。所有的遗憾,总会留下一处完美的角落。我在冰封的深海,找寻希望的缺口。却在午夜惊醒时,蓦然瞥见绝美的月光。——几米


           喜欢我的博客请记住我的名字:秦元培,我博客地址是blog.csdn.net/qinyuanpei。
           转载请注明出处,本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/39125353


          文章更新:

          9月10日,博主在测试这个项目的时候意外地发现了一个Bug。Bug出现在如下位置:

    		//设置玩家跟随角度
    		if(Target.GetComponent<NoLockiVew_Player>().State==NoLockiVew_Player.PlayerState.Walk)
    		{
    			Target.rotation=Quaternion.Euler(new Vector3(0,mX,0));
    		}

    该方法主要的作用是当玩家同时按下方向控制键和鼠标右键,玩家可以随着鼠标旋转到对应的角度,这主要是为了满足玩家双手操作的需求,不过由于这行代码,导致玩家在向左、向右、向后三个方向上的转身失效,如果除去这行代码,则原来的方向控制没有任何问题,可是没有这行代码,玩家的操作感就会下降。后来博主想到我们对角色的旋转实际上应该是放在鼠标右键事件里的,所以博主将代码修改如下,这样就解决了这个Bug:

    using UnityEngine;
    using System.Collections;
    
    public class NoLockView_Camera : MonoBehaviour 
    {
    	//观察目标
    	public Transform Target;
    	//观察距离
    	public float Distance = 5F;
    	//旋转速度
    	private float SpeedX=240;
    	private float SpeedY=120;
    	//角度限制
    	private float  MinLimitY = 5;
    	private float  MaxLimitY = 180;
    
    	//旋转角度
    	private float mX = 0.0F;
    	private float mY = 0.0F;
    
        //鼠标缩放距离最值
    	private float MaxDistance=10;
    	private float MinDistance=1.5F;
    	//鼠标缩放速率
    	private float ZoomSpeed=2F;
    
    	//是否启用差值
    	public bool isNeedDamping=true;
    	//速度
    	public float Damping=10F;
    
    	private Quaternion mRotation;
    
    	void Start () 
    	{
    		//初始化旋转角度
    		mX=transform.eulerAngles.x;
    		mY=transform.eulerAngles.y;
    	}
    	
    	void LateUpdate () 
    	{
    		//鼠标右键旋转
    		if(Target!=null && Input.GetMouseButton(1))
    		{
    		    //获取鼠标输入
    			mX += Input.GetAxis("Mouse X") * SpeedX * 0.02F;
    			mY -= Input.GetAxis("Mouse Y") * SpeedY * 0.02F;
    			//范围限制
    			mY = ClampAngle(mY,MinLimitY,MaxLimitY);
    			//计算旋转
    			mRotation = Quaternion.Euler(mY, mX, 0);
    			//根据是否插值采取不同的角度计算方式
    			if(isNeedDamping){
    				transform.rotation = Quaternion.Lerp(transform.rotation,mRotation, Time.deltaTime*Damping); 
    			}else{
    				transform.rotation = mRotation;
    			}
    			//处理同时按下鼠标右键和方向控制键
    			if(Target.GetComponent<NoLockiVew_Player>().State==NoLockiVew_Player.PlayerState.Walk){
    				Target.rotation=Quaternion.Euler(new Vector3(0,mX,0));
    			}
    		}
    
    		//鼠标滚轮缩放
    		Distance-=Input.GetAxis("Mouse ScrollWheel") * ZoomSpeed;
    		Distance=Mathf.Clamp(Distance,MinDistance,MaxDistance);
    
    		//重新计算位置
    		Vector3 mPosition = mRotation * new Vector3(0.0F, 0.0F, -Distance) + Target.position;
    
    		//设置相机的角度和位置
    		if(isNeedDamping){
    		   transform.position = Vector3.Lerp(transform.position,mPosition, Time.deltaTime*Damping); 
    		}else{
    		   transform.position = mPosition;
    		}
    
    	}
    
    
    	//角度限制
    	private float  ClampAngle (float angle,float min,float max) 
    	{
    		if (angle < -360) angle += 360;
    		if (angle >  360) angle -= 360;
    		return Mathf.Clamp (angle, min, max);
    	}
    }
    
    
    
    不过经过博主测试,如果不采用插值的话,似乎效果更为真实啊(为什么会和第一次测试的感觉不一样啊,囧!)




    展开全文
  • 在我之前的文章《Unity3D游戏开发之地图的实现》一文中,我为大家讲解了基于OnGUI()方法绘制贴图实现地图的方法。那么,今天呢,博主再来为大家分享一种实现地图的方法。在正式开始今天的文章之前,我们先来...

            大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei

           在我之前的文章《Unity3D游戏开发之小地图的实现》一文中,我为大家讲解了基于OnGUI()方法绘制贴图实现小地图的方法。那么,今天呢,博主再来为大家分享一种实现小地图的方法。在正式开始今天的文章之前,我们先来了解下Unity3D中的相机吧。在Unity3D中,相机是一个能够为玩家捕获并显示游戏世界的设备。通过操纵相机,我们可以使得我们的游戏场景以更加真实和独特的方式显示出来。在Unity3D中默认有一个主相机Main Camera用来显示我们设计的游戏场景,其实呢,在一个游戏场景中我们是可以设置多个相机对象的,而且它们可以被设置为任意的渲染序列、任意的渲染部分和任意的渲染位置。下面我们来讲解一些比较重要的东西吧!

          1、Clera  Flags:决定场景的哪个部分需要清除。当需要使用多个相机以显示不同的游戏元素时这是非常有用的。

          2、Background Color:处于所有对象之后的背景颜色,设置此属性后,天空盒子(SkyBox)将失效。

          3、Normalized View Port Rect:在屏幕坐标系下使用四个值来确定相机的哪些部分将显示在屏幕上。

          4、Near Clip Plane:相对于相机昀近绘制点。

          5、Far Clip Plane:相对于相机昀远的绘制点。

          6、Field of view:沿着局部 Y轴的相机视角宽度。

          7、Is orthographic:打开或关闭相机的景深效果

          8、正交视大小(Orthographic size):在正交模式下的视口大小。

          9、Depth:相机的绘制顺序,相当于ZIndex属性,具有较高深度的相机将绘制在较低深度相机的上面。

          好了,有了上面的基础,我们就可以开始今天的正式内容了,如图是博主自己创建的一个游戏场景,游戏场景是在一个没有光照的黑暗的屋子里面,我们的游戏主角头顶上添加了一个点光源,所以当游戏主角运动的时候,其经过的场景会被主角头顶上的光源照亮,我们现在要做的就是为这个游戏场景添加一个小地图,以保证玩家在玩游戏的时候不会在黑暗的屋子里迷路。


            好,现在我们开始来做小地图,我们在场景中添加一个Camera,然后设置其旋转角度使其垂直于XOZ平面,命名为TopCamera,这时候我们设置摄像机的投影方式为正交投影,相信根据前面提到的关于Camera的一些内容,大家已经猜到这个小地图的制作原理了,不错,这个小地图就是根据Normalized View Port Rect属性来制作的。我们可以自己调整Normalized View Port Rect的四个数值来让小地图在合适的位置显示合适的内容,下面是博主对TopCamera的一些设置数值,供大家参考:

           

            那么这样,我们的小地图就做好了,我们一起来看看效果吧!图中红框表示出了游戏场景和地图中的相互对应关系。当我们移动人物的时候,地图上的角色位置会同步更新!今天的小地图没有写一行代码啊,这时多么给力的一件事情啊。哈哈


          喜欢我请记住我的名字:秦元培,我的博客地址是:blog.csdn.net/qinyuanpei!
          转载请注明出处,本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/23628275

          大家晚安!

    展开全文
  • 在上一篇文章中,我们以经典的打砖块游戏为例,讲解了一个Unity3D游戏的完整实现过程。今天呢,我们来做一个在游戏中十分重要的组成元素:血条。血条是什么呢?血条是生命值的一种体现,就像《仙剑奇侠传三》电视剧...
  • [Unity3D]Unity3D游戏开发之Unity与Android交互调用研究

    万次阅读 多人点赞 2014-10-02 09:59:53
    众所周知,Unity3D是一个强大的跨平台游戏引擎,和大多数喜欢Unity的朋友一样,博主在体验了Unity强大的跨平台能力后,被深深地震撼了,试想以前我们如果要开发一款游戏的话,我们需要对DX、OpenGL等图形库
  • Unity3D 塔防游戏

    2020-07-30 23:33:34
    一个Unity塔防的资源包,供大家参考使用
  • 在本系列中,我们将在Unity3D中使用丰富的控件创建一个简单的3D游戏。 第一部分介绍了如何设置Unity3D ,第二部分介绍了如何 使用C#控制Unity3D 。 在本系列的最后一篇文章中,我们将深入研究如何使用Unity3D将...
  • Unity 3D游戏场景设计实例教程针对Unity3D引擎进行了全面、系统的讲解,全书从结构上主要分为3大部分:概论、引擎知识讲解以及实例制作讲解。概论主要针对游戏图像技术的发展以及当今游戏制作领域的主流引擎技术进行...
  • Unity3D】自学之路2.0

    万次阅读 多人点赞 2020-04-07 08:40:42
    一、前言 原文主要讲的是如何从零基础入门,然后一步一步进阶的文章,包括很多学习资料,学习的网址,研究方向等,内容还是比较全面的。大家多多支持一些克森大神,关注一下他的公众号。这篇文章就将原文的内容...
  • Unity3D游戏开发之SQLite让数据库开发更简单

    万次阅读 多人点赞 2015-11-03 08:09:40
    在经历了一段时间的忙碌后,博主终于有时间来研究新的东西啦,今天博客向和大家一起交流的内容是在Unity3D游戏开发中使用SQLite进行数据库开发,坦白来讲,在我的技术体系中Web和数据库是相对薄弱的两个部分,因此...
  • Unity3D游戏开发(第二版)及源码大小1个G,骗人是孙子。。。
  • 几乎所有代码都带有注释,适合新手入门理解运作原理,再决定要不要继续在这条路走下去。实现了多种功能(各种道具功能,...(之前的那份注释不全面,现在加了全注释,修复一个BUG,前面的资源删除不掉了,积分不够)
1 2 3 4 5 ... 20
收藏数 4,923
精华内容 1,969
关键字:

unity3d小游戏csdn