Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考
此代码仅为较上一P有所改变的代码
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili
AudioManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioManager : MonoBehaviour
{
public static AudioManager instance;
[SerializeField] private float sfxMinimumDistance;
[SerializeField] private AudioSource[] sfx;
[SerializeField] private AudioSource[] bgm;
public bool playBgm;
private int bgmIndex;
private void Awake()
{
if (instance != null)
{
Destroy(instance.gameObject);
}
else
instance = this;
}
private void Update()
{
if (!playBgm)
StopAllBGM();
else
{
if (!bgm[bgmIndex].isPlaying)
PlayBGM(bgmIndex);
}
}
public void PlaySFX(int _sfxIndex,Transform _source)
{
//if (sfx[_sfxIndex].isPlaying)//防止出现多个相同物体同时发出声音
//{
// return;
//}
if (_source != null && Vector2.Distance(PlayerManager.instance.player.transform.position, _source.position) > sfxMinimumDistance)//防止东西很远的情况下发出声音
return;
if(_sfxIndex < sfx.Length)
{
sfx[_sfxIndex].pitch = Random.Range(.85f, 1.1f);
sfx[_sfxIndex].Play();
}
}
public void StopSFX(int _sfxIndex)
{
sfx[_sfxIndex].Stop();
}
public void PlayRandomBGM()
{
bgmIndex = Random.Range(0, bgm.Length);
PlayBGM(bgmIndex);
}
public void PlayBGM(int _bgmIndex)
{
bgmIndex = _bgmIndex;
StopAllBGM();
if (_bgmIndex < sfx.Length)
{
bgm[_bgmIndex].Play();
}
}
public void StopAllBGM()
{
for(int i = 0; i < bgm.Length; i++)
{
bgm[i].Stop();
}
}
}
Checkpoint.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Checkpoint : MonoBehaviour
{
private Animator anim;
public string id;
public bool activationStatus;
private void Awake()
{
anim = GetComponent<Animator>();
}
private void Start()
{
anim = GetComponent<Animator>();
}
[ContextMenu("Generate checkpoint id")]
private void GenerateId()//制作ID函数
{
id = System.Guid.NewGuid().ToString();//不根据path,直接生成id
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.GetComponent<Player>()!=null)
{
ActivateCheckpoint();
}
}
public void ActivateCheckpoint()//激活检查点函数
{
if (activationStatus == false)
AudioManager.instance.PlaySFX(5, transform);
anim.SetBool("active", true);
activationStatus = true;
}
}
ItemObject.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemObject : MonoBehaviour
{
private SpriteRenderer sr;
[SerializeField] private Rigidbody2D rb;//设置速度
[SerializeField] private ItemData ItemData;
[SerializeField] private Vector2 velocity;//设置速度
private void SetupVisuals()
{
if (ItemData == null)
return;
GetComponent<SpriteRenderer>().sprite = ItemData.icon;
gameObject.name = ItemData.name;
}
public void SetupItem(ItemData _itemData,Vector2 _velocity)设置实例函数
{
ItemData = _itemData;
rb.velocity = _velocity;//设置速度
SetupVisuals();
}
public void PickupItem()//拾取函数打包
{
if(!Inventory.instance.CanAddItem()&&ItemData.itemType == ItemType.Equipment)//修复在Inventory满时捡钱装备并销毁它的bug
{
rb.velocity = new Vector2(0, 7);
return;
}
AudioManager.instance.PlaySFX(18, transform);
Inventory.instance.AddItem(ItemData);
Destroy(gameObject);
}
}
Skill.cs
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class Skill : MonoBehaviour
{
public float cooldown;
public float cooldownTimer;
protected Player player;//拿到player
protected virtual void Start()
{
player = PlayerManager.instance.player;//拿到player
CheckUnlock();
}
protected virtual void Update()
{
cooldownTimer -= Time.deltaTime;
}
protected virtual void CheckUnlock()//再次打开游戏时读取数据文件后使技能可以使用的函数
{
}
public virtual bool CanUseSkill()
{
if (cooldownTimer < 0)
{
UseSkill();
cooldownTimer = cooldown;
return true;
}
else
{
Debug.Log("Skill is on cooldown");
return false;
}
}
public virtual void UseSkill()
{
// do some skill thing
}
//整理能返回最近敌人位置的函数
protected virtual Transform FindClosestEnemy(Transform _checkTransform)
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(_checkTransform.position, 25);//找到环绕自己的所有碰撞器
float closestDistance = Mathf.Infinity;//正无穷大的表示形式(只读)
Transform closestEnemy = null;
//https://docs.unity3d.com/cn/current/ScriptReference/Mathf.Infinity.html
foreach (var hit in colliders)
{
if (hit.GetComponent<Enemy>() != null)
{
float distanceToEnemy = Vector2.Distance(_checkTransform.position, hit.transform.position);//拿到与敌人之间的距离
if (distanceToEnemy < closestDistance)//比较距离,如果离得更近,保存这个敌人的位置,更改最近距离
{
closestDistance = distanceToEnemy;
closestEnemy = hit.transform;
}
}
}
return closestEnemy;
}
}
Blackhole_Skill.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Blackhole_Skill : Skill
{
[SerializeField] private UI_SkillTreeSlot balckholeUnlockButton;
public bool blackholeUnlocked { get; private set; }
[SerializeField]private float maxSize;//最大尺寸
[SerializeField] private float growSpeed;//变大速度
[SerializeField] private float shrinkSpeed;//缩小速度
[SerializeField] private GameObject blackholePrefab;
[Space]
[SerializeField] private float blackholeDuration;
[SerializeField] int amountOfAttacks = 4;
[SerializeField] float cloneAttackCooldown = .3f;
Blackhole_Skill_Controller currentBlackhole;
private void UnlockBlackhole()
{
if(balckholeUnlockButton.unlocked)
{
blackholeUnlocked = true;
}
}
public override bool CanUseSkill()
{
return base.CanUseSkill();
}
public override void UseSkill()
{
base.UseSkill();
GameObject newBlackhole = Instantiate(blackholePrefab,player.transform.position,Quaternion.identity);
currentBlackhole = newBlackhole.GetComponent<Blackhole_Skill_Controller>();
currentBlackhole.SetupBlackhole(maxSize,growSpeed,shrinkSpeed,amountOfAttacks,cloneAttackCooldown,blackholeDuration);
AudioManager.instance.PlaySFX(3, player.transform);
AudioManager.instance.PlaySFX(6, player.transform);
}
protected override void Start()
{
base.Start();
balckholeUnlockButton.GetComponent<Button>().onClick.AddListener(UnlockBlackhole);
}
protected override void Update()
{
base.Update();
}
public bool SkillCompleted()
{
if(currentBlackhole == null)
return false;
if (currentBlackhole.playerCanExitState)
{
return true;
}
else
{
return false;
}
}
//把随机敌人半径改成黑洞半径的一半就行
public float GetBlackholeRadius()
{
return maxSize / 2;
}
protected override void CheckUnlock()
{
base.CheckUnlock();
UnlockBlackhole();
}
}
PlayerGroundState.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//GroundState用于保证只有在Idle和Move这两个地面状态下才能调用某些函数,并且稍微减少一点代码量
public class PlayerGroundState : PlayerState
{
public PlayerGroundState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName)
{
}
public override void Enter()
{
base.Enter();
}
public override void Exit()
{
base.Exit();
}
public override void Update()
{
base.Update();
if(Input.GetKeyDown(KeyCode.R)&& player.skill.blackhole.blackholeUnlocked)
{
if (player.skill.blackhole.cooldown > 0)
return;
stateMachine.ChangeState(player.blackhole);
}
if(Input.GetKeyDown(KeyCode.Mouse1)&&HasNoSword() && player.skill.sword.swordUnlocked)//点击右键进入瞄准状态,当sword存在时,不能进入aim状态
{
stateMachine.ChangeState(player.aimSword);
}
if(Input.GetKeyDown(KeyCode.Q) && player.skill.parry.parryUnlocked)//摁Q进入反击状态
{
stateMachine.ChangeState(player.counterAttack);
}
if(Input.GetKeyDown(KeyCode.Mouse0))//p38 2.从ground进入攻击状态
{
stateMachine.ChangeState(player.primaryAttack);
}
if(player.IsGroundDetected()==false)
{
stateMachine.ChangeState(player.airState);
}// 写这个是为了防止在空中直接切换为moveState了。
if (Input.GetKeyDown(KeyCode.Space) && player.IsGroundDetected())
{
stateMachine.ChangeState(player.jumpState);
}//空格切换为跳跃状态
}
private bool HasNoSword()//用这个函数同时控制了是否能进入aimSword和如果sword存在便使他回归player的功能
{
if(!player.sword)
{
return true;
}
player.sword.GetComponent<Sword_Skill_Controller>().ReturnSword();
return false;
}
}
PlayerMoveState.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMoveState : PlayerGroundState
{
public PlayerMoveState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName)
{
}//构造函数,用于传递信息。
//当外补New出对象时,New出的对象里传入参数
public override void Enter()
{
base.Enter();
AudioManager.instance.PlaySFX(14,null);
}
public override void Exit()
{
base.Exit();
AudioManager.instance.StopSFX(14);
}
public override void Update()
{
base.Update();
player.SetVelocity(xInput*player.moveSpeed, rb.velocity.y);//player.rb.newVelocity.y默认的为0,player.moveSpeed在player中定义,但可以在Unity引擎中更改
if (xInput==0|| player.IsWallDetected())
{
stateMachine.ChangeState(player.idleState);//在这里我们能使用Player里的东西,主要是因为我们通过构造函数传过来Player实体,如果不传,则无法使用已经存在了的Player实体。
}
}
}