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,可玩性更强一些)

       

     

     

  • 相关阅读:
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
  • 原文地址:https://www.cnblogs.com/FudgeBear/p/8029275.html
Copyright © 2011-2022 走看看