技术类技能学习就是需要多学习实例,多总结。今天又学习了一个见缝插针案例,特记录总结。
一.案例说明
本案例是siki学院的免费课程,可以自行搜索。本案例是2D项目案例。
二.效果图
游戏初始状态
游戏运行中
游戏结束
三.脚本说明
public class RotateSelf : MonoBehaviour { //旋转速度 public float rotateSpeed; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { //旋转 transform.Rotate(new Vector3(0, 0, rotateSpeed * Time.deltaTime)); } }
首先是大黑圈会自动旋转,在其上挂载自动旋转脚本,这个脚本很简单,开放了旋转速度参数,在Update方法中旋转自身即可。
public class GameManager : MonoBehaviour { //针的准备位置,需要使用空物体记录这个位置 public Transform startPoint; //同样使用空物体记录针的生成位置,在游戏界面外部生成针,再使针移动到准备位置 public Transform initiationPoint; //Pin是针上面挂载的脚本,上面有startFly方法,使实例化出来的针从实例位置向准备发射位置移动 private Pin currentPin; //针的prefab public GameObject pin; //记录游戏是否结束的布尔值,游戏中两个针头发生碰撞游戏就会结束,这个布尔值是为了避免多个针实例重复调用游戏结束方法 private bool isGameOver = false; //记录游戏分数(插上圆圈的针个数) private int score = 0; //实时显示分数 public Text text; //主摄像机,在游戏结束时需要将摄像机镜头拉近,因此需要获取主摄像机上的camera组件,调整size属性值 private Camera mainCamera; //游戏结束时需要将背景色渐变,使用线性插值Color.Lerp进行渐变,这里定义的时插值的第三个参数,初始值0.9变化会非常快 public float colorChangeSpeed = 0.9f; // Start is called before the first frame update void Start() { //首先在屏幕外生成一个针并记录下来,针会自动向准备位置移动 currentPin = Instantiate(pin, initiationPoint.position, pin.transform.rotation).GetComponent<Pin>(); //获取摄像机 mainCamera = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>(); } // Update is called once per frame void Update() { //如果游戏已经结束,不再更新 if (isGameOver) return; //实时显示分数 text.text = score.ToString(); //当按下鼠标左键时 if (Input.GetMouseButtonDown(0)) { //按下鼠标左键后调用startFly方法,针开始从准备位置向黑球移动 currentPin.startFly(); //再次实例化一个针,并自动移动到准备位置 currentPin = Instantiate(pin, initiationPoint.position, pin.transform.rotation).GetComponent<Pin>(); } } //游戏结束方法 public void gameOver() { //游戏已经结束就不再调用此方法 if (isGameOver) return; else { //找到圆圈物体,禁用自动旋转组件,停止旋转 GameObject.Find("Circle").GetComponent<RotateSelf>().enabled = false; //开启结束游戏的协程 StartCoroutine(GameOverAnimation()); } //记录下游戏已经结束 isGameOver = true; } //加分,这个方法由针调用,当针到达指定位置并且针头没有和其他针头发生碰撞,调用此方法 public void scoreCount() { score++; } //结束游戏的协程 IEnumerator GameOverAnimation() { while (true) { //改变渲染的背景色 mainCamera.backgroundColor = Color.Lerp(mainCamera.backgroundColor, Color.red, colorChangeSpeed * Time.deltaTime); //改变摄像机正交视野大小 mainCamera.orthographicSize = Mathf.Lerp(mainCamera.orthographicSize, 4f, colorChangeSpeed * Time.deltaTime); //当视野改变和背景色改变完成后结束循环 if(Mathf.Abs(mainCamera.orthographicSize - 4f) < 0.01f) { break; } yield return 0; } //暂停一秒 yield return new WaitForSeconds(1); //重新加载场景 SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex); } }
这段脚本用于管理游戏进程,主要包括计分、发射针和结束游戏等操作。脚本和针上面的控制针运动的脚本耦合性很高,两者相互调用较多,还有改善空间。
public class Pin : MonoBehaviour { //记录针运动的速度 public float speed = 5; //记录针是否已经发射并向目标位置运动,初始为false,下面会做if判断,在else语句中有针运动向准备位置的代码,即针实例化出来后立刻从初始化位置运动往准备位置 private bool isFly = false; //记录针是否到达准备位置 private bool isReach = false; //游戏中间的圆圈,针发射后需要到达的位置 private Transform circle; //针的目标位置,即发射后需要到达的位置 private Vector3 targetPosition; //针的起始位置 private Transform startPoint; // Start is called before the first frame update void Start() { //初始化 startPoint = GameObject.Find("StartPoint").transform; circle = GameObject.Find("Circle").transform; //计算针发射后需要到达的位置,在圆圈下方1.36处 targetPosition = circle.position; targetPosition.y -= 1.36f; } // Update is called once per frame void Update() { //如果针在飞行,初始化出来的针这个值为false if (isFly) { //如果结束飞行说明针到达了准备位置,针就可以发射,在游戏管理脚本中按下鼠标左键后会将isFly的值设置为true,接下来针就会往发射目标位置飞行 transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime); //如果飞行到达目标位置 if (Vector3.Distance(transform.position, targetPosition) < 0.05) { //将真的位置设置为发射终点位置(最终针的到达位置和发射终点位置有微小的偏差) transform.position = targetPosition; //将针设置为圆圈的子物体,针将跟着圆圈一起旋转 transform.parent = circle; //调用游戏管理的计分方法,记录分数 GameObject.FindGameObjectWithTag("GameController").GetComponent<GameManager>().scoreCount(); //设置针的状态为已经到达并没有在飞行 isReach = true; isFly = false; } } //如果针没有在飞行,这里的飞行是指发射后向发射终点位置的飞行,值为false则针并未开始发射 else { //判断针是否到达准备位置 if (isReach) { } //针未到达准备位置则向准备位置运动 else { //向准备位置运动 transform.position = Vector3.MoveTowards(transform.position, startPoint.position, speed * Time.deltaTime); //如果到达准备位置,将是否到达准备位置的布尔值设置为true if(Vector3.Distance(transform.position,startPoint.position) < 0.05) { isReach = true; } } } } //供游戏管理组件调用的方法,按下鼠标左键后会调用此方法,将是否飞行的布尔值设置为true,代表将向发射终点飞行 public void startFly() { isFly = true; } //判断针头是否发生碰撞,如果碰撞则游戏结束 private void OnTriggerEnter2D(Collider2D collision) { //针上设置了PinHead标签,通过标签判断碰撞到的位置是否是针头,如果是则将结束游戏 if(collision.tag == "PinHead") { //调用游戏管理组件的游戏结束方法结束游戏 GameObject.Find("GameManager").GetComponent<GameManager>().gameOver(); } } }
这段脚本用于管理生成的针prefab的运动和碰撞等。这段脚本逻辑复杂了一些,主要设置了两个布尔值,一个isFly代表针是否已经发射,一个isReach代表是否已经到达准备发射位置。刚生成的针的isFly初始值为false,isReach的值也为false,代表没有开始发射并且没有到达准备发射位置,在Update中做两次判断,双false的话针向准备发射位置运动。当按下鼠标左键时,不论针是否到达准备发射位置,isFly值都设置为true,代表针开始发射的飞行,飞行的终点位置为发射终点位置。因此代码Update方法中先判断isFly值看针是否已经发射,已经发射就使针向发射终点运动,如果未发射再判断针是否到达准备发射位置,未到达准备发射位置向准备发射位置运动。在发射到达发射终点后,再将isFly值设置为false,代表不用再飞行,同时设置isReach为true,不用再向发射准备位置运动。
原文:https://www.cnblogs.com/movin2333/p/14050933.html