最终效果
系列导航
文章目录
- 最终效果
- 系列导航
- 前言
- 选择植物
- 简单绘制选择植物面板
- 渲染卡牌数据
- 点击选中和移除卡牌
- 修改UI
- 代码控制
- 开始战斗
- 源码
- 结束语
前言
本节主要实现添加选择植物功能
选择植物
简单绘制选择植物面板
每个卡牌插槽和前面植物卡牌类似,并配置为预制体
渲染卡牌数据
新增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();
}
配置
效果测试,一切正常
源码
源码不出意外的话我会放在最后一节
结束语
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~