Unity3D之头顶Panel的实现与修复.docx

上传人:b****3 文档编号:12714518 上传时间:2023-04-21 格式:DOCX 页数:14 大小:205.48KB
下载 相关 举报
Unity3D之头顶Panel的实现与修复.docx_第1页
第1页 / 共14页
Unity3D之头顶Panel的实现与修复.docx_第2页
第2页 / 共14页
Unity3D之头顶Panel的实现与修复.docx_第3页
第3页 / 共14页
Unity3D之头顶Panel的实现与修复.docx_第4页
第4页 / 共14页
Unity3D之头顶Panel的实现与修复.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

Unity3D之头顶Panel的实现与修复.docx

《Unity3D之头顶Panel的实现与修复.docx》由会员分享,可在线阅读,更多相关《Unity3D之头顶Panel的实现与修复.docx(14页珍藏版)》请在冰豆网上搜索。

Unity3D之头顶Panel的实现与修复.docx

Unity3D之头顶Panel的实现与修复

   

Unity3D之头顶Panel的实现与修复

Daikon虽说有时候方便,但同样有时候很恼火。

因为相比NGUI,daikonGUI在网上基本上找不着什么资料,XX一搜,不是什么“太空泥”就是些稀奇古怪的东西,基本上别想找着点有用的东西,让我都怀疑在中国究竟有多少人在用DaikonGUI了?

NGUI虽说大多都是”过期资料“,好歹有些参考不是?

DaikonGUI就只有自个儿看官方的例子,看看源码了…..遇到问题,也同样只有自个儿折腾了..。

(特别是在我大农村,连官方文档都木有的情况下,会折腾死人的…)

   这次我采用的解决办法是,让DaikonGUI中的一个Panel负责接收一个GameObject和一个是否实例化的Bool变量,接收之后实例化一个先前做好的预制体,同时把GameObject对象传给这个新生成的预制体,当这个预制体得到所有信息后(比如生命、名字等),就附加上一个DaikonGUI的跟踪脚本,并把这个脚本的跟踪对象设置为跟踪物体。

   首先,在_Script中的GUI文件下,新建一个脚本,我命名为”MakeTopHeadContent“,这个脚本负责接收需要实例化的各种参数,首先是对各个变量的定义:

   publicdfPanelm_panel;//自己

   publicGameObjectm_TopHead;//头顶面板预制体

   privateTopHeadContentm_topHeadContent;//头顶面板

   publicGameObjectm_3DGameObject;//放置面板的对象

   publicboolm_ifAddTopContent=false;//是否已经创建了面板

   然后再在Start函数中获取自身的Panel对象(因为GUI的控件实例化同样必须使用GUI控件来进行,否则,无效):

VoidStart()

{

m_panel=GetComponent();

}

    

   现在在Update函数中就可以判断是否进行实例化操作了:

voidUpdate()

{

     

    if(m_ifAddTopContent)

         

    {

         

        m_topHeadContent=m_panel.AddPrefab(m_TopHead).GetComponent();             

         

        m_topHeadContent.m_showTarget=m_3DGameObject;

         

        m_ifAddTopContent=false;

         

    }

}

   

    在Update中,首先判断是否进行实例化操作,如果可以,就使用DaikonGUI的一个函数AddPrefab添加预制体,完成后取得这个预制体对象,并将需要跟踪的物体对向传给它,最后就是将可以实例化的操作置为false了。

   预制体也需要一些指定的操作,所以也需要一个脚本,在GUI文件夹下建立一个脚步,命名为TopHeadContent,代表这个预制体的脚本。

然后双击打开,首先定义了四个变量,分别用于存放需要跟踪的目标,目标的状态,以及目标当前血条的长度和名字:

publicGameObjectm_showTarget;

publicBattleChangem_targetState;

publicfloatm_lifeBarLengh=1;

publicstringm_name=”“;

voidStart()

{

     

    dfFollowObjectfollow=transform.gameObject.AddComponent("dfFollowObject").GetComponent();

     

    follow.attach=m_showTarget;//设置跟踪目标

     

    follow.offset.y=1;

     

    m_targetState=m_showTarget.GetComponent();//这是设置目标显示的内容

     

    while(m_name=="")

         

    {

         

        m_name=m_targetState.m_name;

         

    }

     

    m_lifeBarLengh=m_targetState.m_lifeBarLengh;

     

    

   这个脚本挺短小的,所以在这里我把需要添加的跟踪脚本直接定义在了Start中,然后添加并取得了这个跟踪脚本的对象,并把跟踪对象设置为需要跟踪的目标。

其中follow.offset.y=1;是设置高度,我设置为高一米。

然后获取目标的BattleState脚本对象,并在这个脚本中获取”名字“、”血条长度“的信息。

使用while来定义名字的原因是,名字的获取大概有些先后顺序,当对象还没赋给它时,获取到的名字就是空的,不可用。

所以才在这儿进行循环判断,是否获取到了名字。

   最后是Update函数,在Update函数中,只有一句话,那就是用于更新当前血条的长度(因为血条长度一般都是会动态变化的):

voidUpdate()

{

     

    m_lifeBarLengh=m_targetState.m_lifeBarLengh;

     

}

   

    现在在ChangeBattle脚本中,就要添加一些语句了。

首先定义两个变量:

   publicfloatm_lifeBarLengh=1;//血条长度

   publicfloatm_maxLife;//最大生命

   然后在Start函数中同样添加两句:

   m_maxLife=m_life;

   m_lifeBarLengh=m_life/m_maxLife

 

publicclassEnemySpawn:

MonoBehaviour{

     

    publicTransformm_enemy;//敌人

     

    publicTransformm_enemyBoss;//boss

     

    privateTransformm_madeEnemy;//已经制造出来的敌人

     

    privateBattleChangem_madeEnemyState;//已经制造出来的敌人的状态

     

    privateboolm_madeEnemyIsDead=true;//已经制造出来的敌人是否已经死掉

     

    privateTransformm_player;

     

    privateTransformm_transform;

     

    privateDayAndNightManagerm_dayAndNight;//日夜系统

     

    privatefloatm_makeTimer=0;

     

    privatefloatm_randomValue;//随机值

     

    voidStart()

     

    {

         

        m_transform=this.transform;

         

        m_player=GameObject.FindGameObjectWithTag("Player").transform;//获取角色对象

         

        m_dayAndNight=GameObject.FindGameObjectWithTag("DayAndNight").GetComponent();//获取日夜系统

         

    }

     

     

    voidUpdate()

     

    {

         

        m_makeTimer-=Time.deltaTime;

         

        if(Vector3.Distance(m_transform.position,m_player.position)<90)//如果与玩家距离小于90,就可以制造敌人了

             

        {

             

            if(m_madeEnemyState!

=null)

                 

            {

                 

                m_madeEnemyIsDead=m_madeEnemyState.m_isDead;

                 

            }

             

            if(m_makeTimer<0&&m_madeEnemyIsDead)//判断制造敌人冷却时间和当前制造出的敌人是否已经死掉了

                 

            {

                 

                m_randomValue=Random.value;

                 

                if(m_dayAndNight.m_hour>19||m_dayAndNight.m_hour<6)//如果是晚上,则boss刷新率翻倍

                     

                {

                     

                    m_randomValue+=0.05f;

                     

                }

                 

                if(Random.value<0.95f)//这是用于判断制造出Boss的概率

                     

                {

                     

                    m_madeEnemy=(Transform)Instantiate(m_enemy,m_transform.position,Quaternion.identity);

                     

                    m_madeEnemyState=m_madeEnemy.GetComponent();

                     

                    m_makeTimer=40;//四十秒一次

                     

                }else

                     

                {

                     

                    m_madeEnemy=(Transform)Instantiate(m_enemyBoss,m_transform.position,Quaternion.identity);

                     

                    m_madeEnemyState=m_madeEnemy.GetComponent();

                     

                    m_makeTimer=40;//四十秒一次

                     

                }

                 

            }

        }

    }

}

   首先在上面定义的变量就不用多说了,在Start函数中,我获取了自身、玩家角色以及昼夜系统的对象,以方便后来的使用。

   然后在Update函数中,首先将刷新敌人的计时器减一点之后,判断玩家与自己的距离(这是为性能考虑才这样做的),如果距离小于玩家所能看到的视线距离,就判断一下是否可以刷新敌人了。

这个判断依据就是计时器是否时间以到,并且实例化出来的敌人是否已经死掉了?

   如果两个条件都满足,就进入制造敌人的函数内,通过随机值判断是生成普通敌人还是Boss。

   再创造小狼和小狼Boss的时候,由于破电脑除了问题,导致数据出现了错误。

折腾半天,修好之后,倒也发现几处可以再次优化下的地方。

在Enemy脚本中,刚体和所在的层可以直接由脚本添加,写上以下几句代码之后,就不用每次都手动给敌人添加这几个属性了:

   //加刚体设置

   Rigidbodym_rigidbody=(Rigidbody)m_transform.gameObject.AddComponent(“Rigidbody”);

   m_rigidbody.freezeRotation=true;

   //

   m_transform.gameObject.layer=LayerMask.NameToLayer(“Human”);

   将小狼的那个实例的名字改为Wolf,然后把它拖放到_Enemy/EnemyPrefab/EnemyWolf中。

   如图:

   然后在_Script下的Enemy文件夹中将EnemyWolf脚本复制一份,并改名为EnemyWolfBoss,双击脚本打开,改一下属性即可:

usingUnityEngine;

usingSystem.Collections;

publicclassEnemyWolfBoss:

Enemy{

     

    protectedoverridevoidInit()

     

    {

         

        m_isBoss=true;

         

        SetAttribute("5级小狼王",5*10,670,30,80,4,80,3.5f);

         

    }

}

    

   然后回到场景中的那个小狼身上,将他放大一点,移除远来的EnemyWolf脚本,把EnemyWolfBoss脚本拖给它。

再将其拖动到EnemyWolf文件夹下,做成一个预制体即可。

   运行游戏就差不多了。

   只是在这儿的狼王的头顶显示的内容会不全面,因为此前制作面板的时候,daikonGUI有点问题,添加的Label不能勾选AutoSize的,不然会飞很远。

所以在这儿,又是研究良久,找到一个折衷的办法。

   首先将原来的那个用来显示名字的Label去掉,而重新在Progress下面新建一个Label,如图:

   将Label的大小拉得长长的额,然后在Formatting中的TextAlign选择为Center。

就达到像上图的效果了。

   最后一步,在场景中新建一个空的GameObject,并将先前写好的EnemySpawn脚本拖给它,再把做好的小狼预制体、小狼Boss预制体分别赋给它,随便放在游戏中一个地方,运行游戏,就OK了!

   最后,又是一个问题被发现了。

就是敌人将玩家攻击死亡之后,不会再停止攻击了!

   这问题又调试了一个小时,最后发现,是GetState函数中的问题。

因为以前写完GetState函数以后没有对主动攻击自己的对象进行释放,结果造成了即便攻击对象已经死亡,这些怪物还在继续着“鞭尸”这样可恨的行为!

   花了大功夫去调试的问题,最后却发现只要在WaitForAttack函数中,判断对象已经死掉了的语句里面加上一句话就可以了:

   m_changeState.m_changeMeTarget=null;

   现在我已经忘了原来的的代码是啥样了…..不过还好,虽然现在时间很暗了,这个问题也算是不完美地解决了!

   刚开始我记得是在Enemy脚本中的Start函数里进行头顶面板创建的通知的,默认函数只会去呼叫一次创建面板,我猜想可能这样就导致了如果一下子实例化出来的物体过多的话,那么当面板还没创建出来的时候,我传入的当前物体的对象就被其他对象覆盖了,就没了….

   于是我就想用wihle这个循环语句进行判断MakeTopHeadContent中是否添加了面板,当然结果是失败了……(不过这也已经是第N个思路了),后来改用在BattleChange中定义一个变量:

   publicboolm_addedPanel=false;//是否已经添加了头顶面板

   创建面板后获取对象,然后再在MakeTopHeadContent脚本中,把已经添加了面板的判断置为真。

Enemy中判断是否添加了面板:

while(!

m_changeState.m_addedPanel)

{

m_makeTopOfTheHead.m_3DGameObject=m_transform.gameObject;//通知GUI建头顶面板

}

在Update函数里加上这样一句:

if(!

m_changeState.m_addedPanel)

{

m_makeTopOfTheHead.m_3DGameObject=m_transform.gameObject;//通知GUI创建头顶面板

}

   然后是MakeTopHeadContent这个脚本,现在已经定义的变量有:

   publicdfPanelm_panel;//自己

   publicGameObjectm_TopHead;//头顶面板预制体

   privateTopHeadContentm_topHeadContent;//头顶面板

   publicGameObjectm_3DGameObject;//放置面板的对象

   privateGameObjectm_tempGameObject;//用于缓存已经添加了面板的对象

   在Update函数中,判断对象是否已经创建了面板(因为Update函数每帧都要调用一次,在不确定是否会重复调用的话,最好这样判断一下,而且因为判断比全都执行一次节约资源多了):

voidUpdate()

{

if(m_tempGameObject!

=m_3DGameObject)

{

m_tempGameObject=m_3DgameObject

m_topHeadContent=m_panel.AddPrefab(m_TopHead).GetComponent();

m_topHeadContent.m_showTarget=m_3DGameObject;

m_3DGameObject.GetComponent().m_addedPanel=true;

}

}

    

   具体作用就是判断物体是否已经创建了面板,如果没有创建,就进入if语句中,将当前这个物体对象放进缓存对象中,并创建一个面板同时取得这个面板对象,然后将需要显示信息的物体对象传入这个面板对象,完成后将已经有了面板的物体“m_addedPanel”设置为true,代表已经添加了面板对象,这样在Enemy函数中就不会再传入自己的对象到这个创建面板的脚本中了。

效果如下:

   首先是,因为之前计算血条长度的时候,我是使用只获取对象的生命(又是为了省资源……),然后通过把这个生命值直接作为最大生命,结过由于变量赋值与初始化不同步,有一定概率出现血

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1