前言
本节主要实现添加选择植物功能
选择植物
简单绘制选择植物面板
每个卡牌插槽和前面植物卡牌类似,并配置为预制体
渲染卡牌数据
新增ScriptableObject,配置植物列表卡牌数据
[CreateAssetMenu(fileName = "CardData", menuName = "CardData", order = 0)] public class CardData : ScriptableObject { // 存储卡牌数据的列表 public List<CardItem> cardItemDataList = new List<CardItem>(); } // 表示单个关卡的数据 [System.Serializable] public class CardItem { public string name; //名称 public float waitTime; //等待时间 public int useSun;//需要阳光 public GameObject prefab;//预制体 public Sprite sprite;//图片 }
配置
新增ChooseCardPanel,渲染植物列表卡牌数据
public class ChooseCardPanel : MonoBehaviour { public GameObject beforeCardPrefab; public CardData cardData; private void Start() { for (int i = 0; i < cardData.cardItemDataList.Count; i++) { GameObject beforeCard = Instantiate(beforeCardPrefab); beforeCard.transform.SetParent(transform, false); beforeCard.name = cardData.cardItemDataList[i].name; beforeCard.GetComponent<Image>().sprite = cardData.cardItemDataList[i].sprite; beforeCard.transform.Find("黑色进度").GetComponent<Image>().fillAmount = 0; beforeCard.transform.Find("黑色底图").gameObject.SetActive(false); Card card = beforeCard.GetComponent<Card>(); card.waitTime = cardData.cardItemDataList[i].waitTime; card.useSun = cardData.cardItemDataList[i].useSun; card.prefab = cardData.cardItemDataList[i].prefab; } } }
配置
运行效果,可以看到卡牌数据都渲染上去了
点击选中和移除卡牌
注意
:这里会使用DOTween实现动画效果,不会用的小伙伴可以查看我之前写的文章:【推荐100个unity插件之2】DoTween动画插件的安装和使用整合(最全)
修改UI
注意修改卡牌容器的顶点位置在左上
卡牌预制体轴心也在左上
选项卡牌面板顶点同样位置在左上
代码控制
这里改动比较大,我直接贴出代码
修改GameManager,新增字段用于判断是否开始游戏
public bool isStart;//是否开始游戏
ChooseCardPanel代码
public class ChooseCardPanel : MonoBehaviour { public static ChooseCardPanel Instance; public GameObject cardPrefab;//卡牌模板预制体 public CardData cardData;//所有卡牌数据 public GameObject useCardPanel;//选中的卡牌的对象父类 public List<GameObject> useCardList;//选中的卡牌 private void Awake() { Instance = this; } private void Start() { //渲染卡牌列表数据 for (int i = 0; i < cardData.cardItemDataList.Count; i++) { GameObject beforeCard = Instantiate(cardPrefab); beforeCard.transform.SetParent(transform, false); beforeCard.GetComponent<Card>().cardItem = cardData.cardItemDataList[i]; } } //添加卡牌 public void AddCard(GameObject go) { int curIndex = useCardList.Count; if (curIndex >= 8) { Debug.Log("已经选中的卡片超过最大数量"); return; } useCardList.Add(go); go.transform.SetParent(transform.root);//父级修改为当前对象所在的最顶层父对象,确保卡牌UI在最顶层显示 Card card = go.GetComponent<Card>(); card.isMoving = true; card.hasUse = true; // DoMove移动到目标位置 go.transform.DOMove(useCardPanel.transform.position, 0.8f).OnComplete( () => { go.transform.SetParent(useCardPanel.transform, false); //移动到其父对象的子物体列表的最前面 go.transform.SetAsFirstSibling(); card.isMoving = false; } ); } //移除卡牌 public void RemoveCard(GameObject go) { useCardList.Remove(go); go.transform.SetParent(transform.root);//父级修改为当前对象所在的最顶层父对象,确保卡牌UI在最顶层显示 Card card = go.GetComponent<Card>(); card.isMoving = true; card.hasUse = false; go.transform.DOMove(transform.position, 0.8f).OnComplete( () => { go.transform.SetParent(transform, false); //移动到其父对象的子物体列表的最前面 go.transform.SetAsFirstSibling(); card.isMoving = false; } ); } }
Card代码
public class Card : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler, IPointerClickHandler { [HideInInspector] public CardItem cardItem;//卡牌信息 [HideInInspector] public bool hasUse = false;//是否使用 [HideInInspector] public bool isMoving = false;//是否正在移动 private GameObject darkBg;//黑图 private Image image; private GameObject progressBar;//进度对象 private float waitTime; //等待时间 private int useSun;//需要阳光 private GameObject prefab;//预制体 public LayerMask layerMask;//检测图层 private GameObject thisObject; void Start() { darkBg = transform.Find("黑色底图").gameObject; progressBar = transform.Find("黑色进度").gameObject; image = progressBar.GetComponent<Image>(); Init(); } private void Init() { if (cardItem == null) { Debug.Log("找不到卡牌数据"); return; } darkBg.SetActive(false); image.fillAmount = 0; GetComponent<Image>().sprite = cardItem.sprite; gameObject.name = cardItem.name; waitTime = cardItem.waitTime; useSun = cardItem.useSun; prefab = cardItem.prefab; } void Update() { if(!GameManager.Instance.isStart) return; UpdateProgress(); UpdateDarkBg(); } void UpdateProgress() { image.fillAmount -= 1 / waitTime * Time.deltaTime; } void UpdateDarkBg() { // TODO 且需要阳光数>useSun if (image.fillAmount == 0 && GameManager.Instance.sunSum >= useSun) { darkBg.SetActive(false); } else { darkBg.SetActive(true); } } //开始拖拽 public void OnBeginDrag(PointerEventData eventData) { if(!GameManager.Instance.isStart) return; if (image.fillAmount != 0 || GameManager.Instance.sunSum < useSun) return; thisObject = Instantiate(prefab, transform.position, Quaternion.identity); //关闭运行 thisObject.GetComponent<Plants>().isOpen = false; //关闭碰撞 thisObject.GetComponent<Collider2D>().enabled = false; //关闭动画 thisObject.GetComponent<Animator>().enabled = false; } //拖拽中 public void OnDrag(PointerEventData eventData) { if (thisObject == null) return; //植物跟随鼠标 Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); thisObject.transform.position = new Vector2(mousePosition.x, mousePosition.y); // 将物体位置设置为鼠标位置 } //拖拽结束 public void OnEndDrag(PointerEventData eventData) { if (thisObject == null) return; Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); Vector2 mousePosition2D = new Vector2(mousePosition.x, mousePosition.y); RaycastHit2D hit = Physics2D.Raycast(mousePosition2D, Vector2.zero, Mathf.Infinity, layerMask);//鼠标“点检测”射线 if (hit.collider != null && hit.collider.transform.childCount == 0) { thisObject.transform.parent = hit.transform; thisObject.transform.localPosition = Vector2.one; //开始运行 thisObject.GetComponent<Plants>().isOpen = true; //开启碰撞 thisObject.GetComponent<Collider2D>().enabled = true; //开启动画 thisObject.GetComponent<Animator>().enabled = true; thisObject = null; //重置进度 progressBar.GetComponent<Image>().fillAmount = 1; //扣除阳光 GameManager.Instance.SetSunSum(-useSun); AudioManager.Instance.PlaySFX("种植"); } else { Destroy(thisObject); } } //点击事件 public void OnPointerClick(PointerEventData eventData) { if (isMoving) return; if(GameManager.Instance.isStart) return; if (hasUse) { ChooseCardPanel.Instance.RemoveCard(gameObject); } else { ChooseCardPanel.Instance.AddCard(gameObject); } } }
配置
效果
开始战斗
修改GameManager,定义开始游戏事件,记得去除原来生成阳光和生成僵尸的代码
//开始游戏 public void StartGame(){ AudioManager.Instance.PlayMusic("bgm1"); isStart = true; //顶部随机位置掉落阳光 InvokeRepeating("CreateSunDown", 10, 10); //生成僵尸 GenerateZombies.Instance.TableCreateZombie(); }
配置
效果测试,一切正常
源码
源码不出意外的话我会放在最后一节