主要技术:UI,Cavens,血条显示,玩家信息UI,主菜单UI
血条显示UI
新建UI -> Cavens(UI挂载在上面) -> image(血条)



1 2 3 4 5
| using System;
public event Action<int, int> UpdateHealthBarOnAttack;
UpdateHealthBarOnAttack?.Invoke(CurrentHealth, MaxHealth);
|
取子物体,按子物体顺序 0 1 2 ,子物体的子物体 0 0, 01……
1
| healthSlider = UIbar.GetChild(0).GetComponent<Image>();
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| # HeathBarUI public class HeathBarUI : MonoBehaviour { public GameObject healthbarPrefab; public Transform barpoint; public bool alwaysVisible;
public float visibleTime; public float timeLeft;
Image healthSlider; Transform UIbar; Transform cam; CharacterStates currentStates;
void Awake() { currentStates = GetComponent<CharacterStates>(); currentStates.UpdateHealthBarOnAttack += UpdataHealthBar; } void OnEnable() { cam = Camera.main.transform; foreach (Canvas canvas in FindObjectsOfType<Canvas>()) { if (canvas.renderMode == RenderMode.WorldSpace) { UIbar = Instantiate(healthbarPrefab, canvas.transform).transform; healthSlider = UIbar.GetChild(0).GetComponent<Image>(); UIbar.gameObject.SetActive(alwaysVisible); } } } private void UpdataHealthBar(int currentHealth, int maxHealth) { if (currentHealth <= 0) Destroy(UIbar.gameObject); UIbar.gameObject.SetActive(true); timeLeft = visibleTime; float sliderPercent = (float)currentHealth / maxHealth; healthSlider.fillAmount = sliderPercent; 】 } void LateUpdate() { if (UIbar != null) { UIbar.position = barpoint.position; UIbar.forward = -cam.forward; if (timeLeft <= 0 && !alwaysVisible) UIbar.gameObject.SetActive(false); else timeLeft -= Time.deltaTime; } } }
|
玩家信息显示UI
显示内容:血量 经验值 等级
血条:GameManager.Instance.playStats.CurrentHealth / GameManager.Instance.playStats.MaxHealth
经验值:GameManager.Instance.playStats.characterData.currentExp / GameManager.Instance.playStats.characterData.baseExp

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| # PlayerHealthUI public class PlayerHealthUI : MonoBehaviour { Text levelText; Image healthSlider; Image expSlider;
void Awake() { levelText = transform.GetChild(2).GetComponent<Text>(); healthSlider = transform.GetChild(0).GetChild(0).GetComponent<Image>(); expSlider = transform.GetChild(1).GetChild(0).GetComponent<Image>(); }
void Update() { levelText.text = "Level " + GameManager.Instance.playStats.characterData.currentLevel.ToString("00"); UpdateHealth(); UpdateExp(); }
void UpdateHealth() { float sliderPrecent = (float)GameManager.Instance.playStats.CurrentHealth / GameManager.Instance.playStats.MaxHealth; healthSlider.fillAmount = sliderPrecent; }
void UpdateExp() { float sliderPrecent = (float)GameManager.Instance.playStats.characterData.currentExp / GameManager.Instance.playStats.characterData.baseExp; expSlider.fillAmount = sliderPrecent; } }
|
1 2 3 4 5
| # CharacterStates TakeDamage
if (CurrentHealth <= 0) attacker.characterData.UpdateExp(characterData.killPoint); GameManager.Instance.playStats.characterData.UpdateExp(characterData.killPoint);
|
主菜单UI

- 设置 Pender Mode 为Screen Space - Camera,选择 Main Camera
调整位置
设置 Pender Mode 为 World Space 产生视觉差
MenuCanvas 挂载 MainMenu,设置每个按钮的功能,如何触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| # MainMenu public class MainMenu : MonoBehaviour { Button newGameButton; Button continueButton; Button quitButton;
private void Awake() { newGameButton = transform.GetChild(1).GetComponent<Button>(); continueButton = transform.GetChild(2).GetComponent<Button>(); quitButton = transform.GetChild(3).GetComponent<Button>(); newGameButton.onClick.AddListener(NewGame); continueButton.onClick.AddListener(ContinueGame); quitButton.onClick.AddListener(QuitGame); }
void NewGame() { PlayerPrefs.DeleteAll(); SceneControllor.Instance.TransitionToFirstLevel(); }
void ContinueGame() { SceneControllor.Instance.TransitionToLoadGame(); }
void QuitGame() { Application.Quit(); Debug.Log("退出游戏"); } }
|
空Object 挂载 SceneControllor
通过传送门 Destination 位置切换场景生成人物
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| # SceneControllor public void TransitionToMain() { StartCoroutine(LoadMain()); }
public void TransitionToLoadGame() { StartCoroutine(LoadLevel(SaveManager.Instance.SceneName)); }
public void TransitionToFirstLevel() { StartCoroutine(LoadLevel("Sky1")); }
IEnumerator LoadLevel(string scene) { if (scene != "") { yield return SceneManager.LoadSceneAsync(scene); yield return player = Instantiate(playerPrefab, GameManager.Instance.GetEntrance().position, GameManager.Instance.GetEntrance().rotation); SaveManager.Instance.SavePlayerData(); yield break; } }
IEnumerator LoadMain() { yield return SceneManager.LoadSceneAsync("Menu"); yield break; }
|
生成人物先读取存档
1 2 3 4 5
| # PlayerController void Start() { SaveManager.Instance.LoadPlayerData(); }
|
保存数据 读档当时场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| # SaveManager public class SaveManager : Singleton<SaveManager> { string sceneName = "level";
public string SceneName { get { return PlayerPrefs.GetString(sceneName); } }
protected override void Awake() { base.Awake(); DontDestroyOnLoad(this); }
void Update() { if (Input.GetKeyDown(KeyCode.Escape)) { SceneControllor.Instance.TransitionToMain(); }
if (Input.GetKeyDown(KeyCode.S)) { SavePlayerData(); }
if (Input.GetKeyDown(KeyCode.L)) { LoadPlayerData(); } }
public void SavePlayerData() { Save(GameManager.Instance.playStats.characterData, GameManager.Instance.playStats.characterData.name); }
public void LoadPlayerData() { Load(GameManager.Instance.playStats.characterData, GameManager.Instance.playStats.characterData.name); }
public void Save(Object data, string Key) { var jsonData = JsonUtility.ToJson(data, true); PlayerPrefs.SetString(Key, jsonData); PlayerPrefs.SetString(sceneName, SceneManager.GetActiveScene().name); PlayerPrefs.Save(); }
public void Load(Object data, string key) { if (PlayerPrefs.HasKey(key)) { JsonUtility.FromJsonOverwrite(PlayerPrefs.GetString(key), data); } } }
|