Unity RPG 黑暗之光 问题记录 下(64-110 技能、装备商店、头像栏、快捷栏、敌人攻击系统、玩家攻击系统)

黑暗之光

64-73技能系统

在这里插入图片描述

数据读取

数据 表

黄色枚举,红色没有的
在这里插入图片描述

数据 文本

在这里插入图片描述

数据 读取

背包时是itemList,读取属性时各有不同,无法统一,
这种方式是为了方便读取,所有需要的数据表都可以在DataHub上读取到,不用写重复写名字各异的单例,比如ItemTextAssetToList._intanse.itemList,
SkillIextAssetToList._intanse.skillList
现在写
DataHub._instance.itemList
DataHub._instance.skillList
//后面想想也挺麻烦的,因为GetItemById的方法还在xxxTextAssetToList里面
在这里插入图片描述

不用数组,列表存储数据子节点,是因为前面的名字,只看索引很麻烦
skillList也有些,但不知道为什么没显示出来,public是为了让其他访问到(其实想编辑器看不到,但又让其他类访问到(HideInInspector)
在这里插入图片描述

(问题) VS语法"有毒糖"

VS支持,Unity不支持,所以不支持
当写了5段switch,回去unity一百多个红色

            skill.effectType = propertyArray[4] switch{"Passive" => EffectType.Passive,"Buff" => EffectType.Buff,"MultiTarget" => EffectType.MultiTarget,"SingleTarget" => EffectType.SingleTarget,_ => throw new System.NotImplementedException()};

读取成功

   public override string ToString(){string str = "";str += "\t" + id;str += "\t" + name;str += "\t" + icon_name;str += "\t" + description;str += "\t" + coolTime;str += "\t" + applyType;str += "\t" + lv;str += "\t" + roleLv;str += "\t" + costMp;str += "\t" + effectProperty;str += "\t" + effectTarget;str += "\t" + effectTime;str += "\t" + effectType;str += "\t" + effectValue;str += "\t" + releaseDistance;return str;     }
        foreach (Skill skill in skillList){print(skill.ToString());}

在这里插入图片描述

UI

scrollView下方第一个Item的初始位置的空物体,作为所有技能的容器的父节点
在这里插入图片描述
在这里插入图片描述

(UI) 遮罩

就是一张图,表示未解锁
//需要加上触发器和DragScrollView,不然未解锁部分不能拖拽滚动
在这里插入图片描述
在这里插入图片描述

技能栏项目

SkillItem继承Skill(Skill继承MonoBehaviour,不然没事件机制,编辑器显示也有问题)
SetValue是将skill的值赋值给skillIItem
SetUI做UI显示

public class SkillItem : Skill
{public UISprite skillSprite;public UILabel nameLabel;public UILabel effectTypeLabel;public UILabel descriptionLabel;public UILabel costMpLabel;// Start is called before the first frame updatevoid Start(){SetUI();}......

技能栏项目的图片可以拖拽到快捷栏

盒子+UIDragAndDropItem(克隆拖拽)
Start的是克隆的那个,保存父节点的SkillItem后,把父节点移到根节点,让可以移到ScrollView之外
Release的tarnsfrom是克隆的那个,surface是鼠标移到的物体,移到格子,就是格子,根据Tag确定可以放置
Release调用surface(格子)的ShortItem方法,进行图片替换(默认是大小,位置设好的透明图)
在这里插入图片描述

public class SkillSprite : UIDragDropItem
{public SkillItem skillItem;protected override void OnDragDropStart(){base.OnDragDropStart();skillItem = transform.parent.GetComponent<SkillItem>();transform.parent = transform.root;//用回root方式跳出去GetComponent<UISprite>().depth = 5;//最高就行}protected override void OnDragDropRelease(GameObject surface){base.OnDragDropRelease(surface);if (surface != null && surface.tag == "Shortcut"){surface.GetComponent<ShortcutItem>().SetSkill(skillItem);}}
}

(代码) 关联玩家等级和职业

视频是只盖住图片,我用的碰撞体盖住整个Item,后果是不可滑动未解锁的技能,scrollBar的depth保证在整个节点组的顶部,不然不能(偶尔可以)滑动
//SkillItem

    public void ShowSkillItem()//根据人物等级和职业显示技能{if (roleLv > Player._instance.level || applyType!=Player._instance.applyType){maskSprite.gameObject.SetActive(true);}else{maskSprite.gameObject.SetActive(false);}       }

74-80 头像

头像框

增加图层,修改图层,调整相机
在这里插入图片描述
运行后,FaceCamrera
在这里插入图片描述
新建simpleTexture到场景,然后指定刚才的那张图
在这里插入图片描述

lv,name,exp,hp,mp

Player设int需要转float到value显示

exp,hp,mp用slider的value,视频是用exp+“/”+maxExp的格式

NPC在小地图上的UI标记 ,小地图缩放

3D/Quad(矩形),旋转到有显示的一面,加图层NpcSign,主相机不勾选该图层

没有圆形遮罩的素材,地图和头像都是方的
在这里插入图片描述

(问题)缩放失败

orthographicSize>0这样对应,小于0就反过来

    public void OnPlusClick(){miniMapCamera.orthographicSize--;}public void OnMinusClick(){miniMapCamera.orthographicSize++;}

上透视,下正交
越过0,按键作用相反,人物朝向由北向南(再底层的未了解)
在这里插入图片描述
改变的是这个
在这里插入图片描述

81 装备商店

(问题) unity完全不能点击,只能任务管理器结束进程

(问题) NGUI修改depth,子节点不随之变化

NGUI中更换Widget.depth时如何让子节点的depth也跟着变化
加的两句话的行数
1047行
1058行

Where需要引入using System.Linq;

NGUI ScrollView不能拖拽

在以下条件下,ScrollView里面的项目不能拖动:
ScrollView全打钩,Vertical移动,Vertical的Bar
Grid,Horizontal,1,调高度

(现象)运行后子节点Grid失效

项目,BoxCollider,UI Drag Scroll View。Grid是整理布局的·,运行后还是不激活,但可以拖拽了

在这里插入图片描述

(问题) 滚动滑轮时,画面不缩放,出现穿模

在这里插入图片描述

(问题) 物品的带信息提示框可以作为一个类

背包和商店的物品UI不同,但都可以带信息提示框。
现在是背包的带信息提示框,商店的继承背包的不合适,有很多UI不一样,会报错
所以商店的先继承Item

(了解) 类和属性的命名

可能复用的用最简洁的命名(方便以后合并复用),数据来源,类名用最骚最长的
比如weaponItem,potionItem,都统一用item,类名

(问题)描述与换行

        string str = "";if (attack > 0) str += "攻击:+" + attack+"\n";if (defense > 0) str += "防御:+" + defense + "\n";if (speed > 0) str += "移速:+" + speed + "\n";descriptionLabel.text =str;

(现象) NGUI和UGUI的层级

有NGUI的UIRoot后再加UGUI,UGUI会自动归于UIRoot下,手动移出也没用
在这里插入图片描述

(问题) NGUI的UIGrid无效

Unity3D学习笔记——NGUI之UIGrid

(问题) UIGrid的.Reposition()、Excute

导致Panel为空,但是一点击滑动块就正常
在这里插入图片描述
//正常
在这里插入图片描述
//没什么好说的,实例位置写错了。不过写错了,一点击,UIGrid还能正常排序,也挺新的
UIGrid组件的Excute可以代码调用,.Reposition()
在这里插入图片描述

(代码) 商店消费(一个)

在这里插入图片描述
//1 item

    public void OnBuyClick(){Transform panel = transform.parent.parent.parent.parent;panel.GetComponent<WeaponShopPannel>().Buy(price_buy);}

//
写在父类ShopPanel(Panel负责Tween动作、关闭;ShopPanel多了购买功能)
E-R的箭头是反着来的,但觉得这样视觉上更能体现“谁生谁”
在这里插入图片描述

    public void Buy(int price){int coin = Player._instance.coin;//if (coin < price) return;//不够钱if (coin <= 0) return;//没有钱//           coin -=price;Player._instance.coin = coin;coinLabel.text = coin.ToString();}

(想法)买了应该销毁它,商店现有物品情况重新写入磁盘文本

(代码) 商店消费(带数量框)

在这里插入图片描述

item

    public void OnBuyClick_Amount(){//显示按钮buyGo.transform.position = transform.position + buyGoOffset;buyGo.SetActive(true);}public void OnBuyClick_Amount_OK(){Transform panel = transform.parent.parent.parent.parent;int amount = int.Parse(buyGo.GetComponentInChildren<UILabel>().text) ;int id = GetComponent<WeaponShopItem>().id;//buyGo.SetActive(false);//panel.GetComponent<WeaponShopPannel>().Buy(id, price_buy, amount);}

ShopPanel

    public void Buy(int id ,int price , int amount){int coin = Player._instance.coin;//price *= amount;int remainCoin = coin - price * amount;//        if (remainCoin < 0) return;//不够钱//           coin = remainCoin;Player._instance.coin = coin;coinLabel.text = coin.ToString();//背包添加for (int i = 0; i < amount; i++){BagPannel._instance.CreateNewItem(id);}        }

BagPanel

ShowWindow()打开不显示,所以在ShowWindow中调用显示item的方法

   public void CreateNewItem(int createNewItemId)//点击生成物品的测试函数,{//1 随机添加一个物品int itemGroupId ;if (itemGroupList.Count == 0)AddNewItem(createNewItemId);else if (itemGroupList.Count<=gridList.Count){for (int i = 0; i < itemGroupList.Count; i++)//找到图片名相同的grid的索引{itemGroupId = itemGroupList[i].id;//取得格子里面的物品的id,moonobehavior排斥if (itemGroupId == createNewItemId)//相同,到对应的i加加{AddExistingItem(createNewItemId);break;}if (i == itemGroupList.Count - 1 && itemGroupId != createNewItemId)//到最后{AddNewItem(createNewItemId);//用拿到的id去对应的i实例break;}if (gridList.Count <= itemGroupList.Count){print("满了");break;//不加报Error}}}   }......public override void ShowWindow(){base.ShowWindow();DisplayItem(itemGroupList);}

(问题) Invalid editor window UIPrefabTool

Invalid editor window UnityEditor.FallbackEditorWindow UnityEditor.EditorApplicationLayout:SetPlaymo

86 快捷栏

(代码) 将物品拖到快捷栏

//item就是ItemGroup
在这里插入图片描述

在这里插入图片描述

从背包中拖出

写在MyDragAndDrop:UIDragDropItem

    protected override void OnDragDropRelease(GameObject surface){base.OnDragDropRelease(surface);.......else if (surface.tag == "Shortcut"){ItemGroup item=GetComponent<ItemGroup>();//surface.GetComponent<ShortcutItem>().AddBagItem(item);//BagPannel._instance.RemoveItem(item.id);}}
}

拖进快捷栏

ShortcutItem,共6个格子

    public void AddBagItem(ItemGroup item){GameObject go = Instantiate(BagPannel._instance.itemGroupPrefab);go.transform.position = transform.position;go.transform.parent = transform.GetChild(0);//父节点为背景图go.transform.localScale = Vector3.one;go.GetComponent<ItemGroup>().SetValue(item);}

(代码) 快捷栏使用药品

10/200血量,100血d的药,110/200=55%
在这里插入图片描述
在这里插入图片描述

回血回蓝

Player回复

    public bool Heal(int hp, int mp) //回血,还是不用item不然治愈技能不能复用{//if (mp==0 && hp > 0 && this.hp == maxHp) return false;//满血时不用纯血药if (hp==0 && mp > 0 && this.mp == maxMp) return false;//满蓝时不用纯蓝药if (this.hp == maxHp && this.mp == maxMp) return false;//都满不用药//int remainHp =this.hp + hp;int remainMp =this.mp + mp;//if (remainHp > maxHp) this.hp = maxHp;if (remainMp > maxMp) this.mp = maxMp;//this.hp = remainHp;this.mp = remainMp;return true;}

用药

ItemGroup(药物)
注意if (count <= 0)的位置,不要给显示0的机会
一开始用双击动作测试调用,所以这样命名

public void OnButtonDoubleClick(){......//药品if (itemType == ItemType.Potion){bool isSuccese = Player._instance.Heal(hp, mp);if (isSuccese){count--;if (count <= 0){Destroy(gameObject);}countLabel.text = count.ToString();}}     }

数字键调用

ShortItem调用它下面的ItemGroup

    void Update(){if(Input.GetKeyDown(keyCode)){if (transform.GetChild(0).childCount <= 0) return;//Transform itemGroup = transform.GetChild(0).GetChild(0);     itemGroup.GetComponent<ItemGroup>().OnButtonDoubleClick();//用双击测试故此命名}}

87 处理经验条和升级

经验条的UI在PlayerStatus部分

在这里插入图片描述

写在Player

    void Start(){//默认1级level =1;maxLevel = 6;                   //   0  1    2    3    4    5   6    7UI上每个等级对应的maxLevelmaxExpLevelList = new List<int> {  100, 200, 300, 400, 500, 600,700 ,800};}public void AddExp(int exp){int nextLevel = this.level + 1;//范围限制if (this.level >= maxLevel && this.exp >= maxExpLevelList[maxLevel]){this.level = maxLevel;this.exp = maxExpLevelList[maxLevel];return;}//int remainExp = this.exp + exp;while (remainExp >= maxExpLevelList[nextLevel])//考虑一次升多级的情况{remainExp -= maxExpLevelList[nextLevel];if (UpLevel()){continue;}else{break;}}//this.exp = remainExp;}public bool UpLevel(){int remainLevel = this.level +1;//范围限制//范围限制if (remainLevel > this.maxLevel){return false;}this.level = remainLevel;return true;}

在Update测试效果

        if (Input.GetMouseButtonDown(0)){AddExp(100);}

089 开发敌人小狼

(问题) 贴图(还是说材质)丢失

记得之前做秘密行动(当时没有写下来的意识)是改Materials文件夹下的Stanard
在这里插入图片描述

在这里插入图片描述
//好像管点用
在这里插入图片描述
//全部改Standar
在这里插入图片描述

(问题) 模型变红

材质那里把贴图往“法线贴图”一贴,就变红,然后改不回来了
在这里插入图片描述
//贴图被修改为法线贴图导致的
在这里插入图片描述
//所以把贴图类型改回默认
在这里插入图片描述

添加动画

将Animations中的动画拖到NoAnimations里面的动画器上
在这里插入图片描述

(代码) 默认Idle

//根据名字索引动画
在这里插入图片描述

public class Wolf : MonoBehaviour
{public State state;//public string idleClip = "WolfBaby-Idle";private new Animation animation;// Start is called before the first frame updatevoid Start(){state = State.Idle;animation = GetComponent<Animation>();}// Update is called once per framevoid Update(){Aniamtor();}void Aniamtor(){if (state == State.Idle){animation.CrossFade(idleClip);}}
}

90 控制小狼的随机移动巡逻

需求

随机的Idle、Walk
Idle,直接Walk
Walk,随机转弯,再Walk
计时循环
在这里插入图片描述

代码

    void Update(){......Timer();}void Timer(){timer += Time.deltaTime;if (timer > time){timer = 0f;Patrol();}}void Patrol()//巡逻{int rState = Random.Range(0,2);//if (rState == 0) //Idlestate = State.Idle;else if (rState == 1)//Walk{if (state == State.Idle)//上个状态==Idlestate = State.Walk;else if (state == State.Walk)//上个状态==Walk{int rRotate = Random.Range(0, 360);transform.Rotate(transform.up * rRotate);//y轴旋转}state = State.Walk;}}

//修改下Animator中的Walk,让它动

            case State.Walk:{GetComponent<CharacterController>().SimpleMove(transform.forward * walkSpeed * Time.deltaTime);PlayAniClip(walkClip); }break;

在这里插入图片描述

91 控制小狼被打中的效果

需求

受击打
闪避率 分 打中,打不中
打中,锁定击中标志,掉血,身体协程变红1秒
//需要加标识符,防止协程变红未恢复,就进行下一次变色

在这里插入图片描述

    [Tooltip("闪避率")] public float missRate = 0.2f;[Tooltip("生命值")] public float hp=100f;[Tooltip("最大生命值")] public float maxHp=100f;[Tooltip("身体变红的锁,类似于计时器的效果")] public bool isAttacked = false;void Update(){//测试受伤动画if (Input.GetKeyDown(KeyCode.Space)){TakeDamage(20f);}}void TakeDamage(float attack){float r = Random.Range(0f, 1f);if (r < missRate){print("Miss");return;}else{float remainHp = hp - attack;if (remainHp > 0) hp = remainHp;else hp = 0f;//PlayAniClip(damage1Clip);//if (!isAttacked)//防止协程变红未恢复,就进行下一次变色{isAttacked = true;StartCoroutine(ShowBodyRed());}      }}IEnumerator  ShowBodyRed(){Material material= GetComponentInChildren<Renderer>().material;Color normalColor = material.color;material.color = Color.red;yield return new WaitForSeconds(1f);material.color = normalColor;isAttacked = false;}

(存疑) render与GetComponentInChildren()

//以前的render等价于以下?

GetComponentInChildren<Renderer>()

//(起码视频中没看到给render赋值)
在这里插入图片描述

//应该是等价的,下面导入NGUI HUDText解决报错时看到类似的light
在这里插入图片描述

92 显示Miss(闪避)效果

需求

UGUI HUDText与NGUI HUDText

HUDText插件,商店太慢.
//下面的插件看看区别
UGUI HUD Text 1.4.1 Unity角色显示文字与数值插件 免费版//有UGUI HUDText
NGUI的HUD Text的扩展插件学习–(HUDText)的使用//只有教程NGUI HUDText
NGUI HUD Text//有NGUI HUDText,22M,包括NGUI、HUDText
//示例
在这里插入图片描述
//视频中的示例
在这里插入图片描述

UGUI HUDText不能用

拖了预制体,是UGUI的。混用麻烦
在这里插入图片描述

(代码)

在这里插入图片描述
在这里插入图片描述

    [Tooltip("预制体,加了UIFollowTarget的新的预制体")] public GameObject hudTextPrefab;[Tooltip("预制体的实例,全局定义,方便调用")] public GameObject hudTextGo;[Tooltip("预制体生成对象上的组件。用来add文本")] private HUDText hudText;[Tooltip("HUDText位置")] public Transform hudTextTrans;//[Tooltip("就上面那个")] public GameObject hudTextFollow;[Tooltip("NGUI的下相机,直接赋值报空错误")] public Camera uiCamera; [Tooltip("HUDText存在的时间")] public float stayDuration = 1f;// Start is called before the first frame updatevoid Start(){......InitHudText();}void InitHudText(){//实例、父节点hudTextGo = NGUITools.AddChild(HudTextParent._instance.gameObject, hudTextPrefab);hudTextGo.transform.position = Vector3.zero;hudTextGo.transform.localScale = Vector3.one;//取得HUDText组件hudText = hudTextGo.GetComponent<HUDText>();//填UIFollowTarget的参数UIFollowTarget followTarget = hudTextGo.GetComponent<UIFollowTarget>();//预制体自带followTarget.target = hudTextTrans;followTarget.gameCamera = Camera.main;//followTarget.uiCamera = UICamera.current.GetComponent<Camera>();//报空指针错误followTarget.uiCamera = uiCamera;}void TakeDamage(float attack){float r = Random.Range(0f, 1f);if (r < missRate){AudioSource.PlayClipAtPoint(missAudioClip,transform.position);hudText.Add("Miss",Color.gray, stayDuration);}......

在这里插入图片描述

093-094 敌人自动攻击部分-巡逻,追击,普攻暴击/受伤HUDText

(问题) 距离

//距离太远,所以放大1000倍,才发现位置的问题()
在这里插入图片描述
//3D视图发现父节点位置有问题,所以删掉新建父节点
在这里插入图片描述

(重构) 计时器委托(为了复用计时器的代码)

(问题) 原本的写法(返回不了 patrolTimer导致不变)

    void Update(){//巡逻Delegate patrol = Patrol;Timer(patrol, patrolTimer , patrolTime);......}private delegate void Delegate();//定义委托类型void Timer( Delegate func, float timer, float time )//定时巡逻{ if (timer > time){timer = 0f;print("委托");func();}else{patrolTimer += Time.deltaTime;}}

符合需求(返回timer的值)

    void Update(){//巡逻Delegate patrol = Patrol;     patrolTimer = Timer(patrol, patrolTimer , patrolTime);......}private delegate void Delegate();//定义委托类型float Timer( Delegate func, float timer, float time )//定时巡逻{ if (timer > time){timer = 0f;print("委托");func();}else{timer += Time.deltaTime;}return timer;}

(代码)

在这里插入图片描述

	......[Tooltip("普攻")] public int atk_normal = 10;[Tooltip("暴击")] public int atk_crazy = 15;[Tooltip("暴击率")] public float atk_crazy_rate = 0.1f;[Tooltip("攻速,一秒几下")] public int atk_rate = 1;[Tooltip("视野范围")] public float range_sight = 5f;[Tooltip("攻击范围")] public float range_atk = 1f;[Tooltip("追击速度")] public float chaseSpeed = 20f;void Update(){Aniamtor();//巡逻Delegate range = Range;     patrolTimer = Timer(range, patrolTimer , patrolTime);......}void Range()//视野{Transform target = Player._instance.transform;float distance = Vector3.Distance(target.position, transform.position);if (distance < range_atk){Attack();}else if (distance < range_sight){Chase();}else{Patrol();}}void Attack()//攻击{float r = UnityEngine.Random.Range(0f, 1f);//Transform target = Player._instance.transform;transform.LookAt(target);if (r < atk_crazy_rate)//暴击{//玩家受伤      state = State.Attack2;}else{state = State.Attack1;}}void Chase()//追击{Transform target = Player._instance.transform;transform.LookAt(target);GetComponent<CharacterController>().SimpleMove( transform.forward *Time.deltaTime *chaseSpeed);state = State.Walk;}void Patrol()//巡逻{int rState = UnityEngine.Random.Range(0, 2);//if (rState == 0) //Idle{state = State.Idle;print("1");}else if (rState == 1)//Walk{if (state == State.Idle)//上个状态==Idle{state = State.Walk;print("2");}else if (state == State.Walk)//上个状态==Walk{int rRotate = UnityEngine.Random.Range(0, 360);transform.Rotate(transform.up * rRotate);//y轴旋转print("3");}state = State.Walk;}}

(了解) 变量使用习惯(全局还是局部)

//个人喜欢用的时候直接 Transform target = Player._instance.transform;(在一个方法中就比较清楚(毕竟命名是件让人头疼的事))
//视频喜欢定义组件里面全局变量在Start()中target = Player._instance.transform;
//
暂时不能从经验上清楚各自特点优劣

(了解) region(折叠代码)

可能之前说了。但是看这坨东西和那小块,心情瞬间就不一样了
在这里插入图片描述

(代码) 敌人掉血HUDText

在Wolf的TakeDamage(float attack)加上,

hudText.Add("-"+attack.ToString(), Color.red, stayDuration);
    void Update(){......//测试受伤动画if (Input.GetKeyDown(KeyCode.Space)){TakeDamage(Player._instance.attack);}}void TakeDamage(float attack){......else{float remainHp = hp - attack;if (remainHp > 0){hp = remainHp;hudText.Add("-"+attack.ToString(), Color.red, stayDuration);} ......}

在这里插入图片描述

095-96 给主角添加战斗系统;主角攻击动画和自动攻击

(重构) 提取状态机那一部分到Player和Wolf的父类Human

反正能复用的,都尝试提取以一下

(代码) Human

//PlayAniClip(string clip)、Timer(Delegate func, float timer, float time)、Range(Transform target)有内容,其它都是下下图的虚函数

    public  void PlayAniClip(string clip){animation.CrossFade(clip);}//public delegate void Delegate();//定义委托类型public float Timer(Delegate func, float timer, float time)//定时执行函数{if (timer > time){timer = 0f;//print("Human计时器委托");func();}else{timer += Time.deltaTime;}return timer;}//public virtual void Range(Transform target)//视野{float distance = Vector3.Distance(target.position, transform.position);if (distance < range_atk){Attack();}else if (distance < range_sight){Chase();}}public virtual void Animator(){switch (state){case State.Idle: PlayAniClip(idleClip); break;case State.Walk:  PlayAniClip(walkClip); break;case State.Dead: PlayAniClip(deathClip); break;}}

//其它都是虚函数
在这里插入图片描述

(了解) 父类的Start,Update

子类不继承父类的Start,Update
所以不能想在父类的Start中赋值,以后就不用赋值了
//正常是,声明,使用,但不赋值,子类实现时再赋值

    public new Animation animation;......// Start is called before the first frame updatevoid Start(){}//public  void PlayAniClip(string clip){animation.CrossFade(clip);}

(问题) animation过时联想不优

//这有点解释了过时的animation和现在的GetComponent< Animation >();就是以前unity帮我们在父类中多做了这一个。但又过时了。难道这是不优的?
在这里插入图片描述

(重构) 之前MoveByMouse也有射线检测的代码,并且都有state,冲突

MoveByMouse的speed、state用Player._instance.speed、state,来达到数据统一

射线检测

//主要是里面的if语句,去掉else(留条件空间给Player),否则会跟Player中的射线检测起冲突

    //判断 mouseDownPosition发出的射线是否撞到标签为tag的物体,是的返回hit的位置public Vector3 RayTesting(){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//点生成射线RaycastHit hit;bool isCollided = Physics.Raycast(ray, out hit);//是否碰到if (isCollided && hit.collider.tag == Tags.ground){targetPosition = hit.point;return hit.point;}return transform.position;//默认值}

state

//主要修改体现在MoveByMouse的Run()中
//主要关注原本的state都用GetComponent< Player >().state

    void Run(){    float stopDistanceNearTargetPosition = 0.2f;//离目标点方圆0.2米内就可以float distance = Vector3.Distance(transform.position, targetPosition);//检测现在pos与目标pos的距离if (targetPosition != Vector3.zero && distance > stopDistanceNearTargetPosition)//有目的地而未到达{GetComponent<Player>().state = State.Run;characterController.SimpleMove(transform.forward * Time.deltaTime * speed);transform.LookAt(new Vector3(targetPosition.x, transform.position.y, targetPosition.z));}else if(distance < stopDistanceNearTargetPosition && Player._instance.target ==null){GetComponent<Player>().state = State.Idle;}}

(问题) 第二次点击才会在范围内攻击

调用问题
//之前Range(target);放在 RayTesting();里面,每次调用需要Input.GetMouseButton(0)
//所以拆出来

    void Update(){if (Input.GetMouseButton(0)){RayTesting();}if (target != null){Range(target);}                Animator();    }

(问题) 飞起来攻击

敌人和玩家都加上碰撞器就不会;
只给一个加碰撞器也会
在这里插入图片描述

098 添加攻击的特效

//掉血上面做了
Attack()里面加
//暂时看不出视频所说的加标志符,防止实例的特效重复播

Instantiate(atk_prefab, target.transform.position, Quaternion.identity);

在这里插入图片描述

099 开发敌人的孵化器

需求

即时生成max_num的敌人,敌人死了,马上计时补充到max_num

Spawn

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Spawn : MonoBehaviour
{public float timer = 0f;public float time = 1f;public GameObject prefab;public List<Transform> wolfList;public int max_num=5;public int current_num;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){if (wolfList.Count < max_num){timer += Time.deltaTime;if (timer > time){timer = 0f;SpawnWolf();}}}void SpawnWolf(){Vector3 pos;float posX = transform.position.x + Random.Range(-5f, 5f); //不包括右边界float posZ = transform.position.z + Random.Range(-5f, 5f); //不包括右边界pos = new Vector3(posX, transform.position.y, posZ);//GameObject go = Instantiate(prefab, pos, Quaternion.identity);go.transform.parent = transform;//wolfList.Add(go.transform);current_num = wolfList.Count;}public void Remove(Transform wolf)//记录current_num,为了保持max_num的数量{if (wolfList.Contains(wolf)){wolfList.Remove(wolf);current_num = wolfList.Count;}  }
}

Wolf

//死亡的时候调用
//Spawn里设置了Spawn的节点是父节点

    [Tooltip("所属生成器")] public Spawn spawn;void Start(){......spawn = transform.parent.GetComponent<Spawn>();}public override void Dead(){......//spawn.Remove(transform);}

100 开发敌人死亡后经验值的获得和任务的奖励

升级

需求

杀死敌人,传自身的exp调用玩家的AddExp(int Exp)方法

Wolf

	[Tooltip("杀死可得经验值")] public int exp = 10;public override void Dead(){......Player._instance.AddExp(exp);}

Player

    public void AddExp(int exp){int nextLevel = this.level + 1;//范围限制if (this.level >= maxLevel && this.exp >= maxExpLevelList[maxLevel]){this.level = maxLevel;this.exp = maxExpLevelList[maxLevel];return;}//int remainExp = this.exp + exp;while (remainExp >= maxExpLevelList[nextLevel])//考虑一次升多级的情况{remainExp -= maxExpLevelList[nextLevel];if (UpLevel()){continue;}else{break;}}//this.exp = remainExp;}private bool UpLevel(){int remainLevel = this.level + 1;//范围限制if (remainLevel > this.maxLevel){return false;}this.level = remainLevel;return true;}

任务奖励

(问题 ) 毛皮

//spawn这种引用在spawn.Remove(transform);报空指针错误。原因是“毛皮”,声明的spawn附在Wolf上,Wolf没了,spawn也没了
//做成单例,就不报错。逻辑上说,。也可以单例,但是这个单例是有一个spawn的列表,记录各个spawn中玩家杀死的敌人数

	[Tooltip("所属生成器")] public Spawn spawn;void Start(){......spawn = transform.parent.GetComponent<Spawn>(); }public override void Dead(){PlayAniClip(deathClip);    //移除一个,(补充满员)spawn.Remove(transform);//升级Player._instance.AddExp(exp);//任务进度QuestPannel._instance.progress++;//Destroy(gameObject, 1f);}

(问题) Invalid editor window UnityEditor.FallbackEditorWindow

切换个布局,之前也发生过,不清楚原理

后面发现,调整分辨率运行后,出现这种错误

(想法) 任务系统

//TODO:这里应该架构任务系统,任务类的设计,因为不止一个任务
//TODO:受任务后,才会建立起一个任务类,监听敌人的死亡,每死一个,progress++

101-02 给环境添加中型狼、BOSS

(问题) 角色控制器、碰撞器的调整

//角色控制器、碰撞器的基准点是中心,但一般“人型”与地面接触,如果基准点设为“脚底”就方便得多。
//不是全部脚底,类似于。得到一个点的坐标,一种方式是,拖进去坐子节点,重置Transform,再拖出来,这样就得到该点坐标
在这里插入图片描述

(面板) 调整

动画名
角色控制器、碰撞器
因为体型,所以range_atk攻击范围要大点,不然敌人打不到玩家

在这里插入图片描述
在这里插入图片描述

(问题) uiCamera空指针

空指针

//视频的方式找不到NGUI的uiCamera(可能是版本,可能是我遗漏了什么)
//uiCamera是固定的,拖拽赋值也不好

uiCamera = UICamera.current.GetComponent<Camera>();//报空指针错误

在这里插入图片描述

NGUITools.Start()

// NGUITools.FindCameraForLayer的Start()
//主要关注uiCamera = NGUITools.FindCameraForLayer(gameObject.layer);。因为观察到:不给uiCamera手动赋值时,也会自动赋值,所以看源码,它是怎么给uiCamera赋值的

	void Start(){if (target){if (gameCamera == null) gameCamera = NGUITools.FindCameraForLayer(target.gameObject.layer);if (uiCamera == null) uiCamera = NGUITools.FindCameraForLayer(gameObject.layer);Update();}else{if (destroyWithTarget) Destroy(gameObject);else enabled = false;}}

NGUITools.FindCameraForLayer(int layer)

//NGUITools的FindCameraForLayer()
//从Start(),注意到有个方法FindCameraForLayer(gameObject.layer);
//更底层的是UICamera.list.buffer[i].cachedCamera

	static public Camera FindCameraForLayer (int layer){int layerMask = 1 << layer;Camera cam;for (int i = 0; i < UICamera.list.size; ++i){cam = UICamera.list.buffer[i].cachedCamera;if (cam && (cam.cullingMask & layerMask) != 0)return cam;}......

解决方法

//然后看了源代码,干脆就用uiCamera = NGUITools.FindCameraForLayer(gameObject.layer);
//所以就是uiCamera = NGUITools.FindCameraForLayer(5);(这里可以做个int类型的枚举)
//或者uiCamera这一步不做了,反正会自动赋值
在这里插入图片描述

Spawn

//根据类型(枚举(枚举的那个下拉看起来很爽)),在InitType()中给实际要实例的预制体prefab赋值
//enum 公有还是私有,其他类都可以访问到;就是该类型的属性的访问级别不能比enum高。比如enum私有,该类型的属性就不能public

public enum WolfType
{WolfBaby,WolfNormal,WolfBoss
}public class Spawn : MonoBehaviour
{[Tooltip("根据类型用到的prefab")] private GameObject prefab;[Tooltip("生成类型")] public WolfType wolfType;public GameObject wolfBabyPrefab;public GameObject wolfNormalPrefab;public GameObject wolfBossPrefab;......void Start(){InitType();}private void InitType(){switch (wolfType){case WolfType.WolfBaby: prefab = wolfBabyPrefab;break;case WolfType.WolfNormal: prefab = wolfNormalPrefab;break;case WolfType.WolfBoss: prefab = wolfBossPrefab;break;default: prefab = wolfBabyPrefab; break;}}......

在这里插入图片描述
//可以看到生效了,不过MainCamera距离最下面的那只狼太近,穿模了。(暂时未学到怎么叫解决)
在这里插入图片描述

103 控制主角的受攻击的效果(掉血)、死亡

(重构) 将Wolf受伤,身体变红的代码 提取到 父类Human

属性的就不写了,解释前面有写

父类Human

    public virtual void InitHudText(){//实例、父节点hudTextGo = NGUITools.AddChild(HudTextParent._instance.gameObject, hudTextPrefab);hudTextGo.transform.position = Vector3.zero;hudTextGo.transform.localScale = Vector3.one;//取得HUDText组件hudText = hudTextGo.GetComponent<HUDText>();//填UIFollowTarget的参数UIFollowTarget followTarget = hudTextGo.GetComponent<UIFollowTarget>();//预制体自带followTarget.target = hudTextTrans;followTarget.gameCamera = Camera.main;//followTarget.uiCamera = UICamera.current.GetComponent<Camera>();//报空指针错误followTarget.uiCamera = NGUITools.FindCameraForLayer(5);//5是UI层}public virtual void TakeDamage(int attack){float r = UnityEngine.Random.Range(0f, 1f);if (r < missRate){AudioSource.PlayClipAtPoint(missAudioClip, transform.position);hudText.Add("Miss", Color.gray, stayDuration);print("Miss");}else{int remainHp = hp - attack;if (remainHp > 0){hp = remainHp;hudText.Add("-" + attack.ToString(), Color.red, stayDuration);}else{hp = 0;Dead();}//TakeDamageEffect();}}public virtual void TakeDamageEffect() { }public IEnumerator ShowBodyRed(){Material material = GetComponentInChildren<Renderer>().material;Color normalColor = material.color;material.color = Color.red;yield return new WaitForSeconds(1f);material.color = normalColor;isAttacked = false;}

子类Wolf

TakeDamage(int attack)用父类的就行

    public override void TakeDamageEffect(){PlayAniClip(damage1Clip);if (!isAttacked)//防止协程变红未恢复,就进行下一次变色{isAttacked = true;StartCoroutine(ShowBodyRed());}}IEnumerator  ShowBodyRed(){Material material= GetComponentInChildren<Renderer>().material;Color normalColor = material.color;material.color = Color.red;yield return new WaitForSeconds(1f);material.color = normalColor;isAttacked = false;}

子类Player

//子类在原本父类基础上加了一些。
//受伤方法跟同父类的Wolf一样

    public int Attack_Func(int attack){  //具体公式看自己设计int remainAttack = attack - defense;if (remainAttack <= 0) remainAttack = 1;return remainAttack;}public override void TakeDamage(int attack){if (Player._instance.state == State.Dead) return;//根据什么防御力整合最终所受攻击力attack = Attack_Func(attack);//仅仅为了方便从Wolf贴过来的代码//base.TakeDamage(attack); }public override void Dead(){state = State.Dead;Destroy(gameObject,5f);}

(代码) 死亡销毁 return

对报错的地方,进行 stateState.Dead、Player._instacenull,的判断

(运行) 也是跑得通的

在这里插入图片描述

104 添加技能额外信息的存储

主要看流程,因为这时代码多了,不方便都放出来

(需求)

//后三项是特效名称、角色动画名称、角色动画时间
//战士没有写后三项,所以只做魔法师的
在这里插入图片描述

Skill

添加属性

//技能特效名称efx是什么中文的翻译?
在这里插入图片描述
添加

    [Tooltip("技能特效文件名称")] public string skill_efx_name;[Tooltip("玩家动画文件名称")] public string player_ani_name;[Tooltip("玩家动画时间")] public string player_ani_time;

ToString()重写(觉得贴一下,因为觉得有做成片段的需要)

    public override string ToString(){string str = "";......//str += "\t" + skill_efx_name;str += "\t" + player_ani_name;str += "\t" + player_ani_time;return str;     }

片段

	......<Code Language="csharp"><![CDATA[  public override string ToString(){string str = "";str += "\t" + id;      return str;     }]]>......

SkillTextAssetToList

//在想只有魔法师有,要不要把代码到里面
//主要是觉得战士的后三项为空,会不会报错。视频是直接接在后面的
在这里插入图片描述

105 技能系统-使用增益技能

(需求)

//快捷栏需要的是Skill,而不是包含很多UI的SkillItem(因为Start()中就会初始化UI,快捷栏没有对应的UI,导致报空错误),如下图
//以上总而言之就是,就是避开SetUI、UnlockSkillItem
//01、SetUI、UnlockSkillItem的调用实际,在Start()去除,在ShowPanel加入(成功)
//02、所以SkillItem,不继承Skill,而是加属性。 public Skill skill;(没试成)
在这里插入图片描述

ShortItem

//我是放在Sprite下,Sprite是一张透明图,等着被换成技能或者物品

    void Start(){sprite = transform.GetChild(0);}void Update(){if (Input.GetKeyDown(keyCode))PlayerInput();}void PlayerInput(){      if (sprite.childCount <1) return;//item = sprite.GetChild(0);//挂在sprite下if (item.GetComponent<ItemGroup>() != null)//物品{item.GetComponent<ItemGroup>().OnButtonDoubleClick();//用双击测试故此命名}else if (item.GetComponent<SkillItem>() != null)//技能{print("发动技能");Player._instance.UseSkill(item.GetComponent<SkillItem>() );}}

在这里插入图片描述

SkillItem

    }public void SetValue(Skill skill){......skill_efx_name = skill.skill_efx_name;player_ani_name = skill.player_ani_name; player_ani_time = skill.player_ani_time;}

Player

拖技能预制体,做字典

    [Tooltip("技能预制体")] public List<GameObject> skillGoList;[Tooltip("根据名字找预制体的字典")] public Dictionary<string, GameObject> skillDictionary;......void Start(){......InitSkill();}void InitSkill(){foreach (GameObject go in skillGoList){skillDictionary.Add(go.name, go);}}

在这里插入图片描述
在这里插入图片描述

//需求,扣篮,Fill图,根据技能类型,执行对应类型技能的代码

    public bool UseSkill(Skill skill)//使用技能看蓝够不够{int mp = skill.costMp;int remainMp = this.mp - mp;//if (remainMp < 0)//没蓝{return false;}else//成功{this.mp = remainMp;UseSkillByEffectType(skill);return true;}}void UseSkillByEffectType(Skill skill){//清洗//增益(Hp、Mp) 增强(攻防) 单目标 多目标switch (skill.effectType){case EffectType.Passive:{UsePassiveSkill(skill);}break;case EffectType.Buff:{UsePassiveSkill(skill);}break;case EffectType.SingleTarget:{UsePassiveSkill(skill);}break;case EffectType.MultiTarget:{UsePassiveSkill(skill);}break;default: break;}}void UsePassiveSkill(Skill skill)//增益{switch (skill.effectProperty){case EffectProperty.HP: AddHp((int) skill.effectValue); break;case EffectProperty.MP: AddMp((int) skill.effectValue); break;}}void UseBuffSkill(Skill skill)//增强{ }void UseSingleTargetSkill(Skill skill)//单目标{ }void UseMultiTarget(Skill skill)//多目标{ }

HP/MP生效

//一开始hp=50%
//按下后显示“发动技能”,回血到62%
在这里插入图片描述

(问题) 字典找不到值

//
ArgumentException: The Object you want to instantiate is null.
//
KeyNotFoundException: The given key was not present in the dictionary.

打印键值是否存在

//false没有键
print(skillDictionary.ContainsKey(“Effect-Heal”));
//true有值true
print(skillDictionary.ContainsValue(skillGoList[1]));

直接取预制体列表可以生效

模型是战士,但是类型已经改为魔法师
在这里插入图片描述

字典取值的两种方式

//所以是Key出现问题

        GameObject go = skillGoList[1];skillDictionary.Add("Effect-Heal",  go);GameObject go = null;//01 方式一//skillDictionary.TryGetValue("Effect-Heal", out go);//02 方式二go = skillDictionary["Effect-Heal"] ;//Instantiate(go, transform.position, Quaternion.identity);

结果

名字问题
//三个文件夹中有heal_Effect、Effect_Heal
在这里插入图片描述

(问题) 实例不出来

//前面强制命名测试没改回来
//字典取不到值,可以先强制命名Key,能不能拿到Value

(效果)

共三个文件,1一个Heal,3两个Heal。效果如下左三
在这里插入图片描述

(动画) 协程

在这里插入图片描述

(代码) Player新增度代码

    [Tooltip("技能预制体")] public List<GameObject> skillGoList;[Tooltip("根据名字找预制体的字典")] public Dictionary<string, GameObject> skillDictionary=new Dictionary<string, GameObject>();[Tooltip("技能实例的地方")] public Transform skillTrans;//可能没用到[Tooltip("粒子播放时间,用来控制动画的播放时间")] public float skillTime;void Start(){......InitSkill();}......void InitSkill(){skillDictionary.Clear();for (int i = 0; i < skillGoList.Count; i++){GameObject go = skillGoList[i];skillDictionary.Add(go.name,go);}}public bool UseSkill(Skill skill)//使用技能看蓝够不够{int mp = skill.costMp;int remainMp = this.mp - mp;//if (remainMp < 0)//没蓝{return false;}else//成功{if (UseSkillByEffectType(skill))//防止满血加血等情况{this.mp = remainMp;}         return UseSkillByEffectType(skill);//比如回血,蓝是够了,但没必要}}bool UseSkillByEffectType(Skill skill){//清洗//增益(Hp、Mp) 增强(攻防) 单目标 多目标switch (skill.effectType){case EffectType.Passive:{return UsePassiveSkill(skill);}break;case EffectType.Buff:{UsePassiveSkill(skill);}break;case EffectType.SingleTarget:{UsePassiveSkill(skill);}break;case EffectType.MultiTarget:{UsePassiveSkill(skill);}break;default: break;}return false;}bool UsePassiveSkill(Skill skill)//增益{bool isSuccesed = false;switch (skill.effectProperty){case EffectProperty.HP:{isSuccesed= AddHp((int)skill.effectValue);//满血,没蓝就失败}  break;case EffectProperty.MP: { isSuccesed= AddMp((int)skill.effectValue); }  break;}if (isSuccesed){//实例特效string key = skill.skill_efx_name;//if (skillDictionary.TryGetValue(key, out GameObject value)){Instantiate(value, transform.position, Quaternion.identity);//skillTime = value.GetComponent<DestroyForTime>().time;StartCoroutine(PlayAniClip());}}else{print("发动技能失败");  }return isSuccesed;}IEnumerator PlayAniClip(){isAttacked = true;state = State.Skill1;yield return new WaitForSeconds(skillTime);isAttacked = false;state = State.Idle;}......

106 技能系统-使用增强技能

(代码) 动画速度

//改变动画速度我查到如下,但是只需要攻击状态变化速度,移速其他的保持原速。

            foreach (AnimationState state in anim){state.speed = speed;}

所以实际加了状态判断,如下:
//问题是复用,aniState.name是写死的,暂不展开

    void ChangeAnimationSpeed(float speed){Animation anim = GetComponent<Animation>();foreach (AnimationState aniState in anim){print("输出"+aniState.name);if (aniState.name == "Sword-Attack1" || aniState.name == "Sword-Attack2"){aniState.speed = attackSpeed;}}}

(代码)

//skill.effectTime是buff存在时间

    IEnumerator UseBuffSkill(Skill skill)//增强{//属性switch (skill.effectProperty){case EffectProperty.Attack: atk_normal*=skill.effectValue/100f;break;case EffectProperty.Defense:defense *= skill.effectValue / 100f; break;case EffectProperty.AttackSpeed:{attackSpeed += skill.effectValue / 100f;UpdateAttackSpeed(attackSpeed);}  break;}print("输出"+ skill.effectTime);//技能状态SkillState(skill);       //属性恢复yield return new WaitForSeconds(skill.effectTime);switch (skill.effectProperty){case EffectProperty.Attack: atk_normal /= skill.effectValue / 100f; break;case EffectProperty.Defense: defense /= skill.effectValue / 100f; break;case EffectProperty.AttackSpeed:{attackSpeed -= skill.effectValue / 100f;UpdateAttackSpeed(attackSpeed);} break;}}void UpdateAttackSpeed(float attackSpeed){Animation anim = GetComponent<Animation>();foreach (AnimationState aniState in anim){print("输出"+aniState.name);if (aniState.name == "Sword-Attack1" || aniState.name == "Sword-Attack2"){aniState.speed = attackSpeed;}}}

在这里插入图片描述

107-108 技能系统-使用单个目标技能

(代码) GameSettings 设置单个目标攻击光标

//实际叫CursorController合理点
//前面(36 鼠标指针管理系统),有设置了所有的

public class GameSettings : MonoBehaviour
{public Texture2D lockTargetCursor;......public static GameSettings _instance;// Start is called before the first frame updatevoid Awake(){_instance = this;}void SetLockTargetCursor(){Cursor.SetCursor(lockTargetCursor, Vector2.zero, CursorMode.Auto);//图形,焦点}......}

(代码) Wolf 光标处理

//inChosingTarget,数字键按下技能,处于选择目标的时候

    private void OnMouseEnter(){if (Player._instance.inChosingTarget) //使用技能时GameSettings._instance.SetLockTargetCursor();else GameSettings._instance.SetAttackCursor();}private void OnMouseExit(){GameSettings._instance.SetNormalCursor();}

(问题) 状态栏不刷新

//并且为了UI刷新, return这段语句要放在方面最后面,如下

    public void UpdatePlayerStatus(){......if (player.level > 6) return;//只做了6的经验表,但是为了解锁技能,我设100级,所以...float exp = (float)player.exp / (float)player.maxExpLevelList[player.level + 1];expBar.GetComponent<UISlider>().value = exp;}

(代码) Player

    [Tooltip("使用单体群体技能后为true,比如选择光标的优先级要大于普攻敌人时普攻光标")] public bool inChosingTarget = false;[Tooltip("当前处理那个技能的选择目标状态")] public Skill currentSkill;void Update(){......if (Input.GetMouseButton(0) && inChosingTarget==true && target != null && target.GetComponent<Wolf>() != null)//使用技能出现选择光标的情况{UseSingleTargetSkill(currentSkill);}}bool UseSkillByEffectType(Skill skill){//清洗//增益(Hp、Mp) 增强(攻防) 单目标 多目标switch (skill.effectType){......case EffectType.SingleTarget:{inChosingTarget = true;currentSkill = skill;return true;                  }void UseSingleTargetSkill(Skill skill)//单目标{//Wolf enemy;inChosingTarget = true;//为了让普攻光标切换为选择光标enemy = target.GetComponent<Wolf>();//SkillState(skill, target);////产生技能伤害(普通、暴击)float r = UnityEngine.Random.Range(0f, 1f);transform.LookAt(target);if (r < atk_crazy_rate)//暴击{print("暴击");//玩家受伤      state = State.Skill2;float attack = atk_crazy * skill.effectValue / 100f;enemy.TakeDamage(attack);}else{print("普攻");state = State.Skill1;float attack =atk_normal * skill.effectValue / 100f;enemy.TakeDamage(attack);}Instantiate(atk_prefab, target.transform.position, Quaternion.identity);//减血文字//看表知道没有能持续时间//inChosingTarget = false;currentSkill =null;}......

(效果)

//有发生倒下的bug
//点击选择目标时,玩家移动
在这里插入图片描述

(代码) MoveBuMouse Run()

//防止点击选择敌人时移动

        if (Player._instance.inChosingTarget) return;

109 技能系统-使用群体攻击技能

target是ground

enemy是所有碰撞到的enemy

在这里插入图片描述

群体、单体的区别

//光标开始变化时间不同
//伤害计算方式不一样,
//射线检测的对象不一样,尤其将射线检测写成一个方法,返回Transform target,在群体中位置不对((问题) 点击地面,实例特效的位置)

(问题) 按住群体技能,角色不能动,技能特效没有出现

//重构射线检测代码时,target局部变量和全局变量的区别

(问题) Skipped updating the transform of this Rigidbody

Skipped updating the transform of this Rigidbody because its components are infinite. Could you have applied infinite forces, acceleration or set huge velocity?
重新运行自动好的

(问题) 点击地面,实例特效的位置

//地图很大,群体技能是射线检测为Ground就释放,hit.collider.transform是地面,坐标是原点,所以不行
//用Input.mousePosition,测试不行
//视频是射线检测的Vector3 hit.point,所以新建一个全局变量targetPos来接收它
//Ground的原点是000
在这里插入图片描述

(问题) 按两下数字键,玩家既不能移动也不能放技能

//点击鼠标,玩家没有目标,但处于群体攻击的选择目标状态
在这里插入图片描述
//update那里的问题,所以梳理下,并且运行通过

    void Update(){      Animator();if (Input.GetMouseButton(0)){if (RayTesting(Tags.Enemy) && inChosingTarget==false)//追击,攻击的状态{Range(target);}if (RayTesting(Tags.Enemy) && inChosingTarget == true)//单体技能{UseSingleTargetSkill(currentSkill);}else if (RayTesting(Tags.Ground)  && inChosingMultiTarget)//群体技能{UseMultiTarget(currentSkill);}}}

在这里插入图片描述

(问题) 没伤害HudText

//特效可以拿到触发列表
在这里插入图片描述
//玩家可以拿到触发列表
在这里插入图片描述
//HudText有生成伤害文字,3D视图发现位置不对
//所以试着跟视频一样,将伤害的代码放在 技能的脚本 中(触发检测中调用改方法),达到效果。详细见MagicSphere
在这里插入图片描述

(问题) 销毁后为空,报空指针

//Wolf加报空检测,有可能死了
//或者((问题) 多次计算伤害) 失效触发器,这样就不会多次走触发事件,从而再次执行(List takingDamageEnemyList, float attack)。第一次执行一定不为空,除非有多个伤害源

    void RangeSkillAttack(List<Transform> takingDamageEnemyList, float attack){for (int i = 0; i < takingDamageEnemyList.Count; i++){if (takingDamageEnemyList[i] != null){takingDamageEnemyList[i].GetComponent<Wolf>().TakeDamage(attack);Instantiate(atk_prefab, transform.position, Quaternion.identity);//减血文字}}}

在这里插入图片描述

(问题) 多次计算伤害

//想过remove,或者标志,麻烦
//使用GetComponent().enabled = false;能达到效果

    void OnTriggerEnter(Collider other){if (other.CompareTag(Tags.Enemy)){ takingDamageEnemyList.Add(other.transform);       }RangeSkillAttack(takingDamageEnemyList, attack); //开打GetComponent<SphereCollider>().enabled = false;}

//下图就是多次运行了OnTriggerEnter(Collider other)的后果
在这里插入图片描述

(效果) 最终效果

//主要代码在UseMultiTarget(Skill skill)
//觉得写得有些地方不明白。
在这里插入图片描述

在这里插入图片描述

(代码) Player

	......[Tooltip("使用单体群体技能后为true,比如选择光标的优先级要大于普攻敌人时普攻光标")] public bool inChosingTarget = false;[Tooltip("使用群体群体技能后为true,比如选择光标的优先级要大于普攻敌人时普攻光标")] public bool inChosingMultiTarget = false;[Tooltip("当前处理那个技能的选择目标状态")] public Skill currentSkill;[Tooltip("群体技能认地面原点所以不能用Transform")] public Vector3 targetPos;void Update(){      Animator();if (Input.GetMouseButton(0)){if (RayTesting(Tags.Enemy) && inChosingTarget==false)//追击,攻击的状态{Range(target);}if (RayTesting(Tags.Enemy) && inChosingTarget == true)//单体技能{UseSingleTargetSkill(currentSkill);}else if (RayTesting(Tags.Ground)  && inChosingMultiTarget)//群体技能{UseMultiTarget(currentSkill);}}}public bool RayTesting(string tag){Ray ray = Camera.main.ScreenPointToRay( Input.mousePosition );//从鼠标位置发出射线RaycastHit hit;bool isCollided = Physics.Raycast( ray, out hit );if (isCollided && hit.collider.CompareTag(tag) ){target = hit.collider.transform;targetPos = hit.point;//针对地形这种大物体获取位置,肯定不能用target.position(为原点)return  true;}else{target = null;return false;}      }bool UseSkillByEffectType(Skill skill){//增益(Hp、Mp) 增强(攻防) 单目标 多目标switch (skill.effectType){......case EffectType.MultiTarget:{inChosingMultiTarget = true;                      currentSkill = skill;GameSettings._instance.SetLockTargetCursor();//一使用就切选择光标,跟单体不同return true;}break;......}void UseMultiTarget(Skill skill)//多目标{inChosingMultiTarget = true ;//防止技能期间移动之类的//相对于单体的SkillState(Skill)重写string key = skill.skill_efx_name;if (skillDictionary.TryGetValue(key, out GameObject value)){                      GameObject go= Instantiate(value, targetPos + Vector3.up  , Quaternion.identity);//技能特效//伤害float attack = SkillAttack(skill);//综合攻击力    go.GetComponent<MagicSphere>().attack = attack;//因为调用伤害是触发器调用的,所以Player这边只设置好参数go.GetComponent<MagicSphere>().atk_prefab = atk_prefab;//skillTime = skill.player_ani_time;StartCoroutine(PlayAniClip());//                           }//看表知道没有能持续时间//inChosingMultiTarget = false;currentSkill = null;GameSettings._instance.SetNormalCursor();}float SkillAttack(Skill skill)//计算综合伤害{//产生技能伤害(普通、暴击)并且实例HudTextfloat r = UnityEngine.Random.Range(0f, 1f);transform.LookAt(target);float attack;if (r < atk_crazy_rate)//暴击{print("暴击");//玩家受伤      state = State.Skill2;attack = atk_crazy * skill.effectValue / 100f;}else{print("普攻");state = State.Skill1;attack = atk_normal * skill.effectValue / 100f;}return attack;}

(代码) MoveByMouse

    void Run(){Player player = Player._instance;......if (player.inChosingMultiTarget) return;if (player.isAttacked) return;......

(代码) MagicSphere(群体技能)

public class MagicSphere : MonoBehaviour
{[Tooltip("将被范围伤害的敌人")]    public List<Transform> takingDamageEnemyList;[Tooltip("角色传过来的攻击力")] public float attack;[Tooltip("角色传过来的对应的Hudtext")] public GameObject atk_prefab;// Start is called before the first frame updatevoid Start(){}void OnTriggerEnter(Collider other){if (other.CompareTag(Tags.Enemy)){ takingDamageEnemyList.Add(other.transform);       }RangeSkillAttack(takingDamageEnemyList, attack); //开打GetComponent<SphereCollider>().enabled = false;}void RangeSkillAttack(List<Transform> takingDamageEnemyList, float attack){for (int i = 0; i < takingDamageEnemyList.Count; i++){if (takingDamageEnemyList[i] != null ){Transform enemy = takingDamageEnemyList[i];enemy.GetComponent<Wolf>().TakeDamage(attack);Instantiate(atk_prefab, enemy.position, Quaternion.identity);//减血文字//}}}
}

110 场景加载-游戏完结

(代码) LoadGame

public class LoadGame : MonoBehaviour
{public List<GameObject> playerList;public Vector3 spawnPos;public int index;public new string name;// Start is called before the first frame updatevoid Awake(){if (PlayerPrefs.HasKey("SelectedPlayerName") ){name = PlayerPrefs.GetString("SelectedPlayerName"); spawnPos = new Vector3(236.27f, 0f, 155.61f);//看到地图广场位置Instantiate(playerList[index], spawnPos, Quaternion.identity);}if (PlayerPrefs.HasKey("SelectedPlayerIndex")){index = PlayerPrefs.GetInt("SelectedPlayerIndex"); Player._instance.name = name;//PlayerStatus做了Update显示name,所以直接设}       }

(代码) Player

    void InitProperty() {if(PlayerPrefs.HasKey("SelectedPlayerName")== false) name = "123";......

(代码) 其他

绑定按钮事件…

(跑流程)

在这里插入图片描述
在这里插入图片描述
//之前模型是没有改回来,所以一直是魔法师类型的战士模型
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/28360.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity官方案例噩梦射手开发总结<一> 角色的攻击功能实现

愉悦的寒假生活总是会猝不及防地迎来尾声&#xff0c;这也意味着我大一生活的进度条已经过半了。幸运的是&#xff0c;在我某位优秀的学长的带领下&#xff0c;我完整地开发出来了unity的官方案例噩梦射手并基本实现所有功能&#xff0c;也是让我这个大一的苟蒻积攒了不少的新知…

GAMES202-Shadow总结概括

截图均来自于闫令琪老师的GMAES202-Shadow&#xff0c;本文在于对课程内容进行总结以及加上自己的理解&#xff0c;希望帮助同学们加深对课程内容的理解&#xff0c;如有谬误请各位指正 复习本节需要的基本知识 1. Shadow Mapping 为了获得一张Shadow Mapping&#xff0c;需要…

暗黑破坏神:不朽 unity mmo arpg资源分包精讲

unity大型游戏资源管理——分包 视频讲解&#xff1a;点击观看 unity mmo arpg 暗黑破坏神&#xff1a;不朽 是一个大型的重度游戏&#xff0c;该游戏资源已经超过10G 所以它用了资源分包技术减少下载时间。 首包只包含基础资源&#xff0c;在玩家玩第一关的时候&#xff0c;后…

股票卖出技巧及原则,你了解哪些

股票卖出技巧及原则&#xff0c;你了解哪些&#xff1f;有句股谚说&#xff0c;“会买的是徒弟&#xff0c;会卖的是师傅&#xff0c;会空仓的是祖师爷”。以前都是把大部分精力放在了选股和如何买股上面&#xff0c;而对如何卖股票太忽视了。难怪总是出不了师&#xff0c;小学…

通达信破底翻选股公式,用缠论底分型进行优化

上次在写《通达信破底翻形态选股公式&#xff0c;选出破底之后再翻回的股票》这篇文章时&#xff0c;编写破底翻选股公式就考虑使用缠论底分型&#xff0c;但是底分型的包含关系较为复杂&#xff0c;不容易处理&#xff0c;只能暂时搁置&#xff0c;采用了一种简单的方式&#…

股票大作手操盘术[图解]

目录 第一章&#xff1a;投机是一项挑战 第二章 何时入场才是好时机 第三章 追随领头羊 第四章 手里的钱财 第五章 关键点 第六章 百万美元的大错 第七章 三百万美元的盈利 第八章 利弗莫尔市场要决 杰西•利弗莫尔为什么能在投机事业中取得巨大成功&#xff0c;这…

【通达信指标公式】主力博弈分时指标,分时图抓日内弱转强牛股

GHYJKU:BETWEEN((CLOSE*1)/(SUM(AMOUNT,BARSCOUNT((CLOSE*1)))/SUM(VOL*100,BARSCOUNT((CLOSE*1)))),1.05,0.95); VBNH:IF(GHYJKU0,MA((CLOSE*1),BARSCOUNT((CLOSE*1))),(SUM(AMOUNT,BARSCOUNT((CLOSE*1)))/SUM(VOL*100,BARSCOUNT((CLOSE*1))))); 紫色跟风:EXPMA((CLOSE/VBNH),…

ChatGPT写代码之——CodeWhisperer在VS Code下如何安装

一、安装 1. 在VS Code扩展中搜索AWS 点安装就安装好了 #二、配置 1. 点击状态栏出现的AWS 选择add New Connection 选择Use a personal email to sign up and sign in with AWS Builder ID 选择Copy Code for AWS builder ID 跳转到浏览器 2. 在浏览器上一步步用自己的邮…

计算机程序设计类论文,计算机编程论文

计算机编程论文 介绍:本栏目是计算机和编程和论文相关的论文例文,免费教你怎么写关于计算机编程的论文提供相关文献资料。 【摘 要】本探究经过问卷调查、现场采访、走访调查、查阅文献资料等方法对河南省各大高校计算机专业大学生的学习情况(特别是编程能力)进行了调查和研。 …

爱丁堡计算机专业硕士世界排名,爱丁堡大学计算机世界排名

导读&#xff1a;,伴随着科技与经济的高速发展&#xff0c;计算机技术专业成为一门热门的专业&#xff0c;越来越受到人们的欢迎&#xff0c;学校的师资力量和教育水平&#xff0c;也直接成为影响我们选择高校的原因之一。 伴随着科技与经济的高速发展&#xff0c;计算机技术专…

爱丁堡大学计算机专业alevel,爱丁堡大学alevel要求?

原标题&#xff1a;爱丁堡大学alevel要求&#xff1f; 爱丁堡大学接受A-level和国际文凭课程的直接申请&#xff0c;每个学位课程都必须达到特定标准的要求才能入学。例如&#xff1a;申请爱丁堡大学商学院本科课程A-level要求AAA-ABB&#xff0c;兽医学(5年制)A-level要求为AA…

革微信的命,要靠“聊天即挖矿”?

广告诱惑我们追求名车服饰,从事自己憎恨的工作,为的就是买堆根本没用的狗屁东西。 ——Tyler Durden,《搏击俱乐部》 2019年1月15日,注定是一个不平凡的日子,这一天,3家公司揭秘了酝酿已久的社交产品——分别是罗永浩的聊天宝,王欣的马桶MT,张一鸣的多闪。目的只有一个…

用AI重构骨架,打造未来感IP体验经济

我国网文市场目前拥有近2000万位作家、4.9亿名读者。 如果将庞大的网文行业比作一个江湖&#xff0c;那么拥有2.4亿月活用户的阅文集团&#xff08;HK00772&#xff0c;股价33.2港元&#xff0c;市值338.06亿港元&#xff09;&#xff0c;称得上是“天下第一大派”。 “第一大…

NLP-预训练模型-GPT系列:GPT-1(2018-06)、GPT-2(2019-02)、GPT-3(2020-05)、InstuctGPT(2022-01)、chatGPT(2022-11)

GPT1:Imporoving Language Understanding By Generative Pre-training GPT2:Lanuage Models Are Unsupervised Multitask Learners GPT3:Language Models Are Few-shot Learners GitHub:https://github.com/openai/gpt-3 从GPT三个版本的论文名也能看出各版本模型的重点…

后端学习路线(包含博主买的课程)(持续更新中...)

快速了解Java体系(尚硅谷雷神主讲): Java技术栈 前端学习路线 博主已购买此网站的永久会员&#xff0c;含有大量付费资源&#xff0c;需要的私聊&#xff1a; 666资源站-666资源站 学习建议&#xff1a; 开发过程中&#xff0c;建议结合ChatGPT开发&#xff0c;减少重复工作…

GPT全家桶再添一员!看论文神器,ResearchGPT,可立即试用

文&#xff5c;Pine 发自 凹非寺源&#xff5c;量子位 科研人员福音&#xff01;专门和论文对话的“ChatGPT”来了。 懒得看论文&#xff1f;没关系&#xff0c;直接让这个工具帮你看&#xff0c;有什么问题直接问它就好了。 而你全程要做的就只有上传论文和问问题。 但又感觉心…

副业是刚需?分享几个程序员接外包私活的网站

经常看到某某程序员接了个项目开发&#xff0c;工作之余轻轻松松赚了钱还顺带提升了技术&#xff1b;或者看到某大佬又发表了一篇程序员技术提升稿件&#xff0c;阅读点赞收藏三连发&#xff0c;这个月的零花钱又不愁了...但自己只是一名普普通通的程序员&#xff0c;能找到这样…

PostgreSQL 不能数据备份及恢复失败,提示postgresql Please correct the Binary Path in the Preferences dialog

备份或恢复提示&#xff1a; Please correct the Binary Path in the Preferences dialog. 看了一下路径&#xff0c;原因是路径不一样 解决方案 File - Preferences -Paths - Binary paths 改成&#xff1a;&#xff08;根据自己安装的位置&#xff0c;复制bin路径过去就…

微信备份聊天记录,显示连接错误,终极解决办法

微信备份聊天记录到电脑时&#xff0c;提示连接错误&#xff0c;网上找了各种办法&#xff0c;关闭防火墙&#xff0c;链接同一wifi&#xff0c;没有解决&#xff0c;有可能和我的路由器有关&#xff0c;如果大家遇到连接同一个路由器WiFi还是无法备份&#xff0c;可以尝试以下…

学术科研专用ChatGPT来了!Github上已斩获2w+ Star

来源&#xff1a;新智元 自从ChatGPT发布之后&#xff0c;各路大神都开始研究如何把它加入到自己的「科研工作流」当中。 比如「数学天才」陶哲轩就表示&#xff0c;他已经将ChatGPT纳入了自己的工作流程。 最近&#xff0c;一位网友也分享了自己的「ChatGPT 学术优化」项目。 …