Unity3D入门--见缝插针

是跟着Siki上的网站进行的,整理思路,原网址如下:

http://www.sikiedu.com/course/78 点击打开链接

打开课程的素材,只有两张图,即圆圈和针棒:


可以把Image文件夹整个拖到Project-Assets下,除此之外在这里再create几个folder:

Scene:存放场景,这个游戏就只有main场景一个

Prefabs:存放“预设”,Unity3D的工程建设中,Prefabs(预设)最非常用的一种资源类型,一种可被重复使用的游戏对象。 特点1:它可以被置入多个场景中,也可以在一个场景中多次置入。 特点2:当你在一个场景中增加一个Prefabs,你就实例化了一个Prefabs。这里将要存入组合好的带圆圈的针

Scripts:存放C#脚本,处理游戏中组件的属性、操作等

(scripts下面添加的脚本)

大致思路:

设置一个mainCamara;拖入圆,调节大小,调为黑色,作为“被插针”的圆;添加Canvas下面的Text也就是UI->Text,记录分数;添加两个位置,起始位置和生成位置,分别表示屏幕上点击之前针的位置和屏幕外游戏中实例化针的位置;然后添加GameManager处理整个游戏的逻辑

    

对Circle的处理

调节成黑色;居中(x坐标为0);调节合适的大小,添加旋转的运动:也就是在Scripts下新建C#脚本RotateSelf,并拖拽到Circle的属性中;打开后在update()函数中添加旋转的代码:

void Update () {
        transform.Rotate(new Vector3(0, 0, -speed*Time.deltaTime));
	}

这里的update函数在打开之初就有,每帧执行一次;

transform是unity组件,每个游戏对象都有组件,transition下常见的属性包括position(组件位置)、parent(组件父级)等用来描述物体的各种属性

transform.Rotate()为旋转物体的函数,参数为一个vector3也就是三维向量x,y,z这里围绕Z轴旋转;而Time类包下面的一个重要重要的类变量deltaTime,它表示距上一次调用Update或FixedUpdate所用的时间。

对Text的处理:

需要调节好大小,这里的单位与圆的单位不一致,要比圆的单位大100倍,所以需要缩小,将其canvas一起缩小,最后拖拽到圆的中心,修改颜色,默认字符可以为0,居中显示


对针的处理:

这里处理完后整体拖入到Prefabs中做预设,就得在这一栏删掉了,窦泽屏幕上凭空多一个

可以先添加针的图片,再加入一个圆,但是把圆放在Pin的下面,这样整个Pin可以作为一个整体。调节针头的大小和颜色,然后移动的合适的位置做针头;针同样要调节到合适的大小和长度,然后可以把整个Pin拖到prefabs中作为一个预设,后面不断实例化和使其运动就可以了。其中这个circle针头的Add component中要添加Circle colider2D 和Rigidbody2D两个组件(搜索即可),是为了之后做碰撞检测。其中Circle colider2D中要勾选IsTrigger使得碰撞后还能继续做处理;Rigidbody2D里gravity要设为0,否则针头就会离针而去啦!


当然还得添加PinHead脚本(scripts文件夹下),才能具体的处理针头碰撞。另外在针头添加Tag PinHead以区分大圆做碰撞处理,需要Add tag之后再次选择,然后apply应用

在PinHead脚本中,添加下面的函数:

private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.tag=="PinHead")
        GameObject.Find("GameManager").GetComponent<GameManager>().GameOver();

    }

 Gameobject是一个类型,所有的游戏物件都是这个类型的对象,是由component组成的;GameObject.find()通过名字来查找场景中的游戏对象,找到里面的GameManager组件下面的GameOver()方法;其中GameManager也是在Scripts下面添加的脚本文件,掌控整个游戏逻辑,里面会有涉及到游戏结束的函数,这里针头碰撞时要调用,可想而知,GameOver()是public的


整个针也有脚本Pin,需要控制针的运动;使其插上后一起跟圆旋转,Pin中的变量和函数,核心就两个函数

public float speed = 20;//针移动的速度
    private bool isFly = false;//针是否在从起始点到圆的过程中
    private bool isReach = false;//针是否实例化后到达了屏幕起始位置
    private Transform startPoint;//屏幕上点击之前针的位置
    private Transform circle;//获取组件大圆
    private Vector3 targetCirclePosition;//由于不是插到圆心位置,需要另求目标位置
	// Use this for initialization
	void Start () {
        startPoint = GameObject.Find("StartPosition").transform;
        circle = GameObject.Find("Circle").transform;
        targetCirclePosition = circle.position;
        targetCirclePosition.y -= 1.55f;//这里是理想碰撞下圆的y坐标和针的y坐标的差,也就是目标的插入位置

    }
    /// <summary>
    /// 从起始点到插入,具体的移动见Update
    /// </summary>
	public void StartFly()
    {
        isFly = true;
        isReach = true;
    }
	// Update is called once per frame
	void Update () {
		if(isFly == false)
        {
            if(isReach==false)
            {//这一段是从屏幕外的生成位置,到屏幕上的开始位置,参数:当前位置,目标位置,速度
                transform.position= Vector3.MoveTowards(transform.position, startPoint.position, speed * Time.deltaTime);
                if (Vector3.Distance(transform.position, startPoint.position) < 0.05f)//计算距离
                    isReach = true;//已到达起始位置
            }
        }
        //从屏幕起始位置移动到圆
        else
        {
            transform.position = Vector3.MoveTowards(transform.position, targetCirclePosition, speed * Time.deltaTime);
            if(Vector3.Distance(transform.position,targetCirclePosition)<0.05f)
            {
                transform.position = targetCirclePosition;
                transform.parent = circle;//这样就会和圆一起rotate
                isFly = false;
            }
        }
	}



GameManager

这里要拖入GameManager脚本,这个脚本就是和其他脚本的图标不一样QAQ

这个脚本主要是实例化针;响应鼠标点击事件;记录修改游戏得分;处理碰撞后游戏结束事件

其中实例化针:

//生成针:在spawnpoint位置实例化
    void SpawnPin()
    {
        currentPin= GameObject.Instantiate(pinPrefab, spawnPoint.position, pinPrefab.transform.rotation).GetComponent<Pin>();
    }

其中pinPrefab是public 的GameObject类型的对象,可以拖拽赋值为之前保存的预设;

开始函数,初始化获取参数,生成针:

 void Start()
    {
        //获取具体位置
        startPoint = GameObject.Find("StartPosition").transform;
        spawnPoint = GameObject.Find("SpawnPoint").transform;
        mainCamera = Camera.main;//主相机
        SpawnPin();
        animationSpeed = 3;//不在这里初始化可能会被初始化为0
    }

Update随时响应鼠标点击事件:

// Update is called once per frame
    void Update()
    {
        if (isGameOver) return;//游戏结束不响应鼠标点击了
        //鼠标点击事件
        if(Input.GetMouseButtonDown(0))
        {
            currentPin.StartFly();//从起始位置向上
            score++;//更新分数
            scoreText.text = score.ToString();
            SpawnPin();//重新实例化针
        }
    }

GameOver处理函数:

public void GameOver()
    {
        if (isGameOver) return;
        
        GameObject.Find("Circle").GetComponent<RotateSelf>().enabled = false;//停止旋转
        StartCoroutine(GameOverAnimation());//游戏结束动画,自己另写一个协程


        isGameOver = true;
    }

GameOver动画,将主相机的背景色渐变,大小渐变:

IEnumerator GameOverAnimation()
    {
        while(true)
        {
            
            //lerp()进行差值计算。背景色和大小都线性变化
            mainCamera.backgroundColor = Color.Lerp(mainCamera.backgroundColor, Color.red, animationSpeed* Time.deltaTime);
            mainCamera.orthographicSize = Mathf.Lerp(mainCamera.orthographicSize, 4, animationSpeed * Time.deltaTime);
            Debug.Log(animationSpeed);
            if (Mathf.Abs(mainCamera.orthographicSize - 4) < 0.01f) break;
            yield return 0;//每次暂停一帧
        }
        yield return new WaitForSeconds(0.2f);//动画暂停0.5秒
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);//重新加载场景
    }
unity协程是一个能暂停执行,暂停后立即返回,直到中断指令完成后继续执行的函数。

它类似一个子线程单独出来处理一些问题,性能开销较小,但是他在一个MonoBehaviour提供的主线程里只能有一个处于运行状态的协程。

效果如图:


这样就好啦

正常的游戏效果:



猜你喜欢

转载自blog.csdn.net/beforeeasy/article/details/79828474