思路
游戏整体思路
这是一个简单的游戏,玩家通过点击鼠标让钉子(Pin
)飞向目标(Circle
)。如果钉子的头部(PinHead
)与目标发生碰撞,则游戏结束。游戏结束时,会有一个动画效果,然后重新加载当前场景。
代码思路
1. 游戏管理器(GameManager.cs
)
- 功能:作为游戏的核心管理器,负责游戏的整体逻辑,包括钉子的生成、计分、游戏结束处理等。
- 关键逻辑:
- 初始化:在
Start()
方法中,查找起始位置和生成位置,获取主相机引用,并生成第一个钉子。 - 玩家操作:在
Update()
方法中,检测鼠标点击事件。每次点击时,增加得分,让当前钉子开始飞行,并生成新的钉子。 - 游戏结束:当钉子头部与目标碰撞时,调用
GameOver()
方法。停止目标的旋转,并启动游戏结束动画。 - 游戏结束动画:通过
GameOverAnimation()
协程,逐渐改变相机的背景颜色和正交大小,完成后重新加载当前场景。
2. 钉子控制(Pin.cs
)
- 初始化:在
- 功能:控制钉子的行为,包括移动到起始位置、飞行到目标位置等。
- 关键逻辑:
- 初始化:在
Start()
方法中,设置钉子的起始位置和目标位置。 - 移动逻辑:在
Update()
方法中,根据isFly
和isReach
的状态,控制钉子的移动。- 如果
isFly
为false
,钉子移动到起始位置。 - 如果
isFly
为true
,钉子移动到目标位置。
- 如果
- 开始飞行:通过
StartFly()
方法,让钉子开始飞行。
3. 钉子头部碰撞检测(PinHead.cs
)
- 初始化:在
- 功能:检测钉子头部是否与目标发生碰撞,触发游戏结束。
- 关键逻辑:
- 碰撞检测:在
OnTriggerEnter2D()
方法中,检测带有 “PinHead” 标签的碰撞。如果检测到碰撞,调用GameManager
的GameOver()
方法。
4. 自旋转组件(RotateSelf.cs
)
- 碰撞检测:在
- 功能:控制目标(
Circle
)的自旋转行为。 - 关键逻辑:
- 旋转逻辑:在
Update()
方法中,每帧更新时,绕 Z 轴旋转目标对象。
- 旋转逻辑:在
代码协同工作
- 游戏开始:
GameManager
在Start()
方法中初始化游戏,生成第一个钉子。Pin
在Start()
方法中初始化钉子的位置和目标位置。
- 玩家操作:
- 玩家点击鼠标左键时,
GameManager
的Update()
方法检测到点击事件。 - 增加得分,调用当前钉子的
StartFly()
方法,让钉子开始飞行。 GameManager
生成新的钉子。
- 玩家点击鼠标左键时,
- 钉子飞行:
Pin
的Update()
方法控制钉子的移动。- 如果钉子头部与目标发生碰撞,
PinHead
的OnTriggerEnter2D()
方法检测到碰撞,调用GameManager
的GameOver()
方法。
- 游戏结束:
GameManager
的GameOver()
方法停止目标的旋转,并启动游戏结束动画。GameOverAnimation()
协程逐渐改变相机的背景颜色和正交大小。- 动画完成后,重新加载当前场景,游戏重新开始。
总结
GameManager
:作为游戏的核心管理器,负责整体逻辑。Pin
:控制钉子的移动和飞行行为。PinHead
:检测钉子头部与目标的碰撞,触发游戏结束。RotateSelf
:实现目标的自旋转效果。
通过这些脚本的协同工作,游戏实现了玩家操作、得分、碰撞检测和游戏结束等核心功能。
代码
GameManager
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using TMPro;
using System.Collections;
public class GameManager : MonoBehaviour
{
// 变量定义
private Transform startPosition; // 钉子的起始位置
private Transform spawnPosition; // 钉子的生成位置
private Pin currentPin; // 当前活动的钉子
private bool isGameOver = false; // 标记游戏是否结束
private int score = 0; // 玩家的得分
private Camera mainCamera; // 主相机的引用
public TextMeshProUGUI scoreText; // 显示得分的 UI 文本
public GameObject pinPrefab; // 钉子的预制体
public float speed = 3; // 动画过渡的速度
// Start 是在 MonoBehaviour 创建后首次调用
void Start()
{
// 查找场景中的起始位置和生成位置
startPosition = GameObject.Find("StartPosition").transform;
spawnPosition = GameObject.Find("SpawnPosition").transform;
// 获取主相机的引用
mainCamera = Camera.main;
// 生成第一个钉子
SpawnPin();
}
// Update 每帧调用一次
void Update()
{
// 如果游戏已经结束,直接返回
if (isGameOver) return;
// 检测鼠标左键点击
if (Input.GetMouseButtonDown(0))
{
// 增加得分
score++;
// 更新得分显示
scoreText.text = score.ToString();
// 让当前钉子开始飞行
currentPin.StartFly();
// 生成新的钉子
SpawnPin();
}
}
// 生成钉子的方法
void SpawnPin()
{
// 实例化钉子预制体
currentPin = GameObject.Instantiate(pinPrefab, spawnPosition.position, pinPrefab.transform.rotation).GetComponent<Pin>();
}
// 游戏结束的方法
public void GameOver()
{
// 如果游戏已经结束,直接返回
if (isGameOver) return;
// 停止 "Circle" 对象的旋转
GameObject.Find("Circle").GetComponent<RotateSelf>().enabled = false;
// 启动游戏结束动画
StartCoroutine(GameOverAnimation());
// 标记游戏结束
isGameOver = true;
}
// 游戏结束动画的协程
IEnumerator GameOverAnimation()
{
// 逐渐改变相机的背景颜色和正交大小
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 null;
}
// 等待 0.2 秒
yield return new WaitForSeconds(0.2f);
// 重新加载当前场景
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
Pin
using UnityEngine;
public class Pin : MonoBehaviour
{
public float speed = 5; // 钉子的移动速度
private bool isFly = false; // 标记钉子是否正在飞行
private bool isReach = false; // 标记钉子是否已到达起始位置
private Transform startPosition; // 钉子的起始位置
private Vector3 targetCirclePos; // 钉子的目标位置
private Transform circle; // 目标圆圈的引用
// Start 是在 MonoBehaviour 创建后首次调用
void Start()
{
// 查找起始位置和目标圆圈
startPosition = GameObject.Find("StartPosition").transform;
circle = GameObject.Find("Circle").transform;
// 设置目标位置
targetCirclePos = circle.position;
targetCirclePos.y -= 1.54f;
}
// Update 每帧调用一次
void Update()
{
// 如果钉子没有开始飞行
if (isFly == false)
{
// 如果钉子没有到达起始位置
if (isReach == false)
{
// 移动钉子到起始位置
transform.position = Vector3.MoveTowards(transform.position, startPosition.position, speed * Time.deltaTime);
// 检查是否到达起始位置
if (Vector3.Distance(transform.position, startPosition.position) < 0.05f)
{
isReach = true;
}
}
}
else
{
// 移动钉子到目标位置
transform.position = Vector3.MoveTowards(transform.position, targetCirclePos, speed * Time.deltaTime);
// 检查是否到达目标位置
if (Vector3.Distance(transform.position, targetCirclePos) < 0.05f)
{
// 将钉子附加到目标圆圈上
transform.position = targetCirclePos;
transform.parent = circle;
// 标记钉子停止飞行
isFly = false;
}
}
}
// 开始飞行的方法
public void StartFly()
{
isFly = true;
isReach = true;
}
}
PinHead
using UnityEngine;
public class PinHead : MonoBehaviour
{
// 当触发器检测到碰撞时调用
private void OnTriggerEnter2D(Collider2D collision)
{
// 如果碰撞对象的标签是 "PinHead"
if (collision.CompareTag("PinHead"))
{
// 调用 GameManager 的 GameOver 方法
GameObject.Find("GameManager").GetComponent<GameManager>().GameOver();
}
}
}
RotateSelf
using UnityEngine;
public class RotateSelf : MonoBehaviour
{
public float speed = 90; // 旋转速度
// Start 是在 MonoBehaviour 创建后首次调用
void Start()
{
// 无初始化逻辑
}
// Update 每帧调用一次
void Update()
{
// 绕 Z 轴旋转对象
transform.Rotate(new Vector3(0, 0, -speed * Time.deltaTime));
}
}