文章目录
- 本节最终效果
- 前言
- 能力升级系统
- 绘制升级按钮
- 武器升级
- 道具升级
- 治疗物品效果
- 双手放置武器
- 控制武器移动转向排序
- 默认先隐藏武器,去除默认的武器精灵图片
- 数据联动
- 完善升级界面
- 控制窗口开启关闭
- 时间控制,升级暂停游戏
- 每次升级随机获取属性项目
- 控制等级上限
- 参考
- 源码
- 完结
本节最终效果
前言
本节紧跟着上一篇,主要实现能力升级系统。
能力升级系统
新增ItemData
[CreateAssetMenu(fileName = "Item", menuName = "Scriptable Object/ItemData")]
public class ItemData : ScriptableObject
{
public enum ItemType { Melee, Range, Glove, Shoe, Heal } // 物品类型枚举
[Header("#Main Info")]
public ItemType itemType; // 物品类型
public int itemId; // 物品ID
public string itemName; // 物品名称
public string itemDesc; // 物品描述
public Sprite itemIcon; // 物品图标
[Header("#Level Data")]
public float baseDamage; // 基础伤害
public int baseCount; // 基础数量
public float[] damages; // 不同等级的伤害数组
public int[] counts; // 不同等级的数量数组
[Header("#Weapon")]
public GameObject projectile; // 投射物对象
}
配置各种物品
绘制升级按钮
绘制UI按钮,只是用于测试
新增Item,该类的作用是管理物品的显示和交互,以便在游戏中方便地使用和管理各种物品。
public class Item : MonoBehaviour
{
// 物品数据,由其他地方赋值
public ItemData data;
// 物品等级
public int level;
// 引用武器组件
public Weapon weapon;
// 物品图标
Image icon;
// 物品等级文本
Text textLevel;
void Awake()
{
// 获取子物体中的Image组件,并将其赋值给icon变量
icon = GetComponentsInChildren<Image>()[1];
// 设置icon的sprite为物品的图标
icon.sprite = data.itemIcon;
// 获取子物体中的Text组件,并将其赋值给texts数组
Text[] texts = GetComponentsInChildren<Text>();
// 将texts数组中的第一个元素赋值给textLevel变量
textLevel = texts[0];
}
// LateUpdate方法,在Update之后调用
// 通常在此方法中更新UI
void LateUpdate()
{
// 更新物品等级文本的内容
textLevel.text = "Lv." + (level + 1);
}
}
挂载脚本,配置参数
效果
修改Item,定义点击事件
// 当点击物品时调用的方法
public void OnClick()
{
// 根据物品类型进行不同的处理
switch (data.itemType)
{
// 如果是近战武器或远程武器
case ItemData.ItemType.Melee:
case ItemData.ItemType.Range:
// 这里可以添加处理近战武器和远程武器的逻辑
break;
// 如果是手套
case ItemData.ItemType.Glove:
// 这里可以添加处理手套的逻辑
break;
// 如果是鞋子
case ItemData.ItemType.Shoe:
// 这里可以添加处理鞋子的逻辑
break;
// 如果是治疗物品
case ItemData.ItemType.Heal:
// 这里可以添加处理治疗物品的逻辑
break;
}
// 物品等级加1
level++;
// 如果等级等于物品伤害数组的长度
if (level == data.damages.Length)
{
// 获取Button组件,并将其交互状态设置为false,即不可交互
GetComponent<Button>().interactable = false;
}
}
绑定点击事件
效果
武器升级
修改Weapon
void Awake()
{
player = GameManager.instance.player;
// Init(); // 初始化武器属性
}
void Update()
{
switch (id)
{
//。。。
if (timer > speed && count > 0)
{
timer = 0f;
Fire();
}
break;
}
}
/// <summary>
/// 初始化武器/子弹属性
/// </summary>
public void Init(ItemData data)
{
name = "Weapon " + data.itemId; // 设置物品名称
transform.parent = player.transform; // 设置物品的父级为玩家对象
transform.localPosition = Vector3.zero; // 设置物品在父级坐标系下的本地位置为(0, 0, 0)
id = data.itemId; // 设置物品ID
damage = data.baseDamage; // 设置物品基础伤害
count = data.baseCount; // 设置物品基础数量
for (int index = 0; index < GameManager.instance.pool.prefabs.Length; index++)
{
if (data.projectile == GameManager.instance.pool.prefabs[index])
{
prefabId = index; // 设置投射物的预制体ID
break;
}
}
//。。。
}
修改Item
// 如果是近战武器或远程武器
case ItemData.ItemType.Melee:
case ItemData.ItemType.Range:
// 这里可以添加处理近战武器和远程武器的逻辑
if(level == 0){
//开始给玩家一个武器
GameObject newWeapon = new GameObject();
weapon = newWeapon.AddComponent<Weapon>();
weapon.Init(data);
}else{
float nextDamage = data.baseDamage;
int nextCount = 0;
nextDamage += data.baseDamage * data.damages[level];
nextCount += data.counts[level];
weapon.LevelUp(nextDamage, nextCount);
}
break;
效果
道具升级
新增Gear,用于处理道具的属性和应用。
public class Gear : MonoBehaviour
{
public ItemData.ItemType type; // 物品类型
public float rate; // 比率
public void Init(ItemData data)
{
// 基本设置
name = "Gear " + data.itemId; // 设置物品名称
transform.parent = GameManager.instance.player.transform; // 将物品的父物体设置为玩家对象
transform.localPosition = Vector3.zero; // 将物品的本地坐标设置为零向量
// 属性设置
type = data.itemType; // 设置物品类型
rate = data.damages[0]; // 选择第一个等级的伤害作为初始值
ApplyGear(); // 应用物品属性
}
public void LevelUp(float rate)
{
this.rate = rate; // 更新比率
ApplyGear(); // 应用物品属性
}
void ApplyGear()
{
switch (type)
{
case ItemData.ItemType.Glove:
RateUp(); // 手套类型的物品增加攻击速率
break;
case ItemData.ItemType.Shoe:
SpeedUp(); // 鞋子类型的物品增加玩家速度
break;
}
}
void RateUp()
{
Weapon[] weapons = transform.parent.GetComponentsInChildren<Weapon>(); // 获取所有子物体中的武器组件
foreach (Weapon weapon in weapons)
{
switch (weapon.id)
{
case 0:
weapon.speed = 150 * (1.0f + rate); // 增加150%速度
break;
default:
weapon.speed = 0.5f * (1.0f + rate); // 增加50%速度
break;
}
}
}
void SpeedUp()
{
float speed = 3.0f; // 默认玩家速度
GameManager.instance.player.speed = speed * (1.0f + rate); // 根据rate调整玩家速度
}
}
修改Item
public Gear gear;
// 如果是手套/鞋子
case ItemData.ItemType.Glove:
case ItemData.ItemType.Shoe:
// 这里可以添加处理手套/鞋子的逻辑
if (level == 0)
{
GameObject newGear = new GameObject();
gear = newGear.AddComponent<Gear>();
gear.Init(data);
}
else
{
float nextRate = data.damages[level];
gear.LevelUp(nextRate);
}
break;
运行效果,点击手套和鞋子buff在人物会生成对应属性,且人物增加攻速和移速效果
治疗物品效果
修改Item
// 如果是治疗物品
case ItemData.ItemType.Heal:
// 这里可以添加处理治疗物品的逻辑
GameManager.instance.health = GameManager.instance.maxHealth;
break;
双手放置武器
控制武器移动转向排序
新增Hand,控制左右手翻转位置,具体的位置数据可以自己按情况修改
public class Hand : MonoBehaviour
{
public bool isLeft; // 是否是左手
public SpriteRenderer spriter; // 手的sprite renderer组件
SpriteRenderer player; // 玩家的sprite renderer组件
Quaternion rightRot = Quaternion.Euler(0, 0, -25);
Quaternion rightRotReverse = Quaternion.Euler(0, 0, 25);
Vector3 leftPos = new Vector3(0.4f, -0.2f, 0);
Vector3 leftPosReverse = new Vector3(0.1f, -0.2f, 0);
void Awake()
{
player = GetComponentsInParent<SpriteRenderer>()[1]; // 获取玩家的sprite renderer组件
}
void LateUpdate()
{
bool isReverse = player.flipX; // 判断玩家是否水平翻转
if (isLeft)
{
// 处理左手
spriter.flipX = isReverse;
spriter.sortingOrder = isReverse ? 6 : 4;
transform.localPosition = !isReverse ? leftPos : leftPosReverse;
}
else
{
// 处理右手
transform.localRotation = isReverse ? rightRotReverse : rightRot;
spriter.flipX = isReverse;
spriter.sortingOrder = isReverse ? 4 : 6;
}
}
}
左右手挂载脚本
效果
默认先隐藏武器,去除默认的武器精灵图片
修改ItemData
public Sprite hand;
物品数据,绑定对应的武器精灵图片数据
数据联动
修改Player
public Hand[] hands;
hands = GetComponentsInChildren<Hand>();
修改Weapon
public void Init(ItemData data)
{
//。。。
Hand hand = player.hands[(int)data.itemType];
hand.spriter.sprite = data.hand;
}
效果,现在开启不同的能力,会在左右手绑定对应的武器
完善升级界面
绘制升级UI
配置道具物品描述
修改Item,注意删除了原来的lateupdate方法
TextMeshProUGUI textName;
TextMeshProUGUI textDesc;
void Awake()
{
// 。。。
textLevel = texts[0];
textName = texts[1];
textDesc = texts[2];
textName.text = data.itemName;
}
void OnEnable()
{
textLevel.text = "Lv." + (level + 1);
switch (data.itemType)
{
case ItemData.ItemType.Melee:
case ItemData.ItemType.Range:
textDesc.text = string.Format(data.itemDesc, data.damages[level] * 100, data.counts[level]);
break;
case ItemData.ItemType.Glove:
case ItemData.ItemType.Shoe:
textDesc.text = string.Format(data.itemDesc, data.damages[level] * 100);
break;
default:
textDesc.text = string.Format(data.itemDesc);
break;
}
}
和之前一样挂载,配置参数
运行效果
控制窗口开启关闭
新增LevelUp代码
public class LevelUp : MonoBehaviour
{
RectTransform rect; // 用于存储RectTransform组件的引用
void Awake()
{
rect = GetComponent<RectTransform>(); // 获取LevelUp对象上的RectTransform组件
}
/// <summary>
/// 显示LevelUp界面
/// </summary>
public void Show()
{
rect.localScale = Vector3.one; // 将界面的缩放设置为(1, 1, 1),即正常大小
}
/// <summary>
/// 隐藏LevelUp界面
/// </summary>
public void Hide()
{
rect.localScale = Vector3.zero; // 将界面的缩放设置为(0, 0, 0),即隐藏界面
}
}
配置点击事件
修改GameManager,人物升级开启面板
public LevelUp uiLevelUp;
//加经验和升级
public void GetExp(){
exp++;
if(exp == nextExp[level]){
level ++;
exp = 0;
uiLevelUp.Show();
}
}
修改LevelUp,默认给主角一个武器
Item[] items;
items = GetComponentsInChildren<Item>(true);
public void Select(int index){
items[index].OnClick();
}
修改GameManager
private void Start() {
//...
uiLevelUp.Select(0);
}
效果
时间控制,升级暂停游戏
我们希望升级进行属性选择时,可以暂停游戏
修改GameManager
public bool isLive;
public void Stop()
{
isLive = false;
Time.timeScale = 0;
}
public void Resume()
{
isLive = true;
Time.timeScale = 1;
}
修改LevelUp
public void Show()
{
rect.localScale = Vector3.one;
GameManager.instance.Stop();
}
public void Hide()
{
rect.localScale = Vector3.zero;
GameManager.instance.Resume();
}
效果
每次升级随机获取属性项目
修改levelUp
public void Show()
{
Next();
//。。。
}
void Next()
{
// 1. 隐藏所有物品
foreach (Item item in items)
{
item.gameObject.SetActive(false);
}
// 2. 随机选择三个不同的索引
int[] ran = new int[3];
while (true)
{
ran[0] = Random.Range(0, items.Length);
ran[1] = Random.Range(0, items.Length);
ran[2] = Random.Range(0, items.Length);
if (ran[0] != ran[1] && ran[1] != ran[2] && ran[0] != ran[2])
{
break;
}
}
// 3. 根据随机索引显示对应的物品
for (int index = 0; index < ran.Length; index++)
{
Item ranItem = items[ran[index]];
if (ranItem.level == ranItem.data.damages.Length)
{
//保留最后恢复生命效果
items[4].gameObject.SetActive(true);
}
else
{
ranItem.gameObject.SetActive(true);
}
}
}
效果
控制等级上限
修改GameManager
//加经验和升级
public void GetExp()
{
exp++;
if (exp == nextExp[Mathf.Min(level, nextExp.Length -1)])
{
level++;
exp = 0;
uiLevelUp.Show();
}
}
修改HUD
case InfoType.Exp:
// 处理经验信息逻辑
float curExp = GameManager.instance.exp;
float maxExp = GameManager.instance.nextExp[Mathf.Min(GameManager.instance.level, GameManager.instance.nextExp.Length - 1)];
mySlider.value = curExp / maxExp;
break;
为了方便测试,可以把升级经验设置少点
效果
参考
【视频】https://www.youtube.com/watch?v=MmW166cHj54&list=PLO-mt5Iu5TeZF8xMHqtT_DhAPKmjF6i3x
源码
源码在最后一节
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~