Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考
此代码仅为较上一P有所改变的代码
【Unity教程】从0编程制作【Unity教程】从0编程制作
Blackhole_Hotkey_Controller.cs
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class Blackhole_Hotkey_Controller : MonoBehaviour
{
private SpriteRenderer sr;
private KeyCode myHotKey;
private TextMeshProUGUI myText;
private Transform myEnemy;
private Blackhole_Skill_Controller blackHole;
public void SetupHotKey(KeyCode _myNewHotKey, Transform _myEnemy, Blackhole_Skill_Controller _myBlackHole)
{
sr = GetComponent<SpriteRenderer>();
myText = GetComponentInChildren<TextMeshProUGUI>();
myEnemy = _myEnemy;
blackHole = _myBlackHole;
myHotKey = _myNewHotKey;
myText.text = myHotKey.ToString();
}
public void Update()
{
if(Input.GetKeyDown(myHotKey))
{
blackHole.AddEnemyToList(myEnemy);
myText.color = Color.clear;
sr.color = Color.clear;
}
}
}
Blackhole_Skill_Controller.cs
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class Blackhole_Skill_Controller : MonoBehaviour
{
[SerializeField] private GameObject hotKeyPrefab;
[SerializeField] private List<KeyCode> KeyCodeList;
public float maxSize;//最大尺寸
public float growSpeed;//变大速度
public bool canGrow;//是否可以变大
public float shrinkSpeed;//缩小速度
public bool canShrink;//缩小
public bool canCreateHotKeys = true;专门控制后面进入的没法生成热键
private bool cloneAttackReleased;
public int amountOfAttacks = 4;
public float cloneAttackCooldown = .3f;
private float cloneAttackTimer;
[SerializeField]private List<Transform> targets = new List<Transform>();
[SerializeField] private List<GameObject> createdHotKey = new List<GameObject>();
private void Update()
{
cloneAttackTimer -= Time.deltaTime;
if(Input.GetKeyDown(KeyCode.R))
{
cloneAttackReleased = true;
canCreateHotKeys = false;
DestroyHotKeys();
}
if(cloneAttackTimer < 0 && cloneAttackReleased)
{
cloneAttackTimer = cloneAttackCooldown;
int randomIndex = Random.Range(0, targets.Count);
//限制攻击次数和设置攻击偏移量
float _offset;
if (Random.Range(0, 100) > 50)
_offset = 2;
else
_offset = -2;
SkillManager.instance.clone.CreateClone(targets[randomIndex], new Vector3(_offset, 0, 0));
amountOfAttacks--;
if(amountOfAttacks <= 0)
{
canShrink = true;
cloneAttackReleased = false;
}
}
if(canGrow&&!canShrink)
{
//这是控制物体大小的参数
transform.localScale = Vector2.Lerp(transform.localScale, new Vector2(maxSize, maxSize), growSpeed * Time.deltaTime);
//类似MoveToward,不过是放大到多少大小 https://docs.unity3d.com/cn/current/ScriptReference/Vector2.Lerp.html
}
if(canShrink)
{
transform.localScale = Vector2.Lerp(transform.localScale, new Vector2(0, 0), shrinkSpeed * Time.deltaTime);
if(transform.localScale.x < 0)
{
Destroy(gameObject);
}
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.GetComponent<Enemy>()!=null)
{
collision.GetComponent<Enemy>().FreezeTime(true);
CreateHotKey(collision);
}
}
private void CreateHotKey(Collider2D collision)
{
if(KeyCodeList.Count == 0)//当所有的KeyCode都被去除,就不在创建实例
{
return;
}
if(!canCreateHotKeys)//这是当角色已经开大了,不在创建实例
{
return;
}
//创建实例
GameObject newHotKey = Instantiate(hotKeyPrefab, collision.transform.position + new Vector3(0, 2), Quaternion.identity);
//将实例添加进列表
createdHotKey.Add(newHotKey);
//随机KeyCode传给HotKey,并且传过去一个毁掉一个
KeyCode choosenKey = KeyCodeList[Random.Range(0, KeyCodeList.Count)];
KeyCodeList.Remove(choosenKey);
Blackhole_Hotkey_Controller newHotKeyScript = newHotKey.GetComponent<Blackhole_Hotkey_Controller>();
newHotKeyScript.SetupHotKey(choosenKey, collision.transform, this);
}
public void AddEnemyToList(Transform _myEnemy)
{
targets.Add(_myEnemy);
}
//销毁Hotkey
private void DestroyHotKeys()
{
if(createdHotKey.Count <= 0)
{
return;
}
for (int i = 0; i < createdHotKey.Count; i++)
{
Destroy(createdHotKey[i]);
}
}
}
Clone_Skill.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Clone_Skill : Skill
{
[Header("Clone Info")]
[SerializeField] private GameObject clonePrefab;//克隆原型
[SerializeField] private float cloneDuration;//克隆持续时间
[SerializeField] private bool canAttack;// 判断是否可以攻击
public void CreateClone(Transform _clonePosition,Vector3 _offset)//传入克隆位置
{
GameObject newClone = Instantiate(clonePrefab);//创建新的克隆//克隆 original 对象并返回克隆对象。
//https://docs.unity3d.com/cn/current/ScriptReference/Object.Instantiate.html
newClone.GetComponent<Clone_Skill_Controller>().SetupClone(_clonePosition,cloneDuration,canAttack,_offset);//调试clone的位置,同时调试克隆持续时间
//Controller绑在克隆原型上的,所以用GetComponents,
}
}
Clone_Skill_Controller.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//Clone_Skill_Controller是绑在Clone体上的也就是Prefah上的
public class Clone_Skill_Controller : MonoBehaviour
{
private Animator anim;//声明animator
private SpriteRenderer sr;//定义Sr
[SerializeField] private float colorLoosingSpeed;//加速消失时间
private float cloneTimer;//定时器
[SerializeField]private Transform attackCheck;
[SerializeField] private float attackCheckRadius = .8f;
private Transform closestEnemy;
private void Awake()
{
sr = GetComponent<SpriteRenderer>();//拿到Sr
anim = GetComponent<Animator>();//拿到anim
}
private void Update()
{
cloneTimer -= Time.deltaTime;
if(cloneTimer < 0)
{
sr.color = new Color(1, 1, 1,sr.color.a-(Time.deltaTime * colorLoosingSpeed));//设置sr消失
}
if(sr.color.a<0)
{
Destroy(gameObject);
}
}
public void SetupClone(Transform _newTransform,float _cloneDuration,bool _canAttack,Vector3 _offset)
{
if(_canAttack)
{
anim.SetInteger("AttackNumber", Random.Range(1, 3));//返回[minInclusive..maxInclusive](范围包括在内)内的随机浮点值。如果minInclusive大于maxInclusive,则数字会自动交换。
} //Random.Range()//https://docs.unity3d.com/cn/current/ScriptReference/Random.Range.html
transform.position = _newTransform.position+_offset;//这个函数实现了将克隆出来的对象的位置与Dash之前的位置重合的效果
cloneTimer = _cloneDuration;
FaceCloseTarget();
}
private void AnimationTrigger()
{
cloneTimer = -.1f;
}
private void AttackTrigger()
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(attackCheck.position, attackCheckRadius);//创建一个碰撞器组,保存所有圈所碰到的碰撞器
//https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Physics2D.OverlapCircleAll.html
foreach (var hit in colliders)//https://blog.csdn.net/m0_52358030/article/details/121722077
{
if (hit.GetComponent<Enemy>() != null)
{
hit.GetComponent<Enemy>().Damage();
}
}
}
private void FaceCloseTarget()
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 25);//找到环绕自己的所有碰撞器
float closestDistance = Mathf.Infinity;//正无穷大的表示形式(只读)
//https://docs.unity3d.com/cn/current/ScriptReference/Mathf.Infinity.html
foreach(var hit in colliders)
{
if(hit.GetComponent<Enemy>()!=null)
{
float distanceToEnemy = Vector2.Distance(transform.position, hit.transform.position);//拿到与敌人之间的距离
if(distanceToEnemy < closestDistance)//比较距离,如果离得更近,保存这个敌人的位置,更改最近距离
{
closestDistance = distanceToEnemy;
closestEnemy = hit.transform;
}
}
}
if(closestEnemy != null)
{
if(transform.position.x>closestEnemy.position.x)//敌人在左面,转一圈
{
transform.Rotate(0,180,0);
}
}
}
}
PlayerDashState.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerDashState : PlayerState
{ //由Ground进入
public PlayerDashState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName)
{
}
public override void Enter()
{
base.Enter();
player.skill.clone.CreateClone(player.transform,new Vector3(0,0,0));//调用克隆函数,并传入当前位置已调试clone的位置
stateTimer = player.dashDuration;设置Dash可以保持的值
}
public override void Exit()
{
base.Exit();
player.SetVelocity(0, rb.velocity.y);//当退出时使速度为0防止动作结束后速度不变导致的持续移动
}
public override void Update()
{
base.Update();
if(!player.IsGroundDetected()&&player.IsWallDetected())//修复无法在空中dash直接进入wallSlide,修复在wallslide可以dash
//因为一旦在wallSlide里dash,就会直接进wallSlide,当然还有更简单的方法
{
stateMachine.ChangeState(player.wallSlide);
}
player.SetVelocity(player.dashSpeed * player.dashDir, 0);//这个写在Update里,防止在x轴方向减速了,同时Y轴写成0,以防止dash还没有完成就从空中掉下去了
if (stateTimer < 0)当timer小于0,切换
{
stateMachine.ChangeState(player.idleState);
}
}
}