2019年7月17日学习日记

**

第三天

**

***见天天气好晴朗处处好风光。早上好,今天刚打开U3d就出现了了一件不愉快的事情,打开相应的项目后材料包脚本包还在,而scene中的各个控件却不在了。这里就需要我们在Assets选项中选择我们已经创建的U3d类型文件,让其于scene同步。好的接下来让我们继续昨天的学习。
一转眼,上午已经过去了,拿出最后的半个小时做一下总结。让我们看看我们的程序中多出来了什么!***在这里插入图片描述
昨天我们刚刚实现了小球的走动,随后就要考虑小球的跳跃。这里我们用了新的方法Raycast:

public static bool RayCast(Vector3 origin, Vector3 direction, float maxDistance );

这里分别取到了原位置坐标,射线方向向量,和射出距离。这里我们要保证球在空中,不能让它在空中连跳,这时候就可以可以看做我们的球从圆心到正下方有一把透明的尺子,要是尺子穿过或者接触了Floor,就可以进行跳跃,如果没有接触,就视为小球在空中无法进行跳跃。显然,若bool为真则进行跳跃,可是这里要注意。由于这个力不能是持续力,且和重力相互作用,一直按着空格也只能作用一次跳跃,为了满足这些条件我们这里调用了力量模式中的Impulse。具体代码如下:

    public void Jump()
    {
        if (Physics.Raycast(transform.position, Vector3.down, 0.6f))//位置方向和大小
        {
            rigid.AddForce(Vector3.up * 2f, ForceMode.Impulse);//瞬间把力加载物体上
        }
    }

很明显这个AddForce在我们昨天施加平面力的时候也有用到,不过不同的是这里我们多加了一个参数,将力以脉冲形式放到物体上,形成跳跃。我们已经写完了跳跃的方法,之后就要在PlayerCtroller中调用。由于这个动作也需要键盘的配合,我们依旧使用Input方法:

        var jump = Input.GetKeyDown(KeyCode.Space);
        if (jump)
        {
            character.Jump();
        }

在得到按键落下后就,执行跳跃动作判断在跳跃函数内部。小球会走会跳了,我们需要给小球加得分对象,在拉入硬币后建立对应的脚本:

    public AudioClip pickSound; //实例化一个音频控件
    private void OnTriggerEnter(Collider other)//碰撞触发器
    {
        var player = other.GetComponent<PlayerCharacter>();//硬币被player碰撞后进行连接,即以变量player得到碰撞对象
        if (player)//要是对硬币也连接成功
        {
            player.AddCoins();//加硬币-----count
            gameObject.SetActive(false);//硬币消失
            player.coinCount++;
            AudioSource.PlayClipAtPoint(pickSound, transform.position );//点播放剪辑,前者地址后者方向位置
        }
    }

依旧和昨天差不多,由于硬币是被“碰撞”的对象,这里就调用碰撞触发器来接收小球的碰撞。
这里有一个问题:什么时候用GetComponent什么时候用FindObjectOfType??

下面对这一天上午提出的这个问题做出解答,两个方法其实本质可以互逆,因为GetComponent是获取物体下的组件,儿FindObjectOfType是用来获取挂着本简本的第一个组件。两个东西容易弄混,要多加练习。

实例化player调用PlayerCharacter脚本后,再检验一下是否调用成功。方法直接内包就可以了。最基本的就是被碰撞之后硬币的消失,调用了gameObject.SecActive方法,上一个游戏也有用到。随后执行硬币增加函数。同时进行吃掉硬币后的音乐播放。这里调用了最初创建的控件:

public AudioClip pickSound; //实例化一个音频控件

在只需要播放简单的音效时,可以使用PlayClipAtPoint来播放,不需要添加AudioSource,不需要获取各个AudioSource的引用,就可以直接播放声音。参数为音源和播放位置即当前坐标。小球得分当然是可以 ,得分也要进行计数,拉入画布再加入子节点text,利用对text内容的调用来对分数进行显示,分数之前的函数中已经数出。由于只是显示分数,控件函数也只是简单的两部分:

public Text goldCount;
    public GameObject GameEndPanel;
    PlayerCharacter character;
    private void Awake()//唤醒
    {
        character = FindObjectOfType<PlayerCharacter>();
    }
    private void Update()
    {
        goldCount.text = "Coin Count:"+ character.coinCount.ToString();
    }

先声明一个text,在U3d内部好进行控件的拖拉和联动,而GameEndPanel是一个在text下面的大白色背景,只是在游戏死亡后出现,也要进行声明。建立脚本和主游戏角色脚本的联系(唤醒)。在更新的时候只需要更新里面的文字,其中character.coinCount已经是public类型的,在Coin被触发的时候就进行增值,在建立连接之后就会持续update。至于小球死亡后在PlayerCharacter:

    private void Update()
    {
        if (transform.position.y<-30)
        {
            if(isAlive)
            {
                Die();
            }
        }
    }
    void Die()
    {
        isAlive = false;
        AudioSource.PlayClipAtPoint(dieSound, transform.position);
        controller.ShowGameEndPanel();
    }

***在没一次刷新的时候都要确认小球儿的位置是否已经掉落至水平下三十单位,如果掉落判定成立,且此时活着,调用死亡函数。死亡函数有三个功能,将生存状态变为false,死亡时播放死亡音效,弹出结束面板(所以说一开始死亡面板是隐藏的,要注意Inspector面板中tag上面的勾取消,这个就代表开始是隐藏的)。好的,上午的一些代码和书写已经总结完毕了,开始下午的学习。小球现在碰撞硬币之后硬币消失发出声音记分板可以改变分数,死亡后也有死亡界面
那么我们在后面该怎么操作呢?怎么在死亡之后复位呢?又怎么让小球进行更加复杂的操作呢?Suo实话,真的没啥特殊操作了。
死亡之后出现Panel,取消的条件Button中设置类似WPF中的 Click事件。这里注意,Button用谁的方法就要把谁的方法public化,并且把组件拉入左下角的框框内

在这里插入图片描述

我们把函数写在PlayerHUD脚本中,很多事件要在U3d中出现就需要public化这里我们在点击之后对整个程序进行了重载:

    public void OnClick_RestartGame()
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene("Start");//保存的文件名字
    }

调用了引擎中的管理方法,不必死记。游戏在进行期间,有两种方式让游戏结束,一个是挂了(摔下平台,限制条件),另外一个是通关,因此之后要设计关于正式通关的代码,先写脚本。由于都是属于被碰撞后过关和者发出声音,因此把coin代码复制到新创建的CheckPoint脚本中,需要修改的有函数名字。而且在触发器函数中也不再需要进行coinCount的增加,且通关点不必消失:

    private void OnTriggerEnter(Collider other)//碰撞触发器
    {
        var player = other.GetComponent<PlayerCharacter>();//硬币被player碰撞后进行连接,即以变量player得到碰撞对象
        if (player)//
        {
            player.controller.LevelComplete();
         //   gameObject.SetActive(false);
            AudioSource.PlayClipAtPoint(checkPointSound, transform.position);//点播放剪辑,前者地址后者方向位置
        }
    }

可见在取到组件并且判断是否成功取到后,里面只需要两段代码,一个是游戏完成代码一个是音乐播放代码。最后的最后我们需要创建一个GameMode脚本,来判断游戏是否真正结束:

public class GameMode : MonoBehaviour
{
    public bool isGameEnd = false;
}

代码很简单,但有一些细节需要修改,比如球在掉落的时候,需要判断游戏是否已经结束,如果结束,再进行多余的操作没有意义,因此再调用死亡函数外的if函数中需要判断两项即 “IsAlive”、“controller.gameMode.isGameEnd == false”。很考验逻辑的严谨性。细节真的还有很多,说的话太费力,我要在最后做一次模拟的游戏总结~~~

***首先这是一个球球游戏,因此要拉入 地板 和 球儿 ,两种组件都要加物理控件,且注意不要乱勾选触发器。这个时候我们让U3d项目运行会发现球儿落到了地板上,很安详,我们无法控制,因此这里我们要给球加控制组件。这里本次给一个组件加了两个脚本:PlayerCharacter和PlayerController,其中PlayerCharacter脚本主要写一些关于组件最基本的操作,就像移动和跳跃,但细节还需要我们的控制器即PlayerController给出。在写PlayerCharacter脚本的第一步就是取到它的Rigidbody脚本,并调用。因为其为刚体脚本,物体的一切运动都无法脱离刚体控件。在唤醒函数中得到了实例化的rigid后还需要取到调用PlayerCtroller的方法,因此调用 FindObjectOfType方法,得到PlayerCtroller的上一级组件,即我们可以通过实例化的对像”点儿“出来调用。前面我们虽然创建了一个PlayerCtroller类型的变量却并没有真正建立他和真正脚本之间的联系,这个实例化就帮助我们建立了联系,让我们更好的调用方法。 接下来就到了最重要的移动 。和第一个游戏一样。先写Move函数参数变量为一个三维向量,给出了物体受力方向,在U3d一般情况下我们受的都是单位力,因此在调用rigid.AddForce(Vector)的时候需要对force进行加工,或乘一个数,或给其一个函数变量,来对我们的速度进行约束或者扩大缩小。顺理成章,这个时候我们就需要对力的方向参数进行描述。用两个var型变量来接收水平和竖直方向,即按下的上下左右。但是我们这次是第一人称视角,相机是跟随的,我们每一刻都是朝向前方,不像再2D平面内以上帝视角。因此我们这次设置单位力的方向需要用用我们键盘输入的单位方向来对相机方向进行乘积,之后单位化得到单位受力方向。最后要调用PlayerCharacter脚本中的Move方法,将得到的单位力写入,让球可以运动。至于跳跃,这里用了一个新方法Raycast,具体参照上面,且在判断可以跳起后还要再次调用刚体的AddForce方法,不过这次不同的是要加第二个ForceMode参数,来让其形成脉冲式给力,不然持续力会让球儿飞。这里正确定义了球儿跳起的方法,判断其是否应该跳的最根本就是空格键是否被按下。这里调用了Input.GetKeyDown(KeyCode.Space),这个是bool类型的,要是按下了空格就为真,这个时候就可以调用character中的Jump函数,进行跳跃。这里又有问题了,PlayerController中怎么调用PlayerCharacter的呢??所以我们在创建PlayerCharacter类型变量的同时需要在Awake函数中进行唤醒,由于是同级脚本,如果需要点出其方法就要调用FindObjectOdType建立我们变量和脚本之间的关系,好调用方法。到了这里我们已经让小球学会了跑跳。之后就是给小球安排敌人,其实也不算是敌人,是要被我们吃掉的Coin。当然,第一步是拉入一个Coin,之后建立一个Coin脚本,二话不说直接给它搞一个碰撞器,得到撞他的东西的PlayerCharacter,其实就是得到球的这个控件,不过是通过刚体之间的碰撞触发这个条件。再判断如果得到控件成功,吃掉的硬币(coinCount)数加一,这枚硬币消失,播放一个得分音乐。这里硬币消失直接调用gameObject,因为Coin脚本是直接挂在Coin这个模型上的,通过对其组件方法SetActive的调用可以让它处于隐藏状态。因此gameObject不必特意去赋值,直接得到当前控件。音乐的播放则需要实例化一个控件public AudioClip pickSound;一定要public,这样再脚本中才会出现框框,利于让我们进行音乐素材的拖拽AudioSource.PlayClipAtPoint(pickSound, transform.position );其中参数只有音乐和播放位置,这里音乐的播放位置取的是当前组件所在位置,利用transform控件得到。好了,现在吃球能得分了,我们需要把分数显示出来,先在Hierarchy中建立一个空folder,取名PlayerHUD,主要用来对本游戏的UI进行调控。再在子节点建立一个画布(Canvas),画布子节点建立一个text改名为CoinCount。text的内容也可通过方法的调用来改变。先在控制UI的脚本PlayerHUD中创建Text类型”变量“goldCount。由上面编写的程序可知,coinCount存在于PlayerCharacter中,因此创建一个PlayerCharacter类型”变量“来连接到挂载这个脚本的问题***(private void Awake() { character = FindObjectOfType<PlayerCharacter>(); }),以便于以第一视角调用这个脚本的方法。在刷新函数中:

    private void Update()
    {
        goldCount.text = "Coin Count:"+ character.coinCount.ToString();
    }

**这个脚本可以直接挂在任何运行的组件上,这里我们选择新建一个空组件并命名为coinCount,承载脚本,严谨。
所有文字的显示都要转换为string类型,这里调用了PlayerCharacter中的coinCount并转换为string类型连接在原Txt内容中。 之 后就是在死亡后结束我们的游戏,跳出结束界面。依旧是在PlayerHUD中的Canvas子节点进行操作。创建一个板(Panel)并在子节点下创建Buttion,改变Button的Text文本属性为ReStart。之后就要书写关于Button的脚本,这里我们直接把Button的触发方法放在了PlayerHUD脚本中,以便于调用。这里注意,由于scene右边的Hierarchy目录由层次关系,即根目录和子节点关系。脚本也有上下级关系,因此如图(但上下级关系并不绝对):<
/**font>
在这里插入图片描述
这里是声明的两种变量,第一种已经在本脚本中被赋值。第二种则需要在在Hierarchy中拉入以在别的脚本调用,唤出和隐藏。
在这里插入图片描述
在这里可见GameEndPanel底层还有button和text。这里我们继续对于Panel控件来进行细说:

    public void ShowGameEndPanel()//在没有过关的时候弹出的窗口
    {
        hud.GameEndPanel.SetActive(true);
        gameMode.isGameEnd = true;
    }
    public void LevelComplete()//过关
    {
        hud.GameEndPanel.SetActive(true);
        gameMode.isGameEnd = true;
    }

如上调用了了PlayerHUD的下一层方法,这里我们就要取到这个载体以调用它的方法。这里的方法需要和其他脚本进行联动。比如死亡后调用游戏结束框,触碰到CheckPoint后调用关卡完成方法。两个方法内部代码完全一样,名字不一样,逻辑概念不一样,因此也不要乱起名字。
CheckPoint和Coin一样都需要被触碰才能触发,因此在Coin的基础上进行修改,除了名字需要修改,对加分方法也可以删掉,且不需要让此控件消失,因为游戏已经结束。
到最后再说一次

transform.Find();
通过名字查找子物体,原来一直以为只能查找挂载该脚本的物体下的子物体,后来经过测试发现,也能找到同级别的物体下的子物体
方法是:transform.Find(“同级别的物体的名字/ 子物体名”);
FindObjectOfType<>();
找到挂<脚本>载该脚本的第一个物体 GetComponent<>(); 直接获取该物体下的<组件名>某组件。



来了来了第三个游戏来了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值