使用ScriptableObject 打造一个卡牌存储器

上一节中我们了解了ScriptableObject的用法,这一节让我们来实现一个卡牌存储器。
使用了我很喜欢的游戏杀戮尖塔的设计和素材{{xieyanxiao}}。


设计理念

不知道大家有没有玩过杀戮尖塔,示例卡牌如下。
在这里插入图片描述
我们可以看到,一张卡牌包括名称消耗类型描述卡牌背景卡牌底图等部分构成,而且在游戏中,玩家的属性可以影响到卡牌的强度,如玩家的力量可以提升卡牌的伤害,玩家的敏捷可以提升玩家获得护甲的多少。
我遵从杀戮尖塔的设计,制作了如下的卡牌编辑器,实现了,数据可视化存储,并且让卡牌强度与玩家挂钩,使用这个存储器可以创建任意数据的卡牌。

设计思考

卡牌应当具有可加成的数值和不可加成的数值,在设计时我将用大写字母占位代表可加成数值,小写字母占位代表不可加成数值。
可加成数值需要从玩家Asset来提取数值。
不论是可加成还是不可加成占位,都将在使用时被替换成具体的数值。

效果预览

在这里插入图片描述
卡牌存储器从上自下可以分成材质,数据,处理三个部分。

  • 材质:存储卡牌的卡面,类型,品质等。
  • 数据:存储卡牌的名称,能力消耗,表达式,描述,基础数据,玩家加成数据等。
  • 处理:读入数据和加载入玩家数据。

代码实现

在项目中我试用了NaughtyAttributes来对检视面板数据做进一步处理,详细NaughtyAttributes可查看github

PlayerAsset.cs
using System.Collections.Generic;
using System.Linq;
using NaughtyAttributes;
using UnityEngine;

namespace Asset
{
    [CreateAssetMenu(fileName = "NEW PlayerAsset", menuName = "MyAsset/PlayerAsset", order = 0)]
    public class PlayerAsset : ScriptableObject
    {

        public int maxHp;
        public int currentHp;
        public int strength;
        public int agility;
        private static PlayerAsset _instance;
        public static PlayerAsset Instance
        {
            get
            {
                if (!_instance)
                {
                   _instance = Resources.FindObjectsOfTypeAll<PlayerAsset>().FirstOrDefault();;
                }
                if (_instance) return _instance;
                _instance= CreateInstance<PlayerAsset>();
                _instance.hideFlags = HideFlags.DontSave;

                return _instance;
            }
            private set => _instance = value;
        }

    }
}
CardAsset.cs
using System;
using System.Collections.Generic;
using System.Linq;
using NaughtyAttributes;
using UnityEngine;
using UnityEngine.Serialization;

namespace Asset
{
    /// <summary>
    /// 卡牌类型
    /// </summary>
    public enum CardType
    {
        Attack,
        Skill,
    }

    public enum CardQuality
    {
        Write,
        Blue,
        Yellow
    }

    [Serializable]
    public class DictData
    {
        public char key;
        public int data;

        public DictData(char key,int data)
        {
            this.key = key;
            this.data = data;
        }
    }

    [CreateAssetMenu(fileName = "NewCard", menuName = "MyAsset/CardAsset", order = 0)]
    public class CardAsset : ScriptableObject
    {
        [BoxGroup("材质")] public CardType cardType;
        [BoxGroup("材质")] public CardQuality cardQuality;
        [BoxGroup("材质")] [ShowAssetPreview()] public Sprite cardSprite;

        [BoxGroup("数据")] [MinValue(0), MaxValue(5), Tooltip("消耗")]
        public int expend;

        [BoxGroup("数据")] public string title;

        [BoxGroup("数据")] [ResizableTextArea] public string express;
        [BoxGroup("数据")] [ResizableTextArea] public string desc;

        [BoxGroup("数据"),Label("基础数据")] [ReorderableList] public DictData[] dictData;
        [BoxGroup("数据"),Label("玩家加成数据")] [ReorderableList] public List<DictData> dictAddData;
        /// <summary>
        /// 写入配置
        /// </summary>
        [Button("写入配置")]
        public void InitCardAsset()
        {
            desc = string.Empty;
            //字典方式
            foreach (var i in express)
            {
                var currChar = i + "";
                foreach (var t in dictData)
                {
                    if (!t.key.Equals(i)) continue;

                    var addValue = 0;    //加成值
                    //判断该数据是否需要被加成
                    if (t.key>='A'&&t.key<='Z')
                    {
                        addValue = dictAddData.FirstOrDefault(m => m.key == t.key).data;
                    }
                    currChar = t.data+addValue + "";
                    break;
                }

                desc += currChar;
            }
        }
        /// <summary>
        /// 更新卡牌
        /// </summary>
        [Button("写入玩家加成数据")]
        public void UpdateCard()
        {
            dictAddData.Clear();
            dictAddData.Add(new DictData('X',PlayerAsset.Instance.strength));
            dictAddData.Add(new DictData('Y',PlayerAsset.Instance.agility));
            //X-玩家力量 Y-玩家敏捷
 Debug.Log(PlayerAsset.Instance.maxHp+"\t"+PlayerAsset.Instance.currentHp+"\t"+PlayerAsset.Instance.strength);
            //重写
            InitCardAsset();
        }
    }
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 写一个卡牌游戏需要用到很多的编程技巧,这里是一个简单的示例: 首先,需要定义卡牌的结构体: ``` struct card { char suit; int value; }; ``` 然后,需要创建一个卡牌的数组: ``` #define MAX_CARDS 52 struct card deck[MAX_CARDS]; ``` 接着,需要初始化卡牌: ``` void init_deck() { int i; for (i = 0; i < MAX_CARDS; i++) { deck[i].suit = i / 13; deck[i].value = i % 13 + 1; } } ``` 最后,需要写一个函数来打印卡牌: ``` void print_card(int i) { switch (deck[i].value) { case 1: printf("Ace"); break; case 11: printf("Jack"); break; case 12: printf("Queen"); break; case 13: printf("King"); break; default: printf("%d", deck[i].value); } printf(" of "); switch (deck[i].suit) { case 0: printf("Clubs"); break; case 1: printf("Diamonds"); break; case 2: printf("Hearts"); break; case 3: printf("Spades"); break; } } ``` 希望这个示例能帮助您开始写您自己的卡牌游戏。 ### 回答2: 卡牌游戏是一种非常受欢迎的游戏类型,可以通过C语言来实现一个简单的卡牌游戏。我将解释如何使用C语言来编写一个基本的卡牌游戏。 首先,我们需要定义一些基本的数据结构来表示一副卡牌。我们可以使用结构体来表示每张卡的属性,例如花色和点数。每张卡可以用一个整数表示,其中高位表示花色,低位表示点数。 ```c typedef struct { int suit; // 花色 int rank; // 点数 } Card; ``` 接下来,我们可以定义一个数组来表示一副卡牌,并使用一个循环来初始化每一张卡。 ```c #define NUM_CARDS 52 Card deck[NUM_CARDS]; // 初始化卡牌 for (int i = 0; i < NUM_CARDS; i++) { deck[i].suit = i / 13; deck[i].rank = i % 13 + 1; } ``` 现在,我们可以实现一些简单的游戏规则,例如洗牌和发牌。 ```c // 洗牌 srand(time(NULL)); for (int i = 0; i < NUM_CARDS; i++) { int j = rand() % NUM_CARDS; Card temp = deck[i]; deck[i] = deck[j]; deck[j] = temp; } // 发牌 int players = 4; int handSize = 5; for (int i = 0; i < players; i++) { printf("Player %d: ", i+1); for (int j = 0; j < handSize; j++) { printf("(%d, %d) ", deck[i*handSize+j].suit, deck[i*handSize+j].rank); } printf("\n"); } ``` 这样,我们就可以实现一个简单的卡牌游戏。当然,这只是一个最基本的实现,你可以根据自己的需求来扩展和改进游戏规则和功能。 ### 回答3: 卡牌游戏是一种非常有趣的娱乐方式,可以通过使用C语言编写来实现。下面是一个基于C语言的简单卡牌游戏的示例。 首先,我们需要定义一副标准的扑克牌,这包括52张牌。我们可以使用数组来表示每张牌,每张牌可以用一个整数来表示其值和花色。 ``` int deck[52]; ``` 然后,我们需要初始化这副牌,可以使用一个函数来随机洗牌和分发牌。 ``` void initDeck() { // 随机洗牌 for (int i = 0; i < 52; i++) { deck[i] = i; } for (int i = 0; i < 52; i++) { int j = rand() % 52; // 交换牌的位置 int temp = deck[i]; deck[i] = deck[j]; deck[j] = temp; } } int dealCard() { // 分发一张牌 static int currentCardIndex = 0; return deck[currentCardIndex++]; } ``` 在游戏中,我们可以有两名玩家,每个玩家可以拥有几张牌。我们可以使用一个数组来表示每个玩家的手牌。 ``` int player1Hand[5]; int player2Hand[5]; ``` 我们可以添加一个函数来分发牌给玩家。 ``` void dealHands() { for (int i = 0; i < 5; i++) { player1Hand[i] = dealCard(); player2Hand[i] = dealCard(); } } ``` 最后,我们可以实现一些简单的游戏逻辑,并输出结果。 ``` void playGame() { initDeck(); dealHands(); // 在这里实现游戏逻辑,比较两个玩家的手牌,输出结果 } ``` 以上是一个简单的基于C语言的卡牌游戏的示例。通过定义牌的数组、洗牌和分发函数以及游戏逻辑,我们可以实现一个简单的卡牌游戏。当然,这只是一个开始,你可以在此基础上进一步添加规则和功能,使游戏更加复杂和有趣。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值