[Using Unity to Realize 7 of 100 Games] Create a turn-based game that imitates killing the spire card from scratch

foreword

Today I will take you to realize a simple card turn-based game

Let's take a look at the final effect first
insert image description here

material resources

Baidu link: https://pan.baidu.com/s/1uy8lN9wESsLy7z1YbfsjLw
Extraction code: 4345

start

1. UI framework

UIManager.cs UI Manager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//UI管理器
public class UIManager : MonoBehaviour
{
    
    
    //ui管理器
    public static UIManager Instance;
    private Transform canvasTf;//画布的变换组件
    private List<UIBase> uiList;//存储加载过的界面的集合
    private void Awake()
    {
    
    
        Instance = this;
        //找世界中的画布
        canvasTf = GameObject.Find("Canvas").transform;
        //初始化集合
        uiList = new List<UIBase>();
    }
    public UIBase ShowUI<T>(string uiName) where T : UIBase
    {
    
    
        UIBase ui = Find(uiName);
        if (ui == null)
        {
    
    
            //集合中没有 需要从Resources/UI文件夹加载
            GameObject obj = Instantiate(Resources.Load("UI/" + uiName), canvasTf) as GameObject;

            //改名字,默认实例化会加上(clone),所以得重命名
            obj.name = uiName;

            //添加需要的脚本
            ui = obj.AddComponent<T>();

            //添加到集合进行存储
            uiList.Add(ui);
        }
        else
        {
    
    
            //显示
            ui.Show();
        }
        return ui;
    }


    //隐藏
    public void HideUI(string uiName)
    {
    
    
        UIBase ui = Find(uiName);
        if (ui != null)
        {
    
    
            ui.Hide();
        }
    }

    //关闭某个界面
    public void CloseUI(string uiName)
    {
    
    
        UIBase ui = Find(uiName);
        if (ui != null)
        {
    
    
            uiList.Remove(ui);
            Destroy(ui.gameObject);
        }
    }

    //关闭所有界面
    public void CloseAllUI(){
    
    
        for(int i = uiList.Count - 1; i>=0; i--){
    
    
            Destroy(uiList[i].gameObject);
        }
        uiList.Clear();//清空合集
    }  


    //从集合中找到名字对应的界面脚本
    public UIBase Find(string uiName)
    {
    
    
        for (int i = 0; i < uiList.Count; i++)
        {
    
    
            if (uiList[i].name == uiName) return uiList[i];
        }
        return null;
    }
}

UIBase.cs interface base class

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//界面基类
public class UIBase : MonoBehaviour
{
    
    
    //显示
    public virtual void Show()
    {
    
    
        gameObject.SetActive(true);
    }

    //隐藏
    public virtual void Hide()
    {
    
    

        gameObject.SetActive(false);
    }
    //关闭界面(销毁)
    public virtual void Close()
    {
    
    
        UIManager.Instance.CloseUI(gameObject.name);
    }

}

Called in LoginUI.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

//开始界面(要继承UIBase)
public class LoginUI : UIBase{
    
    }

GameApp .cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//游戏入口脚本
public class GameApp : MonoBehaviour
{
    
    
    void Start(){
    
    
        //显示loginUI创建的脚本名字记得跟预制体物体名字一致
        UIManager.Instance.ShowUI<LoginUI>("LoginUI");
    }
}

2. Mount the script

insert image description here
running result
insert image description here

3. Event monitoring, used to bind button events

Add an event to the start game button
insert image description here

Add UIEventTrigger.cs script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.EventSystems;

//事件监听
public class UIEventTrigger : MonoBehaviour, IPointerClickHandler
{
    
    
    //这是一个公共的委托,它接受两个参数,一个是被点击的游戏对象,另一个是关于点击事件的数据。
    public Action<GameObject, PointerEventData> onClick;

    //用于获取或添加 UIEventTrigger 组件
    public static UIEventTrigger Get(GameObject obj)
    {
    
    
        UIEventTrigger trigger = obj.GetComponent<UIEventTrigger>();
        if (trigger == null)
        {
    
    
            trigger = obj.AddComponent<UIEventTrigger>();
        }
        return trigger;
    }

    public void OnPointerClick(PointerEventData eventData)
    {
    
    
        //这是 IPointerClickHandler 接口的方法,当 UI 元素被点击时,它将被调用。
        if (onClick != null) onClick(gameObject, eventData);
    }
}

Added registration event in UIBase.cs

//注册事件
public UIEventTrigger Register(string name)
{
    
    
    Transform tf = transform.Find(name);
    return UIEventTrigger.Get(tf.gameObject);
}

LoginUI binding button event

void Awake(){
    
    
  //开始游戏
    Register("bg/startBtn").onClick = onStartGameBtn;
}

private void onStartGameBtn(GameObject obj, PointerEventData pData){
    
    
    //关闭login界面
    Close();
}

running result
insert image description here

4. Sound Manager

AudioManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//声音管理器
public class AudioManager : MonoBehaviour
{
    
    
    public static AudioManager Instance;
    private AudioSource bgmSource;//播放bgm的音频
    private void Awake()
    {
    
    
        Instance = this;
    }
    //初始化
    public void Init()
    {
    
    
        bgmSource = gameObject.AddComponent<AudioSource>();
    }

    //播放bgm
    public void PlayBGM(string name, bool isLoop = true)
    {
    
    
        //加载bgm声音剪辑
        AudioClip clip = Resources.Load<AudioClip>("Sounds/BGM/" + name);
        bgmSource.clip = clip;//设置音频
        bgmSource.loop = isLoop;//是否循环
        bgmSource.Play();
    }


    //播放音效
    public void PlaEffect(string name)
    {
    
    
        AudioClip clip = Resources.Load<AudioClip>("Sounds/" + name);
        AudioSource.PlayClipAtPoint(clip, transform.position);
    }
}

transfer

//游戏入口脚本
public class GameApp : MonoBehaviour
{
    
    
    void Start(){
    
    
        //初始化声音管理器
        AudioManager.Instance.Init();

        //显示loginUI创建的脚本名字记得跟预制体物体名字一致
        UIManager.Instance.ShowUI<LoginUI>("LoginUI");

        //播放bgm
        AudioManager.Instance.PlayBGM("bgm1");
    }
}

mount script
insert image description here
effect
insert image description here

Five, excel to txt text

To read Excel, you need to use Excel.dlland ICSharpCode.SharpZipLiblibrary files

Create a new MyEditor.cs in the Editor directory

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;//编辑器的命名空间
using System.IO;//文件流
using Excel;//读取excel
using System.Data;

//编辑器脚本
public static class MyEditor
{
    
    
    [MenuItem("我的工具/excel转成txt")]
    public static void ExportExcelToTxt()
    {
    
    
        //_Excel文件夹路径
        string assetPath = Application.dataPath + "/_Excel";
        //获得Excel文件夹中的excel文件
        string[] files = Directory.GetFiles(assetPath, "*.xlsx");
        for (int i = 0; i < files.Length; i++)
        {
    
    
            files[i] = files[i].Replace('\\', '/');//反斜杠替换成正斜杠
            //通过文件流读取文件
            using (FileStream fs = File.Open(files[i], FileMode.Open, FileAccess.Read))
            {
    
    
                //文件流转成excel 对象
                var excelDataReader = ExcelReaderFactory.CreateOpenXmlReader(fs);
                //获得excel数据
                DataSet dataSet = excelDataReader.AsDataSet();
                //读取excel第一张表
                DataTable table = dataSet.Tables[0];
                //将表中内容 读取后 存储到 对应的txt文件
                readTableToTxt(files[i], table);
            }
        }
        //刷新编辑器
        AssetDatabase.Refresh();
    }

    private static void readTableToTxt(string filePath, DataTable table)
    {
    
    
        // 获得文件名(不要文件后缀 生成与之名字相同的txt文件)
        string fileName = Path.GetFileNameWithoutExtension(filePath);
        // txt文件存储的路径
        string path = Application.dataPath + "/Resources/Data/" + fileName + ".txt";
        //判断Resources/Data文件夹中是否已经存在对应的txt文件,如果是 则删除
        if (File.Exists(path))
        {
    
    
            File.Delete(path);
        }
        // 文件流创建txt文件
        using (FileStream fs = new FileStream(path, FileMode.Create))
        {
    
    
            // 文件流转写入流方便写入字符串
            using (StreamWriter sw = new StreamWriter(fs))
            {
    
    
                // 遍历table
                for (int row = 0; row < table.Rows.Count; row++)
                {
    
    
                    DataRow dataRow = table.Rows[row];
                    string str = "";
                    //遍历列
                    for (int col = 0; col < table.Columns.Count; col++)
                    {
    
    
                        string val = dataRow[col].ToString();
                        str = str + val + "\t";//每一项tab分割
                    }

                    //写入
                    sw.Write(str);

                    //如果不是最后一行换行
                    if (row != table.Rows.Count - 1)
                    {
    
    
                        sw.WriteLine();
                    }
                }
            }


        }
    }
}

Remember to create a new Data folder under the Resources directory to store the generated txt text. Clicking the tool will generate the xlsx file in the _Excel folder as txt and save it to the /Resources/Data/ directory. The approximate style of the configuration table is
insert image description here
insert image description here
card.xlsx
cardType
insert image description here
. xlsx
insert image description here
enemy.xlsx
insert image description here
level.xlsx
insert image description here

6. Game configuration

Game configuration GameConfigData

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 游戏配置表类,每个对象对应一个xt配置表
public class GameConfigData
{
    
    
    // 存储配置表中的所有数据
    private List<Dictionary<string, string>> dataDic;
    // 构造函数,参数为字符串
    public GameConfigData(string str)
    {
    
    
        // 初始化数据字典
        dataDic = new List<Dictionary<string, string>>();
        // 按换行符切割字符串
        string[] lines = str.Split('\n');
        // 第一行是存储数据的类型
        string[] title = lines[0].Trim().Split('\t');//tab切割
        // 从第三行(下标为2)开始遍历数据,第二行数据是解释说明
        for (int i = 2; i < lines.Length; i++)
        {
    
    
            // 创建新的字典存储每行数据
            Dictionary<string, string> dic = new Dictionary<string, string>();
            // 按tab切割每行数据
            string[] tempArr = lines[i].Trim().Split("\t");
            // 将切割后的数据添加到字典中
            for (int j = 0; j < tempArr.Length; j++)
            {
    
    
                dic.Add(title[j], tempArr[j]);
            }
            // 将字典添加到数据列表中
            dataDic.Add(dic);
        }
    }

    // 获取所有行的数据
    public List<Dictionary<string, string>> GetLines()
    {
    
    
        return dataDic;
    }

    // 根据ID获取一行数据
    public Dictionary<string, string> GetOneById(string id)
    {
    
    
        // 遍历数据列表
        for (int i = 0; i < dataDic.Count; i++)
        {
    
    
            // 获取当前字典
            Dictionary<string, string> dic = dataDic[i];
            // 如果字典中的ID与参数相同,返回该字典
            if (dic["Id"] == id)
            {
    
    
                return dic;
            }
        }
        // 如果没有找到,返回null
        return null;
    }
}

GameConfigManager.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
// 游戏配置管理类
public class GameConfigManager
{
    
    
    // 单例模式
    public static GameConfigManager Instance = new GameConfigManager();
    private GameConfigData cardData;//卡牌表
    private GameConfigData enemyData;//敌人表
    private GameConfigData levelData;//关卡表
    private GameConfigData cardTypeData; //卡牌类型
    // 文本资源
    private TextAsset textAsset;

    // 初始化配置文件(txt文件 存储到内存)
    public void Init()
    {
    
    
        // 加载卡牌数据
        textAsset = Resources.Load<TextAsset>("Data/card");
        cardData = new GameConfigData(textAsset.text);

        // 加载敌人数据
        textAsset = Resources.Load<TextAsset>("Data/enemy");
        enemyData = new GameConfigData(textAsset.text);

        // 加载关卡数据
        textAsset = Resources.Load<TextAsset>("Data/level");
        levelData = new GameConfigData(textAsset.text);

        //卡牌类型数据
        textAsset = Resources.Load<TextAsset>("Data/cardType");
        cardTypeData = new GameConfigData(textAsset.text);
    }

    // 获取卡牌行数据
    public List<Dictionary<string, string>> GetCardLines()
    {
    
    
        return cardData.GetLines();
    }

    // 获取敌人行数据
    public List<Dictionary<string, string>> GetEnemyLines()
    {
    
    
        return enemyData.GetLines();
    }

    // 获取关卡行数据
    public List<Dictionary<string, string>> GetLevelLines()
    {
    
    
        
        return levelData.GetLines();
    }
    // 根据ID获取卡牌数据
    public Dictionary<string, string> GetCardById(string id)
    {
    
    
        return cardData.GetOneById(id);
    }
    // 根据ID获取敌人数据
    public Dictionary<string, string> GetEnemyById(string id)
    {
    
    
        return enemyData.GetOneById(id);
    }
    // 根据ID获取关卡数据
    public Dictionary<string, string> GetLevelById(string id)
    {
    
    
        return levelData.GetOneById(id);
    }

    //根据ID获取卡牌类型
    public Dictionary<string, string> GetCardTypeById(string id)
    {
    
    
        return cardTypeData.GetOneById(id);
    }
}

The game entry script GameApp initializes and calls the test

//初始化配置表
GameConfigManager.Instance.Init();

//测试
string name = GameConfigManager.Instance.GetCardById("1001")["Name"];
print(name);

Running effect
insert image description here
Output is correct
insert image description here

7. User Information Form

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

//用户信息管理器(拥有的卡牌等信息金币等)
public class RoleManager
{
    
    
    public static RoleManager Instance = new RoleManager();
    public List<string> cardList;//存储拥有的卡牌的id
    public void Init()
    {
    
    
        cardList = new List<string>();
        //四张攻击卡 四张防御卡 两张效果卡
        cardList.Add("1000");
        cardList.Add("1000");
        cardList.Add("1000");
        cardList.Add("1000");

        cardList.Add("1001");
        cardList.Add("1001");
        cardList.Add("1001");
        cardList.Add("1001");

        cardList.Add("1002");
        cardList.Add("1002");
    }
}

Game entry script GameApp initialization

//初始化用户信息
RoleManager.Instance.Init();

8. Battle Manager

combat unit

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//战斗单元
public class FightUnit
{
    
    
    public virtual void Init() {
    
     }//初始化
    public virtual void OnUpdate() {
    
     }//每帧调用
}

Added script control for different combat states

# 卡牌战斗初始化
public class FightInit : FightUnit{
    
    }

# 玩家回合
public class Fight_PlayerTurn : FightUnit{
    
    }

# 敌人回合
public class Fight_EnemyTurn : FightUnit{
    
    }

# 胜利
public class Fight_Win : FightUnit{
    
    }

# 失败
public class Fight_Fail : FightUnit{
    
    }

Fight Manager FightManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//战斗枚举
public enum FightType
{
    
    
    None,
    Init,
    Player,//玩家回合
    Enemy,//敌人回合
    Win,
    Fail
}
//战斗管理器
public class FightManager : MonoBehaviour
{
    
    

    public static FightManager Instance;
    public FightUnit fightUnit;//战斗单元
    private void Awake()
    {
    
    

        Instance = this;
    }
    //切换战斗类型
    public void ChangeType(FightType type)
    {
    
    
        switch (type)
        {
    
    
            case FightType.None:
                break;
            case FightType.Init:
                fightUnit = new FightInit();
                break;
            case FightType.Player:
                fightUnit = new Fight_PlayerTurn();
                break;
            case FightType.Enemy:
                fightUnit = new Fight_EnemyTurn();
                break;
            case FightType.Win:
                fightUnit = new Fight_Win();
                break;
            case FightType.Fail:
                fightUnit = new Fight_Fail();
                break;
        }
        fightUnit.Init();// 初始化
    }
    private void Update(){
    
    
        if(fightUnit != null){
    
    
            fightUnit.OnUpdate();
        }
    }

}

Mount the script
insert image description here
to modify the LoginUI to initialize the battle when starting the game

private void onStartGameBtn(GameObject obj, PointerEventData pData){
    
    
    //关闭login界面
    Close();

    //战斗初始化
    FightManager.Instance.ChangeType(FightType.Init);
}

Improve card battle initialization, switch interface and bgm, remember to add FightUI script code first

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//卡牌战斗初始化
public class FightInit : FightUnit
{
    
    
    public override void Init() {
    
    
        //切换bgm
        AudioManager.Instance.PlayBGM("battle");
        //显示战斗界面
        UIManager.Instance.ShowUI<FightUI>("FightUI");
    }
    public override void OnUpdate() {
    
     
        base.OnUpdate();
    }
}

running result
insert image description here

9. Enemy Manager

Enemy Script Enemy

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//敌人脚本
public class Enemy : MonoBehaviour
{
    
    
    protected Dictionary<string, string> data;//敌人数据表信息
    public void Init(Dictionary<string, string> data)
    {
    
    
        this.data = data;
    }
}

Enemy Manager EnemyManeger

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//敌人管理器
public class EnemyManeger
{
    
    
    public static EnemyManeger Instance = new EnemyManeger();

    private List<Enemy> enemyList;//存储战斗中的敌人
    //加载敌人资源 id=关卡Id
    public void LoadRes(string id)
    {
    
    
        enemyList = new List<Enemy>();
        /* 
         *  Id	Name	EnemyIds	Pos	
         *  Id	关卡名称	敌人Id的数组	所有怪物的位置	
         *  10003	3	10001=10002=10003	3,0,1=0,0,1=-3,0,1	
         */
        //读取关卡表
        Dictionary<string, string> levelData = GameConfigManager.Instance.GetLevelById(id);
        //切割字符串,获取敌人id信息
        string[] enemyIds = levelData["EnemyIds"].Split('=');

        string[] enemyPos = levelData["Pos"].Split('=');// 敌人位置信息
        for (int i = 0; i < enemyIds.Length; i++)
        {
    
    
            string enemyId = enemyIds[i];
            string[] posArr = enemyPos[i].Split(',');
            //敌人位置
            float x = float.Parse(posArr[0]);
            float y = float.Parse(posArr[1]);
            float z = float.Parse(posArr[2]);
            // 根据敌人id获得单个敌人信息
            Dictionary<string, string> enemyData = GameConfigManager.Instance.GetEnemyById(enemyId);
            GameObject obj = Object.Instantiate(Resources.Load(enemyData["Model"])) as GameObject;//从资源路径加载对应的敌人

            Enemy enemy = obj.AddComponent<Enemy>();//添加敌人脚本
            enemy.Init(enemyData);//存储敌人信息
            enemyList.Add(enemy);//存储到集合
           
            obj.transform.position = new Vector3(x, y, z);
        }
    }
}

Battle Card Manager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


//战斗卡牌管理器
public class FightCardManager
{
    
    
    public static FightCardManager Instance = new FightCardManager();
    public List<string> cardList;//卡堆集合
    public List<string> usedCardList;//弃牌堆
    //初始化
    public void Init()
    {
    
    
        cardList = new List<string>();
        usedCardList = new List<string>();
        //定义临时集合
        List<string> tempList = new List<string>();
        //将玩家的卡牌存储到临时集合
        tempList.AddRange(RoleManager.Instance.cardList);
        while (tempList.Count > 0)
        {
    
    
            //随机下标
            int tempIndex = Random.Range(0, tempList.Count);
            //添加到卡堆
            cardList.Add(tempList[tempIndex]);
            //临时集合删除
            tempList.RemoveAt(tempIndex);
        }
        Debug.Log(cardList.Count);
    }
}

Card battle initialization FightInit, new enemy generation, initialization of battle cards

//这里读取关卡三的敌人数据做测试,可以自由选择其他的
EnemyManeger.Instance.LoadRes("10003");

//初始化战斗卡牌
FightCardManager.Instance.Init();

Run the effect, the enemy will be loaded
insert image description here

10. Player blood volume, energy, defense value, number of cards

Modify the FightManager Code

public int MaxHp;//最大血量
public int CurHp;//当前血量
public int MaxPowerCount;//最大能量(卡牌使用会消耗能量)
public int CurPowerCount;//当前能量
public int DefenseCount;//防御值

public void Init()
{
    
    
    MaxHp = 10;
    CurHp = 10;
    MaxPowerCount = 10;
    CurPowerCount = 10;
    DefenseCount = 10;
}

Card battle initialization FightInit script, call to initialize battle values

//初始化战斗数值
FightManager.Instance.Init();

Improve the fighting interface FightUI code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

//战斗界面
public class FightUI : UIBase
{
    
    
    private Text cardCountTxt;//卡牌数量
    private Text noCardCountTxt;//弃牌堆数量
    private Text powerTxt;
    private Text hpTxt;
    private Image hpImg;
    private Text fyTxt;//防御数值

    private void Awake()
    {
    
    
        cardCountTxt = transform.Find("hasCard/icon/Text").GetComponent<Text>();
        noCardCountTxt = transform.Find("noCard/icon/Text").GetComponent<Text>();
        powerTxt = transform.Find("mana/Text").GetComponent<Text>();
        hpTxt = transform.Find("hp/moneyTxt").GetComponent<Text>();
        hpImg = transform.Find("hp/fill").GetComponent<Image>();
        fyTxt = transform.Find("hp/fangyu/Text").GetComponent<Text>();
    }

    private void Start()
    {
    
    
        UpdateHp();
        UpdatePower();
        UpdateDefense();
        UpdateCardCount();
        UpdateUsedCardCount();
    }

    //更新血量显示
    public void UpdateHp()
    {
    
    
        hpTxt.text = FightManager.Instance.CurHp + "/" + FightManager.Instance.MaxHp;
        hpImg.fillAmount = (float)FightManager.Instance.CurHp / (float)FightManager.Instance.MaxHp;
    }

    //更新能量
    public void UpdatePower()
    {
    
    
        powerTxt.text = FightManager.Instance.CurPowerCount + "/" + FightManager.Instance.MaxPowerCount;
    }

    //防御更新
    public void UpdateDefense()
    {
    
    
        fyTxt.text = FightManager.Instance.DefenseCount.ToString();
    }
    //更新卡堆数量
    public void UpdateCardCount()
    {
    
    

        cardCountTxt.text = FightCardManager.Instance.cardList.Count.ToString();
    }
    //更新弃牌堆数量
    public void UpdateUsedCardCount()
    {
    
    

        noCardCountTxt.text = FightCardManager.Instance.usedCardList.Count.ToString();
    }
}

running result
insert image description here

11. The logic of the enemy's HP action display

UI Manager UIManager new method

//创建敌人头部的行动图标物体
public GameObject CreateActionIcon()
{
    
    
    GameObject obj = Instantiate(Resources.Load("UI/actionIcon"), canvasTf) as GameObject;
    obj.transform.SetAsFirstSibling();// 设置在父级的第一位
    return obj;
}

//创建敌人底部的血量物体
public GameObject CreateHpItem()
{
    
    
    GameObject obj = Instantiate(Resources.Load("UI/HpItem"), canvasTf) as GameObject;
    obj.transform.SetAsFirstSibling();// 设置在父级的第一位
    return obj;
}

Improve the enemy script Enemy

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public enum ActionType
{
    
    
    None,
    Defend,//加防御
    Attack,//攻击
}

//敌人脚本
public class Enemy : MonoBehaviour
{
    
    
    protected Dictionary<string, string> data;//敌人数据表信息
    public ActionType type;

    public GameObject hpItemObj;
    public GameObject actionObj;

    //UI相关
    public Transform attackTf;
    public Transform defendTf;
    public Text defendTxt;
    public Text hpTxt;
    public Image hpImg;

    //数值相关
    public int Defend;
    public int Attack;
    public int MaxHp;
    public int CurHp;
    public void Init(Dictionary<string, string> data)
    {
    
    
        this.data = data;
    }

    void Start()
    {
    
    
        type = ActionType.None;
        hpItemObj = UIManager.Instance.CreateHpItem();
        actionObj = UIManager.Instance.CreateActionIcon();
        attackTf = actionObj.transform.Find("attack");
        defendTf = actionObj.transform.Find("defend");
        defendTxt = hpItemObj.transform.Find("fangyu/Text").GetComponent<Text>();
        hpTxt = hpItemObj.transform.Find("hpTxt").GetComponent<Text>();
        hpImg = hpItemObj.transform.Find("fill").GetComponent<Image>();
        // 设置血条行动力位置
        hpItemObj.transform.position = Camera.main.WorldToScreenPoint(transform.position + Vector3.down * 0.2f);
        actionObj.transform.position = Camera.main.WorldToScreenPoint(transform.Find("head").position);
        SetRandomAction();
        //初始化数值
        Attack = int.Parse(data["Attack"]);
        CurHp = int.Parse(data["Hp"]);
        MaxHp = CurHp;
        Defend = int.Parse(data["Defend"]);

        UpdateHp();
        UpdateDefend();
    }

    //随机一个行动
    void SetRandomAction()
    {
    
    
        int ran = Random.Range(1, 3);
        type = (ActionType)ran;
        switch (type)
        {
    
    
            case ActionType.None:
                break;
            case ActionType.Defend:
                attackTf.gameObject.SetActive(false);
                defendTf.gameObject.SetActive(true);
                break;
            case ActionType.Attack:
                attackTf.gameObject.SetActive(true);
                defendTf.gameObject.SetActive(false);
                break;
        }
    }

    //更新血量信息
    public void UpdateHp(){
    
    
        hpTxt.text = CurHp + "/" + MaxHp;
        hpImg.fillAmount = (float)CurHp / (float)MaxHp;
    }

    //更新防御信息
    public void UpdateDefend(){
    
    
        defendTxt.text = Defend.ToString();
    }
}

Effect, in order to make the combat effect richer, add a background
insert image description here

12. Realization of UI prompt effect

Now the card battle initialization FightInit calls the switch player turn function

//切换到玩家回合
FightManager.Instance.ChangeType(FightType.Player);

The UI Manager UIManager adds a method of calling the prompt interface, and introduces the DoTween plug-in to realize the animation effect of the prompt pop-up window. If you don’t know how to use DoTween, you can read my previous article: [unity plug-in] DoTween animation plug-in installation and
integration (the most complete)

//提示界面
public void ShowTip(string msg, Color color, System.Action callback = null)
{
    
    
    GameObject obj = Instantiate(Resources.Load("UI/Tips"), canvasTf) as GameObject;
    Text text = obj.transform.Find("bg/Text").GetComponent<Text>();
    text.color = color;
    text.text = msg;
    Tween scale1 = obj.transform.Find("bg").DOScaleY(1, 0.4f);
    Tween scale2 = obj.transform.Find("bg").DOScaleY(0, 0.4f);
    Sequence seq = DOTween.Sequence();
    seq.Append(scale1);
    seq.AppendInterval(0.5f);
    seq.Append(scale2);
    seq.AppendCallback(delegate ()
    {
    
    
        if (callback != null) callback();
    });
    MonoBehaviour.Destroy(obj, 2);
}

Player turn Fight_PlayerTurn call prompt effect

UIManager.Instance.ShowTip("玩家回合", Color.green, delegate(){
    
    
    Debug.Log("抽卡");
});

Effect
insert image description here

13. Card generation

Fight Card Manager FightCardManager adds two new methods

//是否有卡
public bool HasCard()
{
    
    
    return cardList.Count > 0;
}
//抽卡
public string DrawCard()
{
    
    
    string id = cardList[cardList.Count - 1];
    cardList.RemoveAt(cardList.Count - 1);
    return id;
}

Add CardItem script

public class CardItem : MonoBehaviour
{
    
    
    public Dictionary<string, string> data;//卡牌信息

    public void Init(Dictionary<string, string> data)
    {
    
    
        this.data = data;
    }
}

Battle interface FightUI modified

//存储卡牌物体的合集
private List<CardItem> cardItemList;

private void Awake()
{
    
    
   cardItemList = new List<CardItem>();
}

//创建卡牌物体
public void CreateCardItem(int count)
{
    
    
    if (count > FightCardManager.Instance.cardList.Count)
    {
    
    
        count = FightCardManager.Instance.cardList.Count;
    }

    for (int i = 0; i < count; i++)
    {
    
    
        GameObject obj = Instantiate(Resources.Load("UI/CardItem"), transform) as GameObject;
        obj.GetComponent<RectTransform>().anchoredPosition = new Vector2(-1000, -700);
        var item = obj.AddComponent<CardItem>();
        string cardId = FightCardManager.Instance.DrawCard();
        Dictionary<string, string> data = GameConfigManager.Instance.GetCardById(cardId);
        item.Init(data);
        cardItemList.Add(item);
    }
}

//更新卡牌位置
public void UpdateCardItemPos()
{
    
    

    float offset = 800f / cardItemList.Count;
    Vector2 startPos = new Vector2(-cardItemList.Count / 2f * offset + offset * 0.5f, -500);
    for (int i = 0; i < cardItemList.Count; i++)
    {
    
    
        cardItemList[i].GetComponent<RectTransform>().DOAnchorPos(startPos, 0.5f);
        startPos.x = startPos.x + offset;
    }
}

UI Manager UIManager new method

//获取某个界面的脚本
public T GetUI<T>(string uiName) where T :  UIBase{
    
    
    UIBase ui = Find(uiName);
    if(ui != null){
    
    
        return ui.GetComponent<T>();
    }
    return null;
}

The player turns to call the draw method

public override void Init() {
    
    
 	UIManager.Instance.ShowTip("玩家回合", Color.green, delegate(){
    
    
        //抽卡
        Debug.Log("抽卡");
        UIManager.Instance.GetUI<FightUI>("FightUI").CreateCardItem(4);//抽4张
        UIManager.Instance.GetUI<FightUI>("FightUI").UpdateCardItemPos();//更新卡牌位置
    });
}

running result
insert image description here

14. Card information display

Added start method for CardItem to render card information

private void Start()
{
    
    
    transform.Find("bg").GetComponent<Image>().sprite = Resources.Load<Sprite>(data["BgIcon"]);
    transform.Find("bg/icon").GetComponent<Image>().sprite = Resources.Load<Sprite>(data["Icon"]);
    transform.Find("bg/msgTxt").GetComponent<Text>().text = string.Format(data["Des"], data["Arg0"]);
    transform.Find("bg/nameTxt").GetComponent<Text>().text = data["Name"];
    transform.Find("bg/useTxt").GetComponent<Text>().text = data["Expend"];
    transform.Find("bg/Text").GetComponent<Text>().text = GameConfigManager.Instance.GetCardTypeById(data["Type"])["Name"];
}

Effect
insert image description here

15. Card selection effect

Added mouse event for CardItem

public class CardItem : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
    
    
	//鼠标进入
    public void OnPointerEnter(PointerEventData eventData)
    {
    
    
        transform.DOScale(1.5f, 0.25f);
        index = transform.GetSiblingIndex();
        transform.SetAsLastSibling();
        transform.Find("bg").GetComponent<Image>().material.SetColor("_lineColor", Color.yellow);
        transform.Find("bg").GetComponent<Image>().material.SetFloat("_lineWidth",10);
    }

    //鼠标离开
    public void OnPointerExit(PointerEventData eventData)
    {
    
    
        transform.DOScale(1, 0.25f);
        transform.SetSiblingIndex(index);
        transform.Find("bg").GetComponent<Image>().material.SetColor("_lineColor", Color.black);
        transform.Find("bg").GetComponent<Image>().material.SetFloat("_lineWidth", 1);
    }
    
	private void Start()
    {
    
    
       //。。。

        //设置bg背景image的外边框材质
        transform.Find("bg").GetComponent<Image>().material = Instantiate(Resources.Load<Material>("Mats/outline"));
    }
}

running result
insert image description here

16. Card dragging

Added drag event for CardItem

public class CardItem : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    
    
	Vector2 initPos;//拖拽开始时记录卡牌的位置
    //开始拖拽
    public virtual void OnBeginDrag(PointerEventData eventData)
    {
    
    
        initPos = transform.GetComponent<RectTransform>().anchoredPosition;
        //播放声音
        AudioManager.Instance.PlaEffect("Cards/draw");
    }

    //拖拽中
    public virtual void OnDrag(PointerEventData eventData)
    {
    
    
        Vector2 pos;
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
            transform.parent.GetComponent<RectTransform>(),
            eventData.position,
            eventData.pressEventCamera,
            out pos
        ))
        {
    
    
            transform.GetComponent<RectTransform>().anchoredPosition = pos;
        }
    }

    //结束拖拽
    public virtual void OnEndDrag(PointerEventData eventData)
    {
    
    
        transform.GetComponent<RectTransform>().anchoredPosition = initPos;
        transform.SetSiblingIndex(index);
    }
}

running result
insert image description here

17. Card branch (attack card, draw card, defense card)

Modify FightUI to create card object method CreateCardItem

// var item = obj.AddComponent<CardItem>();
改为
CardItem item = obj.AddComponent(System.Type.GetType(data["Script"])) as CardItem;

Added various card scripts

# 无中生有卡(抽卡效果的卡片)
public class AddCard : CardItem {
    
    }

# 攻击卡
public class AttackCardItem : CardItem {
    
    }

# 防御卡(加护盾效果)
public class DefendCard : CardItem {
    
    }

18. Defensive card effect

Added a method to delete card objects in the battle interface FightUI

//删除卡牌物体
public void RemoveCard(CardItem item)
{
    
    
    AudioManager.Instance.PlayEffect("Cards/cardShove");//移除音效
    item.enabled = false;//禁用卡牌逻辑
    //添加到弃牌集合
    FightCardManager.Instance.usedCardList.Add(item.data["Id"]);
    //更新使用后的卡牌数量
    noCardCountTxt.text = FightCardManager.Instance.usedCardList.Count.ToString();
    //从集合中删除
    cardItemList.Remove(item);
    //刷新卡牌位置
    UpdateCardItemPos();
    //卡牌移到弃牌堆效果
    item.GetComponent<RectTransform>().DOAnchorPos(new Vector2(1000, -700), 0.25f);
    item.transform.DOScale(0, 0.25f);
    Destroy(item.gameObject, 1);
}

CardItem adds a new way to use cards

//尝试使用卡牌
public virtual bool TryUse()
{
    
    
    //卡牌需要的费用
    int cost = int.Parse(data["Expend"]);
    if (cost > FightManager.Instance.CurPowerCount)
    {
    
    
        //费用不足
        AudioManager.Instance.PlayEffect("Effect/lose");//使用失败音效
        //提示
        UIManager.Instance.ShowTip("费用不足", Color.red);
        return false;
    }
    else
    {
    
    
        //减少费用
        FightManager.Instance.CurPowerCount -= cost;
        //刷新费用文本
        UIManager.Instance.GetUI<FightUI>("FightUI").UpdatePower();
        //使用的卡牌删除
        UIManager.Instance.GetUI<FightUI>("FightUI").RemoveCard(this);
        return true;
    }
}

//创建卡牌使用后的特效
public void PlayEffect(Vector3 pos)
{
    
    
    GameObject effectobj = Instantiate(Resources.Load(data["Effects"])) as GameObject;
    effectobj.transform.position = pos;
    Destroy(effectobj, 2);
}

Defense Card DefendCard call

public class DefendCard : CardItem
{
    
    
    public override void OnEndDrag(PointerEventData eventData)
    {
    
    
        if (TryUse() == true)
        {
    
    
            //使用效果
            int val = int.Parse(data["Arg0"]);
            //播放使用后的声音(每张卡使用的声音可能不一样)
            AudioManager.Instance.PlayEffect("Effect/healspell");// 这个字段可以配置到表中

            //增加防御力
            FightManager.Instance.DefenseCount += val;
            // 刷新防御文本
            UIManager.Instance.GetUI<FightUI>("FightUI").UpdateDefense();
            Vector3 pos = Camera.main.transform.position;
            pos.y = 0;
            PlayEffect(pos);
        }else{
    
    
            base.OnEndDrag(eventData);
        }
    }
}

Effect
insert image description here

19. The card effect of drawing cards

public class AddCard : CardItem
{
    
    
    public override void OnEndDrag(PointerEventData eventData)
    {
    
    
        if (TryUse() == true)
        {
    
    
            int val = int.Parse(data["Arg0"]);//抽卡数量
                                              //是否有卡抽
            if (FightCardManager.Instance.HasCard() == true)
            {
    
    
                UIManager.Instance.GetUI<FightUI>("FightUI").CreateCardItem(val);
                UIManager.Instance.GetUI<FightUI>("FightUI").UpdateCardItemPos();
                Vector3 pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 2.5f));
                PlayEffect(pos);
            }
            else
            {
    
    
                base.OnEndDrag(eventData);
            }
        }
        else
        {
    
    
            base.OnEndDrag(eventData);
        }
    }
}

Effect
insert image description here

20. Monster selection effect

Modify Enemy

SkinnedMeshRenderer _meshrenderer;
void Start()
{
    
    
    _meshrenderer = transform.GetComponentInChildren<SkinnedMeshRenderer>();
    
	//。。。
	
	//TODO:测试
    OnSelect();
}

//被攻击卡选中,显示红边
public void OnSelect(){
    
    
    _meshrenderer.material.SetColor("_OtlColor", Color.red);
}

//未选中
public void OnUnSelect(){
    
    
    _meshrenderer.material.SetColor("_OtlColor", Color.black);
}

Effect
insert image description here

Twenty-one, the monster is injured

Enemy Manager EnemyManeger adds a method to remove enemies

//移除敌人
public void DeleteEnemy(Enemy enemy){
    
    
    enemyList.Remove(enemy);

    //TODO:后续还要做击杀所有怪物的判断
}

Enemy script Enemy added injury method

public Animator ani;

void Start()
{
    
    
	ani = transform.GetComponent<Animator>();
}

//受伤
public void Hit(int val)
{
    
    
    //先扣护盾
    if (Defend > val)
    {
    
    
        //扣护盾
        Defend -= val;
        //播放受伤
        ani.Play("hit", 0, 0);
    }
    else
    {
    
    
        val = val - Defend;
        Defend = 0;
        CurHp -= val;
        if (CurHp <= 0)
        {
    
    
            CurHp = 0;
            // 播放死亡
            ani.Play("die");
            //敌人从列表中移除
            EnemyManeger.Instance.DeleteEnemy(this);
            Destroy(gameObject, 1);
            Destroy(actionObj);
            Destroy(hpItemObj);
        }else{
    
    
            //受伤
            ani.Play("hit", 0, 0);
        }
    }
    //刷新血量等ui
    UpdateDefend();
    UpdateHp();
}

22. Attack card effect

AttackCardItem Script

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;

public class AttackCardItem : CardItem, IPointerDownHandler
{
    
    

    //按下
    public void OnPointerDown(PointerEventData eventData)
    {
    
    
        //播放声音
        AudioManager.Instance.PlayEffect("Cards/draw");
        //隐藏鼠标
        Cursor.visible = false;
        //关闭所有协同程序
        StopAllCoroutines();
        //启动鼠标操作协同程序
        StartCoroutine(OnMouseDownRight(eventData));

    }
    IEnumerator OnMouseDownRight(PointerEventData pData)
    {
    
    
        while (true)
        {
    
    
            //如果按下鼠标右键跳出循环
            if (Input.GetMouseButton(1)) break;
            Vector2 pos;
            if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
                transform.parent.GetComponent<RectTransform>(),
                pData.position,
                pData.pressEventCamera,
                out pos
            ))
            {
    
    
                // 进行射线检测是否碰到怪物
                CheckRayToEnemy();
            }

            yield return null;
        }
    }
    Enemy hitEnemy;//射线检测到的敌人脚本
    private void CheckRayToEnemy()
    {
    
    
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 10000, LayerMask.GetMask("Enemy")))
        {
    
    
            hitEnemy = hit.transform.GetComponent<Enemy>();
            hitEnemy.OnSelect();//选中
                                //如果按下鼠标左键使用攻击卡
            if (Input.GetMouseButtonDown(0))
            {
    
    
                //关闭所有协同程序
                StopAllCoroutines();
                //鼠标显示
                Cursor.visible = true;
                if (TryUse() == true)
                {
    
    
                    //播放特效
                    PlayEffect(hitEnemy.transform.position);
                    //打击音效
                    AudioManager.Instance.PlayEffect("Effect/sword");
                    //敌人受伤
                    int val = int.Parse(data["Arg0"]);
                    hitEnemy.Hit(val);
                }
                //敌人未选中
                hitEnemy.OnUnSelect();
                //设置敌人脚本null
                hitEnemy = null;
            }
        }
        else
        {
    
    
            //未射到怪物
            if (hitEnemy != null)
            {
    
    
                hitEnemy.OnUnSelect();
                hitEnemy = null;
            }

        }

    }
}

Run the effect, remember to change the layer of the monster to Enemy
insert image description here

23. Curve effect

Line UI Screenplay

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;

public class LineUI : UIBase
{
    
    
    //设置开始位置
    public void SetStartPos(Vector2 pos)
    {
    
    
        transform.GetChild(0).GetComponent<RectTransform>().anchoredPosition = pos;
    }

    //设置终点位置
    public void SetEndPos(Vector2 pos)
    {
    
    

        transform.GetChild(transform.childCount - 1).GetComponent<RectTransform>().anchoredPosition = pos;
        //开始点
        Vector3 startPos = transform.GetChild(0).GetComponent<RectTransform>().anchoredPosition;
        //终点
        Vector3 endPos = pos;
        //中点
        Vector3 midPos = Vector3.zero;
        midPos.y = (startPos.y + endPos.y) * 0.5f;
        midPos.x = startPos.x;
        //计算开始点跟终点的方向
        Vector3 dir = (endPos - startPos).normalized;
        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;//弧度转角度
        //设置终点角度
        transform.GetChild(transform.childCount - 1).eulerAngles = new Vector3(0, 0, angle - 90);
        for (int i = transform.childCount - 1; i >= 0; i--)
        {
    
    
            transform.GetChild(i).GetComponent<RectTransform>().anchoredPosition = GetBezier(startPos, midPos, endPos, i / (float)transform.childCount);
            if (i != transform.childCount - 1)
            {
    
    
                dir = (transform.GetChild(i + 1).GetComponent<RectTransform>().anchoredPosition - transform.GetChild(i).GetComponent<RectTransform>().anchoredPosition).normalized;
                angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
                transform.GetChild(i).eulerAngles = new Vector3(0, 0, angle - 90);
            }
        }
    }
    
    //贝塞尔曲线
    public Vector3 GetBezier(Vector3 start, Vector3 mid, Vector3 end, float t)
    {
    
    
        return (1f - t) * (1f - t) * start + 2.0f * t * (1.0f - t) * mid + t * t * end;
    }
}

AttackCardItem calls
insert image description here

insert image description here
insert image description here

Effect
insert image description here

Twenty-four, switch the enemy round

Modify the FightUI code of the battle interface, bind the end event and delete all cards

private void Awake()
{
    
    
     //结束回合按钮,绑定点击事件
     transform.Find("turnBtn").GetComponent<Button>().onClick.AddListener(onChangeTurnBtn);
 }
 
//玩家回合结束,切换到敌人回合
private void onChangeTurnBtn()
{
    
    
    //只有玩家回合才能切换
    if (FightManager.Instance.fightUnit is Fight_PlayerTurn)  FightManager.Instance.ChangeType(FightType.Enemy);
}

//删除所有卡牌
public void RemoveAllCards()
{
    
    
    for (int i = cardItemList.Count - 1; i > 0; i--)
    {
    
    
        RemoveCard(cardItemList[i]);
    }
}

The enemy turn Fight_EnemyTurn initialization call deletes all cards and pop-up prompts

public override void Init()
{
    
    
    //删除所有卡牌
    UIManager.Instance.GetUI<FightUI>("FightUI").RemoveAllCards();
    //显示敌人回合提示
    UIManager.Instance.ShowTip("敌人回合", Color.red, delegate ()
    {
    
    
        Debug.Log("执行敌人ai");
    });
}

Effect
insert image description here

25. The Logic of Enemy Behavior

The battle manager FightManager adds a new way for players to be attacked

//玩家受击
public void GetPlayerHit(int hit)
{
    
    
    //扣护盾
    if (DefenseCount > hit)
    {
    
    
        DefenseCount -= hit;
    } else {
    
    
        hit = hit - DefenseCount;
        DefenseCount = 0;
        CurHp -= hit;
        if (CurHp <= 0)
        {
    
    
            CurHp = 0;
            //切换到游戏失败状态
            ChangeType(FightType.Fail);
        }

    }
    // 更新界面
    UIManager.Instance.GetUI<FightUI>("FightUI").UpdateHp();
    UIManager.Instance.GetUI<FightUI>("FightUI").UpdateDefense();
}

Enemy script Enemy modification

//隐藏怪物头上的行动标志
public void HideAction()
{
    
    
    attackTf.gameObject.SetActive(false);
    defendTf.gameObject.SetActive(false);
}

//执行敌人行动
public IEnumerator DoAction()
{
    
    
    HideAction();
    //播放对应的动画(可以配置到excel表这里都默认播放攻击)
    ani.Play("attack");
    //等待某一时间的后执行对应的行为(也可以配置到excel表)
    yield return new WaitForSeconds(0.5f);//这里我写死了
    switch (type)
    {
    
    
        case ActionType.None:
            break;
        case ActionType.Defend:
            // 加防御
            Defend += 1;
            UpdateDefend();
            //可以播放对应的特效
            break;
        case ActionType.Attack:
            // 玩家扣血
            FightManager.Instance.GetPlayerHit(Attack);
            //摄像机可以抖一抖
            Camera.main.DOShakePosition(0.1f, 0.2f, 5, 45);
            break;
    }
    //等待动画播放完(这里的时长也可以配置)
    yield return new WaitForSeconds(1);
    //播放待机
    ani.Play("idle");
}

EnemyManeger added the behavior of executing living monsters

//执行活着的怪物的行为
public IEnumerator DoAllEnemyAction()
{
    
    
    for (int i = 0; i < enemyList.Count; i++)
    {
    
    
        yield return FightManager.Instance.StartCoroutine(enemyList[i].DoAction());
    }
    // 行动完后更新所有敌人行为
    for (int i = 0; i < enemyList.Count; i++)
    {
    
    
        enemyList[i].SetRandomAction();

    }
    // 切换到玩家回合
    FightManager.Instance.ChangeType(FightType.Player);
}

Modified the behavior of Fight_EnemyTurn calling alive monsters

public override void Init()
{
    
    
     //删除所有卡牌
     UIManager.Instance.GetUI<FightUI>("FightUI").RemoveAllCards();
     //显示敌人回合提示
     UIManager.Instance.ShowTip("敌人回合", Color.red, delegate ()
     {
    
    
         FightManager.Instance.StartCoroutine(EnemyManeger.Instance.DoAllEnemyAction());
     });
 }

Effect
insert image description here

26. Game victory or end logic

Improve player turn Fight_PlayerTurn code

public override void Init()
{
    
    
    UIManager.Instance.ShowTip("玩家回合", Color.green, delegate ()
    {
    
    
        //回复行动力
        FightManager.Instance.CurPowerCount = 3;
        UIManager.Instance.GetUI<FightUI>("FightUI").UpdatePower();
        //卡堆己经没有卡重新初始化
        if (FightCardManager.Instance.HasCard() == false)
        {
    
    

            FightCardManager.Instance.Init();
            //更新弃卡堆数量
            UIManager.Instance.GetUI<FightUI>("FightUI").UpdateUsedCardCount();
        }
        //抽卡
        Debug.Log("抽卡");
        UIManager.Instance.GetUI<FightUI>("FightUI").CreateCardItem(4);//抽4张
        UIManager.Instance.GetUI<FightUI>("FightUI").UpdateCardItemPos();//更新卡牌位置

        //更新卡牌数
        UIManager.Instance.GetUI<FightUI>("FightUI").UpdateCardCount();
    });
}

Game failure Fight_Fail code

public override void Init()
{
    
    
    Debug.Log("失败了");
    FightManager.Instance.StopAllCoroutines();
    //显失败界面石到这里的小伙伴可以自已作
}

Game Win Fight_Win Code

public override void Init() {
    
    
   Debug.Log("游戏胜利");
    //何以显示结算界面预制体有了能看到这里的小伙伴应该可以自己补上了
}

Enemy Manager EnemyManeger kills all monsters

//移除敌人
public void DeleteEnemy(Enemy enemy)
{
    
    
    enemyList.Remove(enemy);

    //击杀所有怪物的判断
    if (enemyList.Count == 0)
    {
    
    
        FightManager.Instance.ChangeType(FightType.Win);
    }
}

Effect
insert image description here

final effect

insert image description here

source code

What source code do you want, give me a good look, study hard

reference

【Video】https://www.bilibili.com/video/BV1eF41177hu/

end

Gifts of roses, hand a fragrance! If the content of the article is helpful to you, please don't be stingy with yours 点赞评论和关注, so that I can receive feedback as soon as possible. Every time you write 支持is the biggest motivation for me to continue to create. Of course, if you find something in the article 存在错误or something 更好的解决方法, you are welcome to comment and private message me!

Well, I am 向宇, https://xiangyu.blog.csdn.net

A developer who worked silently in a small company, out of hobbies, recently began to study unity by himself. If you encounter any problems, you are also welcome to comment and private message me. Although I may not necessarily know some problems, I will check the information of all parties and try to give the best suggestions. I hope it can help more people who want to learn programming People, encourage each other~
insert image description here

Guess you like

Origin blog.csdn.net/qq_36303853/article/details/132591577