zoukankan      html  css  js  c++  java
  • Siki_Unity_1-5_见缝插针

    1-5 见缝插针

    任务1:资源下载

    任务2:案例演示

    任务3:创建工程和场景

    Project Name:StickPin

    import素材,为两张png图

    创建各个分类文件夹Scenes/ Prefabs/ Scripts

    修改Main Camera的Clear Flags为Solid Color
      Background颜色到小清新的卡其色

    任务4:创建小球和分数显示

    2D游戏 -- 勾选Scene上的2D标识

    创建小球:

    将Image里的Circle拖入Hierarchy面板
    调整位置到中偏上,scale为0.7
    颜色为黑

    计分板:

    UI->Text 用于显示分数
    删除自动创建的EventSystem,因为不需要用到事件
    Text居中(reset Rect Transform即可)
    文字水平居中竖直居中,字体白色,大小变大

    Canvas的渲染模式Render Mode改为World Space
      这样就可以将UI缩小到和游戏开发环境一样,便于设计大小
    Canvas的Event Camera选择为Main Camera;共用同一个Camera即可
    Canvas的大小设置为100*100(因为Text的是100*100)
      但是Canvas和Circle比较还是很大,-> scale 0.01 (之前是1pixel=1m,现在是100pixels=1m)
      将Canvas的位置放在Circle圆心(Position值相同即可)

    运行游戏,手动改变分数,发现100分时候只显示10分
      勾选Text的best fit,自适应大小

    任务5:控制小球旋转

    围绕圆心顺时针匀速旋转 -- 围绕z轴旋转

    transform.Rotate(new Vector3(0, 0, -1) * speed * Time.deltaTime);

    speed 设置为90; // 每秒钟旋转90°

    任务6:针的Prefab预制体

    创建针 Image->Pin
    颜色为黑,大小放大到接近Circle的直径,方向从下往上

    创建针头 Image->Circle
    成为Pin的子物体
    颜色为黑,改变大小,放在针的下端

    给针头Circle添加碰撞器Circle Collider 2D

    做成Prefab

    任务7:开发GameManager生成针(实例化)

    创建空物体StartPoint,放置于针准备发射的位置

    创建空物体SpawnPoint,放置于针实例化的位置(在屏幕外部)

    创建空物体GameManager,用于管理针的实例化
      创建GameManager.cs
      控制针的发射:

    得到两个点的位置:

    private Transform startPoint;
    private Transform spawnPoint;

    startPoint = GameObject.Find("StartPoint").transform;
    spawnPoint = GameObject.Find("SpawnPoint").transform;

    得到Prefab:

    public GameObject pinPrefab; // 拖拽赋值

    实例化针:

    GameObject.Instantiate( pinPrefab, spawnPoint.position, pinPrefab.transform.rotation);

    public class GameManager : MonoBehaviour {
    
        public GameObject pinPrefab;private Transform spawnPoint;
    
        // Use this for initialization
        void Start() {
            spawnPoint = GameObject.Find("SpawnPoint").transform;
            SpawnPin();
        }
    
        private void SpawnPin() {
            GameObject.Instantiate(pinPrefab, spawnPoint.position, pinPrefab.transform.rotation);
        }
    }

    任务8&9&10:控制针移动到准备位置 & 针的插入 & 判断针到达表面

    给Pin添加脚本PinMovement.cs来控制针的初始运动

    Pin的运动分为两段:1. 准备阶段;2. 插针阶段
      用bool hasReachedStartPoint = false; 来判断是否到达StartPoint
      用bool isInserting = false; 来判断是否在插针阶段

    1. 准备阶段

    private Transform startPoint; // 获取该Transform与上任务相同

    逻辑思路:
      if(isInserting == false) {
        if(hasReachedStartPoint == false) {  // 准备阶段
          transform.position = Vector3.MoveTowards
            (transform.position, startPoint.position, speed * Time.deltaTime);
          // MoveTowards(起点,终点,速度) 返回一个Vector3的位置信息
        }
      }

    2. 判断是否到达StartPoint

    Vector3.Distance(transform.position, startPoint.position) < 0.05f;
    // Vector3.Distance(两点坐标),返回的是两点之间的距离

    如果到达,hasReachedStartPoint = true;

    3. 插针阶段

    检测鼠标左键的按下
      Input.GetMouseButtonDown(0);

    发射针:
      private PinMovement currentPin;
      实例化的时候currentPin得到Pin的实体(赋值给currentPin即可)
        currentPin = GameObject.Instantiate(..).GetComponent<PinMovement>();
      currentPin.StartInsert();

      StartInsert() {
        isInserting = true;
        hasReachedStartPoint = true;
      }

    朝着Circle运动:
      得到Circle的位置 private Transform... = GameObject.Find(...);
      transform.position = Vector3.MoveTowards(...);

    运行,点击鼠标,Pin insert了,但是在一个奇怪的位置停住了

    发现针头的名字也是Circle,怀疑得到的是这个Circle的坐标,将其改为PinHead

    还是不对,将脚本中Circle设置为public,运行游戏,双击Unity里的public Circle,发现这个Circle的属性和PinHead的属性相同,但是不知道怎么改。。。故使用FindGameObjectWithTag("Circle");实现

    成功运行了。但是将代码改回Find("Circle")后发现,也成功运行了。不知道为何。有点懵逼。

    4. 判断是否到达目标位置(是否插入Circle)

    同样用Vector3.Distance()判断

    在Unity中手动计算针在到达小球表面时候针和小球原点的距离

    private Vector3 targetPosition = circleTransform.position - Vector3(0, diff,0);
    if(Vector3.Distance(transform.position, targetPosition) < 0.05f) {
      transform.position = targetPosition; // 最后位置的到达
      transform.parent = circle; // 让针随着小球转动
      isInserting = false;
    }

    void Update () {
        if (isInserting == false) {
            if (hasReachedStartPoint == false) {  // 准备阶段
                transform.position = Vector3.MoveTowards(transform.position, startPoint.position, speed * Time.deltaTime);
                // MoveTowards(起点,终点,速度) 返回一个Vector3的位置信息
                if (Vector3.Distance(startPoint.position, transform.position) < 0.05f) {
                    transform.position = startPoint.position;
                    hasReachedStartPoint = true; // 到达以后transform就不变了,除非isInserting == true
                }
            }
        } else {
            // 插针阶段
            transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
            if (Vector3.Distance(transform.position, targetPosition) < 0.05f) {
                transform.position = targetPosition; // 最后位置的到达
                transform.parent = circleTransform; // 让针随着小球转动
                isInserting = false; // 到达小球表面,isInserting == false; hasReached == true; 不会执行代码
            }
        }
    }
    
    public void StartInsert() {
        isInserting = true;
        hasReachedStartPoint = true;
    }

    任务10:针的连环发射

    在点击鼠标左键的时候,StartInsert();之后进行SpawnPin();即可

    针的运动速度有点慢,修改为15

    void Update() {  // GameManager.csif (Input.GetMouseButtonDown(0)) {                  
            currentPin.StartInsert();
            SpawnPin();        
        }
    }

    任务11:针头的碰撞和游戏结束

    触发检测

    针头有了Collider,但是没有刚体组件
      添加Rigidbody2D,重力Gravity Scale设置为0
      并使用Trigger模式(不想让碰撞影响运动)

    如果两个针头碰撞,游戏结束

    给PinHead添加Tag "PinHead",方便Trigger的检测

    PinHeadCollision.cs
      void OnTriggerEnter2D(Collider2D collier) {
        if(collider.tag == "PinHead") {
          // 调用GameManager的方法
          GameObject.Find("GameManager").
            GetComponent<GameManager>().GameOver();
        }
      }

    GameManager.GameOver():

    // 因为每个PinHead上都会有PinHeadCollision的脚本,所以Collision发生的时候会执行多次GameOver(),而实际上执行一次即可

    private bool isGameOver = false;

    public void GameOver() {
      if(isGameOver) return;
      // 游戏结束后小球不旋转了
      GameObject.Find("Circle").GetComponent<RotateSelf>().enabled = false;
      isGameOver = true;

      }

    在Update()中,游戏结束后就不能控制Pin了

    Update() {
      if(isGameOver) return;
      ...
    }

    任务12:控制分数的显示

    private int score = 0;
    public Text scoreText;  // using UnityEngine.UI;

    // 在按下鼠标的时候加分
    scoreText.text = score.ToString();

    void Update() { // GameManager.cs
        if (isGameOver) return;
        if (Input.GetMouseButtonDown(0)) {                  
            currentPin.StartInsert();
            score++;
            scoreText.text = score.ToString();
            SpawnPin();        
        }
    }

    任务13:游戏结束动画的显示

    思路:
      游戏背景颜色改变
      Camera size变小(画面变近)

    GameManager.cs

    IEnumerator GameOverAnimation() {  // using System.Collections;
      while(true) {
        mainCamera.backgroundColor =
          Color.Lerp(mainCamera.backgroundColor, Color.red, speed * Time.deltaTime);
        mainCamera.orthographicSize =
          Mathf.Lerp(mainCamera.orthographicSize, 4, speed * Time.deltaTime);
        if(Mathf.Abs(mainCamera.orthographicSize - 4) < 0.01f)  break;  // 判断是否到达目标值
        yield return 0;
      }
      yield return new WaitForSeconds(0.5f); // 暂停0.5s(因为播放完动画会自动重新开始游戏)
      // using UnityEngine.SceneManagement
      SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);  // 重载游戏
    }

    // Lerp(起始值,目标值,改变速度) -- 渐变

    在GameOver()中加入StartCoroutine(GameOverAnimation());调用;

    (将circle旋转速度改为140,可玩性更强一些)

       

     

     

  • 相关阅读:
    打印日志宏定义
    数据库读写操作
    SQL语句组成
    MySQL数据库的使用
    ubuntu下解决MySQL 1045 error
    css样式优先级
    redis
    dubbo
    maven
    Mybatis笔记
  • 原文地址:https://www.cnblogs.com/FudgeBear/p/8029275.html
Copyright © 2011-2022 走看看