|
前文:
Unity快速上手教程(一):拉方块
Unity快速上手系列之2:2D物理弹球
Unity快速上手教程(三):《反应堆》实例开发
未尝试做过跑酷游戏,大约相当于没学过游戏开发。
玩笑至此,想传达的意思大家想必也清楚。跑酷游戏普遍非常简单,但简单并不代表简陋,跑酷是最能体现“麻雀虽小五脏俱全”的游戏类型。在当中开发者可以充分展示自己的设计才能,无论是奇思妙想的关卡设计还是灵光一现的功能创意。这样必然能获取到充足而高频的正反馈——而这一切都是建立在这样一个门槛较低的游戏体量上的。
因此对于初学者来说,没有比它更合适练手的类型了,这也是我专门写这样一篇番外篇的目的。
闲话少叙,直接开干。
创建地形
地面
标配的地面和天花板自不必说,跟着自己的喜好设计即可。
而移动地形则能稍微增加一点变数。以垂直升降为例,在自己设定的移动范围内,地形最低位置就向上移动,反之亦然。把脚本挂载到对应地形上即可:
- void Update() {
- if (transform.position.y > 0) {
- IsChange = false;
- }
- if (transform.position.y < -6) {
- IsChange = true;
- }
- if (IsChange == false) {
- //在世界坐标向下移动
- transform.Translate(0, -4 * Time.deltaTime, 0, Space.World);
- } else {
- //在世界坐标向上移动
- transform.Translate(0, 4 * Time.deltaTime, 0, Space.World);
- }
- }
复制代码
水平移动同理。
背景
以下图为例,一张普通的砖墙背景:
为了展示出向前跑的效果,需要让图片每一帧向后移动。
transform.position=new Vector3(transform.position.x-0.03f,transform.position.y,transform.position.z);
顺便说一句,在Unity2018版本中可以使用纹理偏移的方法来达到类似的效果,这样就不用单独移动图片了:
- public float scrollSpeed = 0.5f;
- public Renderer = rend;
- //Use this for initialization
- void Start()
- {
- rend = GetComponent<Renderer>();
- }
- //Update is called once per frame
- void Update()
- {
- float offset = Time.time * scrollSpeed;
- rend.material.mainTextureOffset = new Vector2(offset, 0); //纹理偏移
- }
复制代码
与之对应的就不再是创建一个精灵,而是创建Quad:
角色
角色图片
把图片素材放在精灵上,并加上刚体和碰撞盒子:
强调一下,网上的图片素材一定只能供自己学习,一定不能用作商业用途!
角色动作
1、移动
我们给角色一个速度,使得游戏一开始角色就向右移动。
- myRigidbody.transform.Translate(speed*Time.deltaTime,0,0);
复制代码
2、跳跃
按下空格键给它一个向上的力,使得角色可以向上跳跃。有两个判断:只有当检测到玩家在地面上,或者在天花板上时,才能跳跃。在空中不能跳跃。当然,通过稍微的逻辑修改,还可以让角色实现二段跳功能。
- //按下空格键可以使方块跳跃
- if (Input.GetKeyDown(KeyCode.Space))
- {
- if (Physics2D.Raycast(transform.position, Vector2.down,hight, LayerMask.GetMask("ground")))
- {
- myRigidbody.AddForce(Vector3.up * upspeed, ForceMode2D.Impulse); //给它一个向上的力
- }
- if (Physics2D.Raycast(transform.position, Vector2.down, hight, LayerMask.GetMask("ceiling")))
- {
- myRigidbody.AddForce(Vector3.up * upspeed, ForceMode2D.Impulse); //给它一个向上的力
- }
- }
复制代码
3、放缩
在这个示例里,我给予了玩家一个放缩的特性,通过灵活地改变体型的大小来通过障碍物。根据体型不同,跳跃能力、奔跑速度会发生相应的变化。
- if (transform.localScale.x>0.3)
- {
- //按下A键可以缩小方块
- if (Input.GetKey(KeyCode.A))
- {
- transform.localScale = new Vector3(transform.localScale.x - 0.01f, transform.localScale.y - 0.01f, transform.localScale.z - 0.01f);
- speed = speed + 0.05f;
- upspeed = upspeed + 0.05f;
- }
- }
复制代码- if(transform.localScale.x <=1)
- {
- //按下D键可以变大方块
- if (Input.GetKey(KeyCode.D))
- {
- //检测到方块上面是天花板则不能变大
- if (Physics2D.Raycast(transform.position, Vector2.up, 0.5f*hight, LayerMask.GetMask("ceiling")))
- {
- }
- else
- {
- transform.localScale = new Vector3(transform.localScale.x + 0.01f, transform.localScale.y + 0.01f, transform.localScale.z + 0.01f);
- speed = speed - 0.05f;
- upspeed = upspeed - 0.05f;
- }
- }
复制代码
效果如图:
摄像机
这一部分的处理较为简单,只需要让镜头跟随玩家移动即可。
- //让相机跟着玩家移动
- transform.position = new Vector3(player.transform.position.x + 5, 0 , transform.position.z);
复制代码
金币
金币是场景中散落的收集要素,就跟《超级马里奥》中的金币一样。
图片资源随便用一个:
我们让金币带上一个旋转的样式:
- transform.Rotate(Vector3.up * 4, Space.World); //原地旋转
复制代码
效果如下图所示:
根据收集逻辑,场景中的金币一旦被玩家所触碰到,就会自动移动至UI中金币数量位置。
金币的移动函数如下:
- //金币向目标点移动
- public void CoinMove()
- {
- //UI坐标转换成世界坐标
- UIcoin = Camera.main.ScreenToWorldPoint(AllCoin.transform.position);
- //当前物体向这某一个物体移动
- transform.position = Vector3.MoveTowards(transform.position, UIcoin + Vector3.forward, 25 * Time.deltaTime);
- //两个坐标相减是方向,用sqrMagnitude获取方向的距离
- if ((transform.position - (UIcoin + Vector3.forward)).sqrMagnitude < 0.1f)
- {
- player.GetComponent<PlayerMove>().money++;
- player.GetComponent<PlayerMove>().SetMoney();
- Destroy(gameObject);
- }
- }
复制代码
当然,要触发这个移动函数,还需要增加一个检测碰撞的过程,在过程中调用移动函数。不要忘了给金币添加碰撞盒子。
- void Update ()
- {
- transform.Rotate(Vector3.up * 4, Space.World); //原地旋转
- if (IsRun == true)
- {
- CoinMove();
- }
- }
- public void OnTriggerEnter2D(Collider2D coll)
- {
- if (coll.gameObject.CompareTag("Player"))
- {
- IsRun = true;
- }
- }
复制代码
在角色脚本中获取该数量text。
- void Start ()
- {
- myRigidbody = this.GetComponent<Rigidbody2D>();
- money = 0;
- SetMoney();
- Hp.gameObject.SetActive(false);
- }
- public void SetMoney() //改变金币数量
- {
- MoneyText.text = money.ToString();
- }
复制代码
金币时,金币在移动至相应位置的同时,数量+1,并销毁自己。
- player.GetComponent<PlayerMove>().money++;
- player.GetComponent<PlayerMove>().SetMoney();
- Destroy(gameObject);
复制代码
机关
角色一旦碰到场景中的各种机关,就宣告game over。机关分为固定机关和移动机关两种。
移动机关当检测到角色靠近时,就自动向下掉落,碰到地板后停止运动,在掉落过程中如果碰到玩家则game over。
- void Update ()
- {
- if (isRun==true)
- {
- //玩家靠近绝对值距离小于4时火焰下落
- if (Mathf.Abs(player.transform.position.x-transform.position.x)<4)
- {
- transform.Translate(0, -9 * Time.deltaTime, 0, Space.World);
- }
- }
- }
- public void OnTriggerEnter2D(Collider2D coll)
- {
- if (coll.gameObject.CompareTag("ground"))
- {
- isRun = false;
- }
复制代码
磁铁功能
很多跑酷游戏里都会有“磁铁”这样的powerup道具,吃到后,会在一定时间内让场景中的金币自动被吸附到玩家身上。
碰撞盒
要实现这样的功能,我们首先需要给磁铁加一个可任意调整的碰撞盒。
随意改变一下形状,能碰到前方的金币即可。
拾取金币
- public void OnTriggerEnter2D(Collider2D coll)
- {
- if(coll.gameObject.CompareTag("coin"))
- {
- coll.GetComponent<Coin>().IsRun = true;
- }
- }
复制代码
碰撞盒碰到金币的盒子时,把金币的IsRun改为True,此时金币就会自动跑向目标点,达到磁铁吸金的效果。
跟随角色
角色碰到磁铁后,为了让吸金效果跟随角色,需要让磁铁本身也跟随角色一起移动。
- if (coll.gameObject.CompareTag("Player"))
- {
- IsFollow = true;
- }
- void Update ()
- {
- if (IsFollow == true)
- {
- //跟着玩家移动
- transform.position = new Vector3(player.transform.position.x - 0.5f, player.transform.position.y + 1, transform.position.z);
- }
- }
复制代码
时间条
我们首先创建两张图片,分别为白色和绿色的,绿色图片在白色图片之上,两张大小一样。
找到面板上的绿色时间条,然后以帧为单位逐渐缩小尺寸。在减少为0的时候销毁磁铁和时间条,意味着磁铁失效。
- //找到玩家
- public GameObject player;
- //找到血量条
- public GameObject MagnetHp;
- //找到HP图片
- public Image HpPhoto;
- //HP数值
- public float Hp;
- //是否移动
- public bool IsFollow = false;
- void Update ()
- {
- if (IsFollow==true)
- {
- //改变Rotation
- transform.eulerAngles = new Vector3(0,0,0);
- transform.localScale = new Vector3(0.17f, 0.17f, transform.localScale.z);
- transform.position = new Vector3(player.transform.position.x-0.5f, player.transform.position.y+1, transform.position.z);
- player.GetComponent<PlayerMove>().Hp.gameObject.SetActive(true);
- Hp = Hp - 0.002f;
- if(Hp<0)
- {
- Hp = 0;
- Destroy(transform.parent.gameObject); //销毁磁铁
- Destroy(MagnetHp); //销毁血条
- }
- //实时更新面板上的HP数值
- HpPhoto.rectTransform.localScale = new Vector3(Hp, HpPhoto.rectTransform.localScale.y, HpPhoto.rectTransform.localScale.z);
- }
- }
复制代码
切换属性
这是在本篇示例中另外添加的一个特性:属性切换。
场景中有时会出现类似于水墙的障碍,玩家需要切换角色的属性后才能通过。
水属性图片:
当角色触碰到上图时,切换角色外形为如下:
- player.GetComponent<SpriteRenderer>().sprite = tupian;
复制代码
当检测到玩家属性已切换时,将水墙的碰撞盒变为可穿越即可。
- rainbowwall.GetComponent<BoxCollider2D>().isTrigger = true;
复制代码
游戏结束
goal标志
当玩家到达goal标志时,判定玩家闯关成功。
反之,玩家碰到机关、摔下悬崖或是未能穿过水墙时,判定游戏失败。
That's it。实际运行的效果如下:
完整的工程如下:
wushupei/RunGamegithub.com
这样一个简单的游戏却作用多多,不光可以应对类似于课程设计之类的学习任务,还足以作为开发者的入门第一次实践。希望能藉由此文,让尽量多的盆友们踏上游戏开发令人激动的旅程中去。
照样怒宣传一波:想系统性学习游戏开发、学习Unity开发的,欢迎围观:
http://levelpp.com/
在线的教学视频:
https://space.bilibili.com/38043731/#/
以及QQ交流群:610475807
作者:四五二十
专栏地址:https://zhuanlan.zhihu.com/p/38476477
|
|