基于unity3d实现的简单的google小恐龙1

本文讲述了作者利用大学期间学习的Unity3D和C#技术,尝试制作小恐龙游戏的过程,包括基础设计如地面移动、仙人掌和翼龙障碍物,以及主角小恐龙的移动控制。作者分享了关键代码片段,展示了如何使用刚体和脚本来实现游戏元素的移动和碰撞检测。
摘要由CSDN通过智能技术生成

 标题1:前言

主要是由于即将大学毕业,但是感觉什么都没学,又苦于找工作,所以想要尝试一下用之前学的u3D知识,编写一些简单的一个小恐龙游戏。很久之前根据书籍《游戏设计,原型与开发 基于untiy与C#从构思到实现》----jeremy Gibson Bond 实现过一些简单的实例,例如接苹果,弹弓(类似愤怒的小鸟),太空射击以及地牢游戏等。但是由于大学有时候比较忙,感觉有点生疏之类的,所以趁着暑假,写一些东西练习一下。

 首先是谷歌小恐龙这个游戏,是谷歌浏览器在用户断网的情况下,自带的一款小游戏,基本内容就是一直恐龙在地面上跳动,然后躲避迎面而来的仙人掌和翼龙。游戏比较简单易懂,用来练习耶很不错。

但是直接实现这个游戏也有点过于简单,因此想要在这个游戏的基础上增加一些自己的内容,丰富一下,顺便也强化一下代码设计能力。

谷歌小恐龙游戏:谷歌浏览器内输入chrome://dino

基础设计

地板设计:

首先是设计地面移动的效果,一般来说这样的游戏基本是使用相对运动的模式,因此只需要地面向前移动就可以看起来像是小恐龙在前面跑动一样。为了连接的连贯性准备两个地面对象,利用卷轴进行交替移动。

上面这个是地面的对象实体

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class groundMove : MonoBehaviour
{
    [Header("Set in Inspector")]
    public float speed = 5f;
    [Header("Set Dynamically")]
    private Rigidbody rid;
    // Start is called before the first frame update
    void Start()
    {
        rid = GetComponent<Rigidbody>();//初始化刚体
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 vel=Vector3.zero;//普通移动
        vel = Vector3.left;
        rid.velocity = vel*speed;
        Vector3 pos=gameObject.transform.position;
        if (pos.x <= 10.8f)
        {
            pos.x = 39.2f;
            gameObject.transform.position = pos;
        }
    }
}

以上是地面移动代码,根据摄像机的坐标以及大小进行交替移动 ,一共两个地面对象。

仙人掌设计:

仙人掌的设计也是一样,因为恐龙并不是真正的移动,因此仙人掌的逻辑跟地面差不多,可以直接给他赋予一个向左的速度,超出屏幕就消失,然后再拿多几个仙人掌的对象

以上为使用的三个个仙人掌图像 

 这三个实体随机出现,仙人掌的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CactusMove : MonoBehaviour
{
    [Header("Set inInspector")]
    public float speed = 5f;
    public Vector3 summonPos;//表示生成坐标
    [Header("Set Dynamically")]
    private Rigidbody rig;
    // Start is called before the first frame update
    void Start()
    {
        rig = GetComponent<Rigidbody>();//初始化刚体
        summonPos = new Vector3(39, 3.8f, 0);//生成坐标初始化
        gameObject.transform.position = summonPos;
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 pos =gameObject.transform.position;
        Vector3 vel = Vector3.left;
        rig.velocity = vel * speed;
        if (pos.x <= 18)
        {
            Destroy(gameObject);
        }//超出范围销毁
    }
}

翼龙设计:

游戏里面除了仙人掌这一种障碍物,还有一种叫做翼龙的障碍物,但是其实在游戏里面这个翼龙,他所拥有的逻辑其实跟仙人掌一摸一样,因此我觉得再搞一个对象再加一摸一样的脚本没什么意思,可以自己写一个。根据实例里面写过的太空设计,有一种会朝玩家冲过来的敌人,可以参考这一个,设计的翼龙会在屏幕上方随机生成,然后记录玩家当前位置(不是瞬时位置)并朝玩家冲过去。这也是比较简单的一种设计思路。那就这样写吧。

以上是翼龙的图像

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class flyMove : MonoBehaviour
{
    [Header("Set in Inspector")]
    public GameObject dino;//恐龙对象
    public float speed;
    public Vector3 dinoPos;
    public Vector3 vel;
    public Vector3 summonPos;
    public int facing = 1;//生成在前面还是后面
    private Rigidbody rig;//刚体对象
    private bool isTrack;

    // Start is called before the first frame update
    void Start()
    {
        dino = GameObject.Find("dino");
        dinoPos = dino.transform.position;
        float x = Random.Range(17, 31);//随机一个x轴坐标
        summonPos = new Vector3(x, 10f, 0);
        gameObject.transform.position = summonPos;
        if (summonPos.x - dinoPos.x<=0)//生成在后面
        {
            facing = -1;
        }
        if (facing == -1) {//假设为后方
            gameObject.transform.rotation = Quaternion.Euler(0, 180f, 0);
                }//找到游戏中的恐龙对象
        rig = GetComponent<Rigidbody>();//获取刚体
        isTrack = false;
        speed = 5f;
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 pos =gameObject.transform.position;
        if (pos.x <= 18 || pos.x >= 32)
        {
            Destroy(gameObject);
        }//超出范围销毁
        if (dino != null&&isTrack==false)//假如不存在恐龙对象
        {
            vel =dinoPos-gameObject.transform.position;//获取速度方向
            vel.Normalize();
            rig.velocity = vel*speed;
            isTrack = true;
        }
    }
}

 翼龙会根据玩家的位置转向,因为只是普通的2D模型,因此只需要绕Y轴转动180度即可。

小恐龙的设计:

小恐龙是游戏里面的主角,但是再谷歌自带的游戏里,小恐龙只可以原地跳动,这个逻辑只需要再检测按键之后,让小恐龙的RIG.velocity获得一个向上的速度即可,因此我决定再次自己写一个,根据获取的KeyCode,可以使得其进行左右移动,同时给予一个冲刺效果。

设计的时候出现了一点问题,本来的思路就是获取到Keycode之后基于对应的速度,但是由于限制有限,一旦按下左右那么小恐龙就会获得一个持续的速度,解决方法是每一次按键后速度都先设置为0。然后就是通过判断是否正在跳跃,限制小恐龙只可以再地面上才可以跳跃。最后是冲刺效果,这一个首先设置一个cd,然后cd好了之后根据是否按下Space键再根据左右之前的输入,进行两格的位移。为了搞一下那种“我刚刚冲刺了”的效果,添加了几个影子,往冲刺的方向不断递增。

这就是小恐龙的基本设计了。

上面是小恐龙和影子的对象,其实小恐龙和上面的翼龙是有一个两帧的动画的,但是我不会录视频和上传gif那就这样了。

以下为小恐龙的基本代码(未添加碰撞),我想等到游戏完善之后再添加,给敌人加上enemy标签,这应该不是什么难事。 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Dino : MonoBehaviour
{

    [Header("Set in Inspector")]
    public float speed = 5f;
    public Vector3 vel = Vector3.zero;
    public float FastMoveTime = 2f;//设定一个冲刺功能
    public float LastFMTime;
    public GameObject shadow;//影子对象
    public GameObject smoke;//烟雾对象
    [Header("Set Dynamically")]
    public int dirHeld = -1;//这是跟方向有关的标志
    private Rigidbody rid;
    private Vector3[] direction = new Vector3[]{
        Vector3.right,Vector3.up,Vector3.left,Vector3.down
        };
    private KeyCode[] keys = new KeyCode[] {
        KeyCode.D,KeyCode.W,KeyCode.A,KeyCode.S
    };
    // Start is called before the first frame update
    void Start()
    {
        //初始化刚体
        FastMoveTime = 1f;
        rid = GetComponent<Rigidbody>();
        LastFMTime = Time.time;
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 pos =gameObject.transform.position;
        if (dirHeld==0||dirHeld==2)
        {
            vel = Vector3.down;
            rid.velocity = vel;
        }//防止左右移动出现一直移动问题
        if (pos.y <= 4f)//当低于地面范围时
        {
            pos.y = 4f;
            gameObject.transform.position = pos;
        }//用于校准
        if (pos.x <= 17.5f)
        {
            pos.x = 18f;
            gameObject.transform.position = pos;
            return;
        }
        if (pos.x >= 32.5f)
        {
            pos.x = 32f;
            gameObject.transform.position = pos;
            return;
        }//分别是三个边框校准
            dirHeld = -1;
            for(int i = 0; i < 4; i++)
            {
                if (Input.GetKey(keys[i]))
                {
                    dirHeld = i;
                }
            }
        vel = Vector3.zero;
        if (dirHeld > -1)
        {
            if (dirHeld == 1 && pos.y > 4f)
            {
                return;
            }//只可以再地面上跳跃
                vel = direction[dirHeld];
                rid.velocity = vel * speed;
        }
        if (Time.time - LastFMTime >= FastMoveTime)//可以冲刺了
        {
            //重设时间
            if (Input.GetKey(KeyCode.Space) && (dirHeld == 0 || dirHeld == 2))//如果按下了空格
            {
                LastFMTime = Time.time;
                int facingNum = 0;
                if (dirHeld == 0)//往右边
                {
                    facingNum = 1;
                }
                else if (dirHeld == 2)//往左边
                {
                    facingNum = -1;
                }
                Vector3 tem = gameObject.transform.position;
                tem.x += facingNum*2f;
                for (int i = 0; i < 5; i++)
                {
                    gameObject.transform.position = tem;
                    GameObject sm = Instantiate(shadow);
                    tem.x += -(facingNum*(float)i*0.08f);
                    sm.transform.position = tem;
                }
            }
        }
    }
}
 

 

 敌人生成器:

可以看到,在上面的仙人掌和翼龙对象,并没有对应的实例化生成代码。因为我在主摄像机里面添加了一个敌人生成的脚本,这个脚本基本思路就是按着时间间隔生成敌人,随机生成的,有可能是仙人掌也可能是翼龙也可能是后面添加的一些东西,下面的代码里是添加了一些东西之后的,但是这篇文章只介绍刚开始的。除了这一个,还设计一个波次的逻辑,每生成20个敌人为一波,然后没过一波就减少生成间隔直到最大值,同时后面设计为每隔几波就出一个boss,敌人对象放在GameObject的一个速度里,然后随机列入一个大小为十的数组,这样可以增加随机性。

对于其生成就差不多这样:

下面是代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CactusSummoner : MonoBehaviour
{
    [Header("Set in Inspector")]
    public GameObject[] cactus;//仙人掌的保留数组
    public GameObject[] Emeny;//敌人生成的数组
    public float timeSum;//时间间隔
    public float timeNow;
    public float timeSLimit = 1f;
    public int numOfSummon;
    public int wave;
    public int sizeOfEmeny;//需要在引擎处初始化
    public GameObject[] Boss;
    private bool isBoss;
    // Start is called before the first frame update
    void Start()
    {
        timeNow = Time.time;//记录目前时间
        timeSum = 1.5f;
        numOfSummon = 0;
        wave = 1;
        sizeOfEmeny = 6;
        isBoss = false;
    }

    // Update is called once per frame
    void Update()
    {
        if (wave % 5 == 0)
        {
            if (isBoss == false)//场上不存在boss
            {
                Instantiate(Boss[0]);//此处为生成boss
                isBoss = true;//使得boss为真

            }
            GameObject bs = GameObject.Find("ks1(Clone)");
            if (bs == null)
            {//boss消失
                isBoss = false;
                numOfSummon = 0;
                wave++;
            }
        }
        else
        {
            if (numOfSummon >= 20)//一波为20
            {
                for (int i = 0; i < 10; i++)
                {
                    int ge = Random.Range(0, sizeOfEmeny);
                    cactus[i] = Emeny[ge];//在敌人数组里面抽取
                }
                numOfSummon = 0;
                if (timeSum <= timeSLimit)
                {
                    timeSum = timeSLimit;
                }
                else
                {
                    timeSum -= 0.2f;
                }
                wave++;
            }
            Vector3 SumPos = new Vector3(34, 3.8f, 0);//记录生成坐标
            if (Time.time - timeNow >= timeSum)//时间间隔足够
            {
                timeNow = Time.time;
                int ranNum = Random.Range(0, 10);//随机抽取仙人掌
                Instantiate(cactus[ranNum]);//生成仙人掌
                numOfSummon += 1;//增加一次计数
            }
        }
    }
}
 

 上面那个跟boss有关的代码还是测试代码,可以无视,后面会将“ks1”改为检测boss的tag的方式。这就是游戏的基本设计了。

基本效果图:

结语

这一个基础设计大概就是这样,本人也是正在unity的入门阶段,代码写得很乱请多多谅解,这个文章主要是记录一下练习。谢谢大家,我还会继续增加一些新内容。

  • 34
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值