学习游戏制作记录(各种水晶能力以及多晶体)8.1

1.实现创建水晶并且能与水晶进行交换位置的能力

创建好水晶的预制体,添加动画控制器,传入待机和爆炸的动画

创建Crystal_Skill_Control脚本:

挂载在水晶预制体上

private float crystalExstTime;//水晶存在时间

public void SetupCrystal(float _crystalDuration)
{
crystalExstTime = _crystalDuration;
}

private void Update()
{
crystalExstTime -= Time.deltaTime;

if(crystalExstTime < 0 )
{
SelfDestroy();//超时自毁
}
}

public void SelfDestroy() => Destroy(gameObject);

创建Crystal_Skill脚本:

挂载在技能管理器上,并在SkillManage脚本上初始化

**[SerializeField] private float crystalDuration;//传入上面的控制脚本

SerializeField\] private GameObject crystalPrefab;//预制体 private GameObject currentCrystal;** **public override void UseSkill() { base.UseSkill();** **if(currentCrystal==null)//不存在则创建 { currentCrystal =Instantiate(crystalPrefab,player.transform.position,Quaternion.identity);** **Crystal_Skill_Control newcrystalScript= currentCrystal.GetComponent\();** **newcrystalScript.SetupCrystal(crystalDuration);** **} else//如果场上有水晶则传送玩家并销毁水晶 { player.transform.position = currentCrystal.transform.position;** **Destroy(currentCrystal); } }** ### Player脚本: **if(Input.GetKeyDown(KeyCode.F)) //update中 { skill.crystal.CanbeUsed(); }** ![](https://i-blog.csdnimg.cn/direct/f917e7d3a4824b0dacac254910f95754.png) ## 2.实现水晶爆炸和变大的功能 给水晶爆炸动画选取中间一帧调用伤害函数,在结束添加帧事件调用自毁函数 ![](https://i-blog.csdnimg.cn/direct/7d4abb970c3d41f9835377ad9f5f6614.png) 动画控制器添加触发Explode ### Crystal_Skill_Control脚本: **private Animator anim =\>GetComponent\();//获取碰撞器和动画器 private CircleCollider2D cd =\>GetComponent\();** **private bool canExplode;//是否可以爆炸 private bool canMove;//是否可以移动 private bool canGrow=false;//是否可以变大** **private float moveSpeed; private float growSpeed=5f;//增大速度** **public void SetupCrystal(float _crystalDuration,bool _canExplode,bool _canMove,float _moveSpeed) { crystalExstTime = _crystalDuration; canExplode = _canExplode; canMove = _canMove; moveSpeed = _moveSpeed;** **}** **if(canGrow)//update()中 { transform.localScale = Vector2.Lerp(transform.localScale,new Vector3(3,3),growSpeed\*Time.deltaTime);//变大** **}** **public void AnimationExplodeEvent()//伤害事件 { Collider2D\[\] collider2Ds = Physics2D.OverlapCircleAll(transform.position,cd.radius);//用碰撞器的半径** **foreach (var hit in collider2Ds) { if (hit.GetComponent\() != null) { hit.GetComponent\().Damage(); } } }** **public void FinishCrystal() { if (canExplode)//如果可以爆炸 { canGrow = true;//设置变大 anim.SetTrigger("Explode");//播放爆炸动画 } else { SelfDestroy(); } }** ### Crystal_Skill脚本: **\[Header("Explode crystal")

SerializeField\] private bool canExplode;** **\[Header("Moving crystal")

SerializeField\] private bool canMove; \[SerializeField\] private float moveSpeed;** **else//修改 { Vector2 playerPos= player.transform.position;** **player.transform.position = currentCrystal.transform.position;** **currentCrystal.transform.position = playerPos;//交换水晶与玩家** **currentCrystal.GetComponent\().FinishCrystal(); }** ## 3.实现水晶的移动 ### Skill脚本: **protected virtual Transform FindClosetEnemy(Transform _checkTransform)//这是之前写克隆攻击时用到的代码,现将它放在skill上,用于找到指定组件附近最近的敌人 { Collider2D\[\] collider2Ds = Physics2D.OverlapCircleAll(_checkTransform.position, 25); float closestEnemyDistance = Mathf.Infinity; Transform closestEnemy = null; foreach (var hit in collider2Ds) {** **if (hit.GetComponent\() != null) { float distanceToEnemy = Vector2.Distance(_checkTransform.position, hit.transform.position);** **if (distanceToEnemy \< closestEnemyDistance) { closestEnemyDistance = distanceToEnemy; closestEnemy = hit.transform; } } }** **return closestEnemy; }** 自行修改克隆攻击脚本中的一些代码 ### Crystal_Skill_Control脚本: **private Transform closestTarget;//最近的敌人目标** **if (canMoveToEnemy) { transform.position =Vector2.MoveTowards(transform.position,closestTarget.position,moveSpeed\*Time.deltaTime);//移动** **if(Vector2.Distance(transform.position,closestTarget.position)\<1f )//距离小于1时自毁 { FinishCrystal(); canMoveToEnemy = false; } }** ### Crystal_Skill脚本: **if(currentCrystal==null) { currentCrystal =Instantiate(crystalPrefab,player.transform.position,Quaternion.identity);** **Crystal_Skill_Control newcrystalScript= currentCrystal.GetComponent\();** **newcrystalScript.SetupCrystal(crystalDuration,canExplode,canMoveToEnemy,moveSpeed,FindClosetEnemy(currentCrystal.transform));//传入上面函数返回的最近敌人** **} else { if (canMoveToEnemy)//水晶移动时不可以换位 { return; }** **Vector2 playerPos= player.transform.position;** **player.transform.position = currentCrystal.transform.position;** **currentCrystal.transform.position = playerPos;** **currentCrystal.GetComponent\().FinishCrystal(); }** ## 4.实现多晶体 玩家可以拥有多个晶体并且可以一次性使用它们 ### Crystal_Skill脚本: **\[Header("Multi Stacking crystal")

SerializeField\] private bool canMultiStack;//是否可以使用多晶体 \[SerializeField\] private int amountofCrystal;//晶体数量 \[SerializeField\] private float MultiCrystalCooldown;//冷却时间 \[SerializeField\] private List\ crystalLeft=new List\();//预备储存晶体的列表** **if(canMultiCrystal())//update中 { return; }** **private bool canMultiCrystal()//是否能够发射多晶体 { if(canMultiStack) { if(crystalLeft.Count\>0)//如果列表里有晶体 { cooldown = 0;//可以连发 GameObject crystaclToSpawn = crystalLeft\[crystalLeft.Count-1\];//取最后一个晶体 GameObject newCrystal =Instantiate(crystaclToSpawn,player.transform.position,Quaternion.identity);//生成** **crystalLeft.Remove(crystaclToSpawn);//从列表中移除 Crystal_Skill_Control newcrystalScript = newCrystal.GetComponent\();** **newcrystalScript.SetupCrystal(crystalDuration, canExplode, canMoveToEnemy, moveSpeed, FindClosetEnemy(newCrystal.transform));** **if(crystalLeft.Count\<=0)//无晶体重新填装 { cooldown = MultiCrystalCooldown;//设置冷却 RefillCrystal(); }** **return true; } } return false; }** **public void RefillCrystal()//填装晶体 { for(int i = 0;i\ 0)//如果已经在冷却则返回 return;** **cooldown = MultiCrystalCooldown; RefillCrystal(); }** **if(crystalLeft.Count\>0) { if(amountofCrystal==crystalLeft.Count)//当发射出第一颗时延迟调用 { Invoke("ResetAbility", useTimeWindow); }**