喜欢看小猪佩奇的朋友都知道一款游戏叫做快乐小鸡,于是作者自己动手实现了一款,有需要的朋友也可以下载apk在安卓上运行或者执行码在电脑上玩,下面是程序的运行视频,以及部分实现的代码
GameManager的代码
cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
private string prefabPath = "Prefabs/ChickenObj";
public int score = 0; // 示例参数
public float moveSpeed = 1f;
public event Action<int> OnButtonClicked;
public event Action startGameEvent;
bool m_isStart = false;
Player m_player;
public Vector3 m_transoffset = new Vector3(0.5f,-1,0);
void Awake()
{
// 如果已经有实例了,说明重复了,销毁自己
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject); // 可选:切场景不销毁
}
private void Start()
{
OnButtonClicked?.Invoke(score);
}
void Update()
{
if(!m_isStart)
{
return;
}
// 鼠标左键按下
if (Input.GetMouseButtonDown(0))
{
// 1. 获取鼠标屏幕坐标
Vector3 screenPos = Input.mousePosition;
// 2. 转成世界坐标
Vector3 worldPos = ScreenToWorld(screenPos);
Debug.Log("screenPos = " + screenPos);
SpawnAtMousePosition(worldPos);
++score;
OnButtonClicked?.Invoke(score);
return;
}
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
SpawnAtMousePosition(Input.GetTouch(0).position);
++score;
OnButtonClicked?.Invoke(score);
return;
}
if (Input.anyKeyDown && !Input.GetKey(KeyCode.Escape) && !Input.GetMouseButtonDown(0))
{
Vector3 randomScreenPos = new Vector3(
UnityEngine.Random.Range(0f, Screen.width - 50),
UnityEngine.Random.Range(0f, Screen.height - 200),
0f);
Vector3 worldPos = ScreenToWorld(randomScreenPos);
SpawnAtMousePosition(worldPos);
++score;
OnButtonClicked?.Invoke(score);
return;
}
if (Input.GetKeyDown(KeyCode.Escape))
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false; // 编辑器里停止运行
#else
Application.Quit(); // 打包后退出程序
#endif
}
}
public void startGame()
{
m_isStart = true;
startGameEvent?.Invoke();
initPlayerChicken();
}
void initPlayerChicken()
{
GameObject prefab = Resources.Load<GameObject>(prefabPath);
Debug.Log("prefabPath = " + prefabPath);
if (prefab == null)
{
Debug.LogError($"找不到 Prefab,路径:Resources/{prefabPath}");
return;
}
Vector3 screenCenter = new Vector3(Screen.width / 2f, Screen.height / 2f,0);
var worldPos = ScreenToWorld(screenCenter);
// 4. 实例化
GameObject playerObj = Instantiate(prefab, worldPos, Quaternion.identity);
m_player = playerObj.GetComponent<Player>();
m_player.initPlayerInfo();
}
void SpawnAtMousePosition(Vector3 worldPos)
{
m_player.setPos(worldPos);
m_player.playJumpAnim();
// 3. 加载 Resources 下的 Prefab
GameObject prefab = Resources.Load<GameObject>(prefabPath);
if (prefab == null)
{
Debug.LogError($"找不到 Prefab,路径:Resources/{prefabPath}");
return;
}
worldPos += m_transoffset;
// 4. 实例化
GameObject chickenObj = Instantiate(prefab, worldPos, Quaternion.identity);
// update player postion
var child = chickenObj.GetComponent<Player>();
child.initChildInfo();
}
// 根据相机类型选择转换方式
Vector3 ScreenToWorld(Vector3 screenPos)
{
Camera cam = Camera.main;
if (cam == null)
{
Debug.LogError("场景里没有 MainCamera 标签的相机");
return Vector3.zero;
}
// 正交相机(2D 常用)
if (cam.orthographic)
{
Vector3 pos = cam.ScreenToWorldPoint(screenPos);
pos.z = 0f; // 2D 场景一般把 z 归零
return pos;
}
// 透视相机(3D 常用)
else
{
// 方法 A:直接取相机前方某个距离的点
float distance = 10f; // 距离相机 10 个单位
Vector3 pos = cam.ScreenToWorldPoint(
new Vector3(screenPos.x, screenPos.y, distance));
return pos;
// 方法 B:如果要精确点到地面/某个平面,用射线检测(见下方说明)
}
}
}
player的代码
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
enum playerStateEnum { EGG0, EGG1, CHICKEN,CHILD_CHICKEN };
public class Player : MonoBehaviour
{
GameObject gameManagerObj;
GameManager gameManeger;
float moveSpeed = 0f;
GameObject m_childChicken;
GameObject m_firstEggObj;
GameObject m_secondEggObj;
GameObject m_curObj;
List<GameObject> allChildObject;
private Animator anim;
public float speed = 1f;
bool m_isStart = false;
private bool m_isPlayer = false;
playerStateEnum _m_state = playerStateEnum.EGG0;
playerStateEnum m_state
{
get { return _m_state; }
set {
_m_state = value;
refreshState();
}
}
private List<string> allAnimName = new List<string>() { "jump", "move", "moveAndSpeak" };
private List<GameObject> allGameObjects = new List<GameObject>();
private void initObject()
{
gameManagerObj = GameObject.Find("GameManager");
m_firstEggObj = transform.Find("egg0").gameObject;
m_secondEggObj = transform.Find("egg1").gameObject;
m_childChicken = transform.Find("chicken_animation").gameObject;
anim = m_childChicken.GetComponent<Animator>();
allChildObject = new List<GameObject>() { m_firstEggObj, m_secondEggObj , m_childChicken };
m_isStart = true;
foreach (GameObject obj in allChildObject)
{
obj.SetActive(false);
}
resetAnimState();
Debug.Log("Start");
}
void Update()
{
}
public void initPlayerInfo()
{
initObject();
m_isPlayer = true;
m_state = playerStateEnum.CHICKEN;
}
void resetAnimState()
{
foreach(var name in allAnimName)
{
anim.SetBool(name, false);
}
}
public void playJumpAnim()
{
resetAnimState();
anim.SetBool("jump",true);
}
public void playMoveAnim()
{
resetAnimState();
anim.SetBool("move", true);
}
public void playmoveAndSpeakAnim()
{
resetAnimState();
anim.SetBool("moveAndSpeak", true);
}
public void playIdleAnim()
{
resetAnimState();
anim.SetBool("idle", true);
}
public void initChildInfo()
{
initObject();
Debug.Log("initChildInfo");
m_isPlayer = false;
m_state = playerStateEnum.EGG0;
StartCoroutine(egg2HatchState());
}
void refreshState()
{
Debug.Log("refreshState");
if (!m_isStart)
{
return;
}
foreach (GameObject obj in allChildObject)
{
obj.SetActive(false);
}
switch (m_state)
{
case playerStateEnum.EGG0:
{
m_firstEggObj.SetActive(true);
m_curObj = m_firstEggObj;
break;
}
case playerStateEnum.EGG1:
{
m_secondEggObj.SetActive(true);
m_curObj = m_secondEggObj;
break;
}
case playerStateEnum.CHICKEN:
{
m_childChicken.SetActive(true);
m_curObj = m_childChicken;
break;
}
case playerStateEnum.CHILD_CHICKEN:
{
m_childChicken.SetActive(true);
m_curObj = m_childChicken;
break;
}
}
}
// 孵化流程
IEnumerator egg2HatchState()
{
yield return new WaitForSeconds(2f);
m_state = playerStateEnum.EGG1;
StartCoroutine(egg2ChickenState());
}
IEnumerator egg2ChickenState()
{
yield return new WaitForSeconds(2f);
m_state = playerStateEnum.CHILD_CHICKEN;
var curPos = m_curObj.transform.position;
Vector3 endPos =new Vector3(-20, curPos.y, curPos.z);
anim.SetBool("idle", false);
playmoveAndSpeakAnim();
StartCoroutine(MoveTo(endPos,speed));
}
IEnumerator MoveTo( Vector3 endPos, float speed)
{
float elapsed = 0f;
while (transform.position.x > endPos.x)
{
var pos = transform.position;
elapsed = Time.deltaTime * speed;
transform.position = new Vector3(pos.x - elapsed, pos.y, pos.z);
yield return null; // 等下一帧
}
transform.position = endPos; // 保证精确到位
Destroy(gameObject);
}
// 根据相机类型选择转换方式
Vector3 ScreenToWorld(Vector3 screenPos)
{
Camera cam = Camera.main;
if (cam == null)
{
Debug.LogError("场景里没有 MainCamera 标签的相机");
return Vector3.zero;
}
// 正交相机(2D 常用)
if (cam.orthographic)
{
Vector3 pos = cam.ScreenToWorldPoint(screenPos);
pos.z = 0f; // 2D 场景一般把 z 归零
return pos;
}
// 透视相机(3D 常用)
else
{
// 方法 A:直接取相机前方某个距离的点
float distance = 10f; // 距离相机 10 个单位
Vector3 pos = cam.ScreenToWorldPoint(
new Vector3(screenPos.x, screenPos.y, distance));
return pos;
// 方法 B:如果要精确点到地面/某个平面,用射线检测(见下方说明)
}
}
public void setPos(Vector3 pos)
{
gameObject.transform.position = pos;
}
}
UIManager的代码
cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIManager : MonoBehaviour
{
GameObject gameManagerObj;
GameManager gameManeger;
public GameObject panel;
GameObject scoreText;
Button startBtn;
// Start is called before the first frame update
void Start()
{
gameManagerObj = GameObject.Find("GameManager");
if (gameManagerObj != null)
{
gameManeger = gameManagerObj.GetComponent<GameManager>();
if (gameManeger != null)
{
Debug.Log("score = " + gameManeger.score);
}
else
Debug.LogError("GameManager 物体上没挂 GameManager 脚本");
gameManeger.OnButtonClicked += updateScore;
}
else
{
Debug.LogError("场景里找不到名为 GameManager 的物体");
}
initUI();
}
void initUI()
{
scoreText = panel.transform.Find("scoreText").gameObject;
startBtn = panel.transform.Find("startBtn").gameObject.GetComponent<Button>();
startBtn.onClick.AddListener(() =>
{
onStartClicked();
});
}
// Update is called once per frame
void Update()
{
}
void updateScore(int score)
{
scoreText.GetComponent<Text>().text = score.ToString();
}
void onStartClicked()
{
Debug.Log("onStartClicked");
gameManeger.startGame();
// hide ui
startGameUpdate();
}
void startGameUpdate()
{
startBtn.gameObject.SetActive(false);
}
void endGameUpdate()
{
startBtn.gameObject.SetActive(true);
}
}
游戏运行图片
