介绍
简单制作植物大战僵尸游戏。
协程实现各种相机动画
卡片填充方式修改为:“已填充”,实现植物恢复
事件系统实现拖拽植物
植物子弹实现对象池
掉落阳光
这段代码是一个Unity游戏中的太阳类(Sun),实现了天上掉落的太阳落下的功能。具体实现如下:
isSkySun:bool 类型的变量,用于标记太阳是否是天上掉落的。
TargetY:float 类型的变量,表示太阳落到的目标位置。
speed:float 类型的变量,表示太阳下落的速度。
InitSkySun 方法:用于初始化天上掉落的太阳,传入太阳的初始位置(x, y)和目标位置 TargetY。
Update 方法:在每一帧更新时,如果太阳是天上掉落的且未被点击(isSkySun 和 isClick 都为 true),则让太阳向下移动。如果太阳到达目标位置 TargetY,则销毁太阳。注意,isClick 变量在该代码中未被定义。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
//太阳 :天上掉落 太阳花掉落
/// </summary>
public class Sun : MonoBehaviour
{
//是否是天上掉落的
private bool isSkySun;
//天空中的太阳下落的目标点
private float TargetY;
//速度
private float speed = 1;
private void Start()
{
//初始化
sunNum = GameObject.Find("SunNum");
}
//初始化天上的太阳 初始化开始的位置 及TargetY
public void InitSkySun(float x, float y, float targetY)
{
//设置初始位置和目标位置
transform.position = new Vector3(x, y, 0);
TargetY = targetY;
isSkySun = true;
}
private void Update()
{
if (isSkySun == true)
{
// 天空下落的太阳 过程中 未被点击
if (isClick == false)
{
//如果太阳未被点击,则让太阳向下移动
if (transform.position.y > TargetY)
{
transform.Translate(new Vector3(0, -1, 0) * Time.deltaTime * speed);
}
else
{
//当太阳到达目标位置时,销毁太阳
Destroy(gameObject, 3f);
}
}
}
}
}
InitSkySun 方法用于初始化天上掉落的太阳,传入太阳的初始位置(x, y)和目标位置 TargetY。Update 方法中,如果太阳未被点击,太阳会一直向下移动,直到到达目标位置 TargetY,然后销毁太阳。
卡片恢复透明度
在植物卡片上叠加一个灰色卡片,设置透明度。
设置图像类型为“已填充”
private void Update()
{
//计时 更新UI
timer += Time.deltaTime;
UpdateProgress();
UpdateBg();
}
private void UpdateProgress()
{
//计算相应的百分比
float per = Mathf.Clamp(timer / coolTime, 0, 1);
image.fillAmount = 1 - per;
}
private void UpdateBg()
{
//1.是否冷却 fillAmount=0
//2.如果当前拥有的阳光 比消耗的阳光多
if (image.fillAmount == 0 && GameMgr.Instance.GetSun() >= costSun)
{
bg.SetActive(false);
}
else
{
bg.SetActive(true);
}
}
拖拽卡片到方格子上生成植物
这段代码定义了一个名为"Card"的类,这个类继承了三个接口IBeginDragHandler、IDragHandler、IEndDragHandler。这个类是用于控制游戏中卡牌的行为的,其中包括冷却时间、花费阳光数量、要创建的植物物体、计时器、当前物体等属性。这个类还包括一些方法,如UpdateProgress()、UpdateBg()、ScreenToWorld()、LoadByName()、OnBeginDrag()、OnDrag()和OnEndDrag()等方法,用于更新UI、加载卡牌、生成物体、让物体跟随鼠标、让物体生成在点击到的格子上等。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
/// <summary>
/// 卡片
/// </summary>
public class Card : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
//冷却时间
public float coolTime = 4;
//计时器
private float timer;
private Image image;
private GameObject bg;
//花费的阳光
public int costSun;
//要创建的植物物体
public GameObject plantPrefab;
//当前的物体
public GameObject curObj;
private void Start()
{
//初始化
costSun = 50;
timer = 0;
image = transform.Find("progress").GetComponent<Image>();
bg = transform.Find("bg").gameObject;
//string[] cardName = name.Split("_");
//string resPath = "Prefabs/" + cardName[1];
//Debug.Log(resPath);
LoadByName(gameObject.name);
}
private void Update()
{
//计时 更新UI
timer += Time.deltaTime;
UpdateProgress();
UpdateBg();
}
private void UpdateProgress()
{
//计算相应的百分比
float per = Mathf.Clamp(timer / coolTime, 0, 1);
image.fillAmount = 1 - per;
}
private void UpdateBg()
{
//1.是否冷却 fillAmount=0
//2.如果当前拥有的阳光 比消耗的阳光多
if (image.fillAmount == 0 && GameMgr.Instance.GetSun() >= costSun)
{
bg.SetActive(false);
}
else
{
bg.SetActive(true);
}
}
//屏幕坐标 转 z为0的世界坐标
public Vector3 ScreenToWorld(Vector3 pos)
{
Vector3 po = Camera.main.ScreenToWorldPoint(pos);
//确保pos 为0;
Vector3 final = new Vector3(po.x, po.y, 0);
return final;
}
根据名字 加载 物体
//public void LoadByName(string name)
//{
// // 切割字符串
// string[] cardName = name.Split("_");
// //加载预制体
// string resPath = "Prefabs/" + cardName[1];
// plantPrefab = Resources.Load<GameObject>(resPath);
//}
public void LoadByName(string name)
{
// 切割字符串
// string[] cardName = name.Split("_");
string[] cardName = name.Split('_');
if (cardName.Length > 1)
{
// 加载预制体
string resPath = "Prefabs/" + cardName[1];
plantPrefab = Resources.Load<GameObject>(resPath);
}
else
{
// 处理拆分结果不正确的情况
Debug.LogError("Invalid name format: " + name);
}
}
//生成一个物体 出现在鼠标所对应的世界处坐标
public void OnBeginDrag(PointerEventData eventData)
{
// Debug.Log(eventData.position);
// eventData.position 不是 世界坐标 做转换
// unity 坐标系 1. 世界坐标系 2.屏幕坐标系 3.视口坐标 ***
//如果黑色背景激活
if (bg.activeSelf)
{
return;
}
curObj = Instantiate(plantPrefab);
curObj.transform.position = ScreenToWorld(eventData.position);
}
// 让物体 跟随 着鼠标
public void OnDrag(PointerEventData eventData)
{
if (curObj != null)
{
curObj.transform.position = ScreenToWorld(eventData.position);
}
}
//让物体生成在点击到的格子上
public void OnEndDrag(PointerEventData eventData)
{
//计时器重置
timer = 0;
//UI更新
GameMgr.Instance.ChangSun(-costSun);
UIMgr.Instance.ChangeUICount(GameMgr.Instance.GetSun());
//开始正式种植
if (curObj == null) { return; }
Collider2D[] col = Physics2D.OverlapPointAll(ScreenToWorld(eventData.position));
// 遍历所有的格子
for (int i = 0; i < col.Length; i++)
{
//1 是格子
//2有没有植物
if (col[i].tag == "Land" && col[i].gameObject.transform.childCount == 0)
{
curObj.transform.position = col[i].transform.position;
curObj.transform.SetParent(col[i].transform);
//这里我们生成的是游戏物体 拖动时会调用方法
//会出现 拖动时发射子弹的bug
//设置isOnGround 为true
//以豌豆为例 后续会提取Plant 类
//Peashooter obj = curObj.GetComponent<Peashooter>();
//if (obj != null)
//{
// obj.isOnGround = true;
//}
Plant obj = curObj.GetComponent<Plant>();
if (obj != null)
{
obj.isOnGround = true;
}
curObj = null;
return;
}
}
// 如果没有合适的格子 curob还在
if (curObj != null)
{
GameObject.Destroy(curObj);
curObj = null;
}
}
}
僵尸生成器
僵尸放在一个链表中
Awake(): 在对象被创建时调用的方法,将当前对象赋值给Instance,实现单例模式。
CreateZombine(): 创建僵尸的方法。实例化僵尸预制体,随机选择生成点,设置生成点的父对象、位置和层级。将生成的僵尸添加到存储的僵尸列表中。
AddZombine(Zombine zom): 将僵尸添加到存储的僵尸列表中。
RemoveZombine(Zombine zom): 从存储的僵尸列表中移除僵尸。
CreateStartZombie(): 创建初始僵尸的方法。循环3次,实例化僵尸预制体,随机选择生成点,设置生成点的父对象、位置和层级。将生成的僵尸添加到正在展示的僵尸列表中,将其动画的播放速度设置为0,将其isWalk标志设为false。
DestoryZombieShow(): 销毁正在展示的僵尸的方法。遍历正在展示的僵尸列表,销毁每个僵尸的游戏对象。
Start(): Unity的内置方法,在脚本启用时调用。调用CreateByTime()方法。
CreateByTime(): 按时间创建僵尸的方法。使用协程CreateSomeZombie(),在一定条件下循环生成僵尸。
CreateSomeZombie(): 使用假数据创建一些僵尸的协程方法。在一定条件下循环生成僵尸。根据刷新标志isRefresh的值,生成一定数量的僵尸,并在每次生成之间等待一定的时间间隔。
StopCreateZombie(): 停止创建僵尸的方法。停止所有的协程。
ClearZombie(): 清除所有僵尸的方法。将刷新标志isRefresh设为false,并销毁存储的所有僵尸的游戏对象。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 僵尸管理
/// </summary>
public class ZombieMgr : MonoBehaviour
{
public static ZombieMgr Instance;
public GameObject zombiePrefab;
//生成点列表
public Transform[] bornPoint;
//存储的列表
public List<Zombine> zombies = new List<Zombine>();
public List<Zombine> zombineShow = new List<Zombine>();
private int layerIndex = 0;
//是否刷新
public bool isRefresh = false;
private void Awake()
{
Instance = this;
}
public void CreateZombine()
{
//生成物体
GameObject go = GameObject.Instantiate(zombiePrefab);
//随机坐标
int index = Random.Range(0, 5);//0 1 2 3 4
go.transform.parent = bornPoint[index];
go.transform.localPosition = Vector3.zero;
//设置层级
layerIndex += 1;
go.GetComponent<SpriteRenderer>().sortingOrder = layerIndex;
AddZombine(go.GetComponent<Zombine>());
}
public void AddZombine(Zombine zom)
{
zombies.Add(zom);
}
public void RemoveZombine(Zombine zom)
{
zombies.Remove(zom);
}
public void CreateStartZombie()
{
for (int i = 0; i < 3; i++)
{
GameObject go = GameObject.Instantiate(zombiePrefab);
//随机坐标
int index = Random.Range(0, 5);//0 1 2 3 4
go.transform.parent = bornPoint[index];
go.transform.localPosition = Vector3.zero;
Zombine zombine = go.GetComponent<Zombine>();
zombineShow.Add(zombine);
go.GetComponent<Animator>().speed = 0;
zombine.isWalk = false;
}
}
public void DestoryZombieShow()
{
for (int i = 0; i < zombineShow.Count; i++)
{
GameObject.Destroy(zombineShow[i].gameObject);
}
}
public void Start()
{
CreateByTime();
}
public void CreateByTime()
{
StartCoroutine(CreateSomeZombie());
}
//使用假数据
private IEnumerator CreateSomeZombie()
{
while (layerIndex < 12)
{
//是否在刷
if (isRefresh == true)
{
int delay = Random.Range(2, 5);
yield return new WaitForSeconds(delay);
int randomNum = Random.Range(1, 4);
for (int i = 0; i < randomNum; i++)
{
CreateZombine();
}
}
yield return new WaitForSeconds(5);
}
yield return new WaitForSeconds(5);
StartCoroutine(CreateSomeZombie());
}
public void StopCreateZombie()
{
StopAllCoroutines();
}
public void ClearZombie()
{
isRefresh = false;
for (int i = 0; i < zombies.Count; i++)
{
GameObject.Destroy(zombies[i].gameObject);
}
//zombies.Clear();
}
}
子弹对象池
在Awake()函数中,将该脚本实例化为单例对象。
在Start()函数中,创建对象池,即实例化一定数量的子弹对象,将它们添加到对象池中,并将其设为未激活状态。
在GetPoolObject()函数中,从对象池中获取一个子弹对象,如果对象池中存在未被激活的子弹对象,则直接返回该对象,并将其设为激活状态;如果对象池中不存在未被激活的子弹对象,则创建一个新的子弹对象,将其添加到对象池中,并将其设为激活状态,最后返回该对象。文章来源:https://www.toymoban.com/news/detail-743359.html
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 子弹对象池 仅作为简单讲解 不涉及其他复杂操作 单例
/// </summary>
public class BulletPool : MonoBehaviour
{
public static BulletPool Instance;
//子弹预制体
public GameObject bulletPrefab;
//对象池容量
public int amount = 10;
// 物品列表
private List<GameObject> pool = new List<GameObject>();
private void Awake()
{
Instance = this;
}
private void Start()
{ //创建对象池的物体
for (int i = 0; i < amount; i++)
{
GameObject go = Instantiate(bulletPrefab);
//让物体失活
go.SetActive(false);
//添加到对象池
pool.Add(go);
}
}
//从对象池获取物体
public GameObject GetPoolObject()
{
for (int i = 0; i < pool.Count; i++)
{
//找出未被激活的物体 将其激活 并返回
if (!pool[i].activeInHierarchy)
{
pool[i].SetActive(true);
return pool[i];
}
}
//如果没有满足条件的物体 创建物体 添加到池中 激活 并返回
GameObject go = GameObject.Instantiate(bulletPrefab);
pool.Add(go);
go.SetActive(true);
return go;
}
}
源码
https://wwez.lanzoul.com/iSCMm0yyk99c文章来源地址https://www.toymoban.com/news/detail-743359.html
到了这里,关于unity制作简单的植物大战僵尸的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!