1.准心判定
2.UI提示
2.1 开头标题提示
- 在主界面的canvas划定区域给DisplayMessage,挂上UITable脚本:
- UI Table代码:
using UnityEngine;
namespace Unity.FPS.UI
{
// The component that is used to display the Objectives, the Notification and the game messages like a list
// When a new one is created, the previous ones move down to make room for the new one
public class UITable : MonoBehaviour
{
[Tooltip("How much space should there be between items?")]
public float Offset;
[Tooltip("Add new the new items below existing items.")]
public bool Down;
public void UpdateTable(GameObject newItem)
{
if (newItem != null)
newItem.GetComponent<RectTransform>().localScale = Vector3.one;
float height = 0;
for (int i = 0; i < transform.childCount; i++)
{
RectTransform child = transform.GetChild(i).GetComponent<RectTransform>();
Vector2 size = child.sizeDelta;
height += Down ? -(1 - child.pivot.y) * size.y : (1 - child.pivot.y) * size.y;
if (i != 0)
height += Down ? -Offset : Offset;
Vector2 newPos = Vector2.zero;
newPos.y = height;
newPos.x = 0;//-child.pivot.x * size.x * hi.localScale.x;
child.anchoredPosition = newPos;
}
}
}
}
- 空物体上挂载脚本
- 有两个脚本 一个是大类objective,一个是使用objective的objectiveKillEnemies。
- title的Objective代码片:
using System;
using UnityEngine;
namespace Unity.FPS.Game
{
public abstract class Objective : MonoBehaviour
{
[Tooltip("Name of the objective that will be shown on screen")]
public string Title;
protected virtual void Start()
{
DisplayMessageEvent displayMessage = Events.DisplayMessageEvent;
displayMessage.Message = Title;
displayMessage.DelayBeforeDisplay = 0.0f;//暂时未知作用
EventManager.Broadcast(displayMessage);
}
- ObjectiveKillEnemy:
using Unity.FPS.Game;
using UnityEngine;
namespace Unity.FPS.Gameplay
{
public class ObjectiveKillEnemies : Objective
{
protected override void Start()
{
base.Start();
EventManager.AddListener<EnemyKillEvent>(OnEnemyKilled);
// set a title and description specific for this type of objective, if it hasn't one
if (string.IsNullOrEmpty(Title))
Title = "Eliminate " + "all the" +
" enemies";//可以并到objective里
}
}
2.1 血条
- WorldHealthBar:
using Unity.FPS.Game;//这里用的health是从这个命名传过来
using UnityEngine;
using UnityEngine.UI;
namespace Unity.FPS.UI
{
public class WorldspaceHealthBar : MonoBehaviour
{
[Tooltip("Health component to track")] public Health Health;//要用Health函数
[Tooltip("Image component displaying health left")]
public Image HealthBarImage;
[Tooltip("The floating healthbar pivot transform")]
public Transform HealthBarPivot;
[Tooltip("Whether the health bar is visible when at full health or not")]
public bool HideFullHealthBar = true;
void Update()
{
// update health bar value
HealthBarImage.fillAmount = Health.CurrentHealth / Health.MaxHealth;
// rotate health bar to face the camera/player
HealthBarPivot.LookAt(Camera.main.transform.position);
// hide health bar if needed
if (HideFullHealthBar)
HealthBarPivot.gameObject.SetActive(HealthBarImage.fillAmount != 1);
}
}
}
- 传入的Health函数:
health脚本挂在敌人以及角色身上
using UnityEngine;
using UnityEngine.Events;
namespace Unity.FPS.Game
{
public class Health : MonoBehaviour
{
[Tooltip("Maximum amount of health")] public float MaxHealth = 10f;
[Tooltip("Health ratio at which the critical health vignette starts appearing")]
public float CriticalHealthRatio = 0.3f;//回血速度 不用
public UnityAction<float, GameObject> OnDamaged;
//public UnityAction<float> OnHealed;
public UnityAction OnDie;
public float CurrentHealth { get; set; }
public float GetRatio() => CurrentHealth / MaxHealth;//计算比值
bool m_IsDead;
void Start()
{
CurrentHealth = MaxHealth;
}
public void TakeDamage(float damage, GameObject damageSource)
{
float healthBefore = CurrentHealth;
CurrentHealth -= damage;
CurrentHealth = Mathf.Clamp(CurrentHealth, 0f, MaxHealth);
// call OnDamage action
float trueDamageAmount = healthBefore - CurrentHealth;
if (trueDamageAmount > 0f)
{
OnDamaged?.Invoke(trueDamageAmount, damageSource);
}
HandleDeath();
}
public void Kill()
{
CurrentHealth = 0f;
// call OnDamage action
OnDamaged?.Invoke(MaxHealth, null);
HandleDeath();
}
void HandleDeath()
{
if (m_IsDead)
return;
// call OnDie action
if (CurrentHealth <= 0f)
{
m_IsDead = true;
OnDie?.Invoke();
}
}
}
}
2.2 敌人血条UI设置:
2.3 自身血条UI设置
3. Emeny
- 总挂载脚本:
- hierarchy设置
3.1 发现
- 接近一定距离后转身攻击。/不用攻击
在这里插入代码片
5. 准心瞄准系统
5.1 UI界面设置
-
先放置一个大区域【空物体】,挂载上UItable脚本,再把设置为准心的UI放在中间。
-
第一人称脚本设置
示例是挂载在武器的preb上,可以见一个空物体或者瞄准框作为武器。
- 代码:
//建立准心的定义类,未瞄中时用一个,瞄中了用一个。
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace Unity.FPS.Game
{
[System.Serializable]
public struct CrosshairData
{
[Tooltip("The image that will be used for this weapon's crosshair")]
public Sprite CrosshairSprite;
[Tooltip("The size of the crosshair image")]
public int CrosshairSize;
[Tooltip("The color of the crosshair image")]
public Color CrosshairColor;
}
public class WeaponController : MonoBehaviour
{
[Tooltip("Default data for the crosshair")]
public CrosshairData CrosshairDataDefault;//default
[Tooltip("Data for the crosshair when targeting an enemy")]
public CrosshairData CrosshairDataTargetInSight;//瞄准了
}
}
- 准心控制函数
using Unity.FPS.Game;
using Unity.FPS.Gameplay;
using UnityEngine;
using UnityEngine.UI;
namespace Unity.FPS.UI
{
public class CrosshairManager : MonoBehaviour
{
public Image CrosshairImage;
public Sprite NullCrosshairSprite;
public float CrosshairUpdateshrpness = 5f;
PlayerWeaponsManager m_WeaponsManager;
bool m_WasPointingAtEnemy;
RectTransform m_CrosshairRectTransform;//图层
CrosshairData m_CrosshairDataDefault;
CrosshairData m_CrosshairDataTarget;
CrosshairData m_CurrentCrosshair;
void Start()
{
m_WeaponsManager = GameObject.FindObjectOfType<PlayerWeaponsManager>();
DebugUtility.HandleErrorIfNullFindObject<PlayerWeaponsManager, CrosshairManager>(m_WeaponsManager, this);
OnWeaponChanged(m_WeaponsManager.GetActiveWeapon());
m_WeaponsManager.OnSwitchedToWeapon += OnWeaponChanged;
}
void Update()
{
UpdateCrosshairPointingAtEnemy(false);
m_WasPointingAtEnemy = m_WeaponsManager.IsPointingAtEnemy;
}
void UpdateCrosshairPointingAtEnemy(bool force)
{
if (m_CrosshairDataDefault.CrosshairSprite == null)
return;
if ((force || !m_WasPointingAtEnemy) && m_WeaponsManager.IsPointingAtEnemy)
{
m_CurrentCrosshair = m_CrosshairDataTarget;
CrosshairImage.sprite = m_CurrentCrosshair.CrosshairSprite;
m_CrosshairRectTransform.sizeDelta = m_CurrentCrosshair.CrosshairSize * Vector2.one;
}
else if ((force || m_WasPointingAtEnemy) && !m_WeaponsManager.IsPointingAtEnemy)
{
m_CurrentCrosshair = m_CrosshairDataDefault;
CrosshairImage.sprite = m_CurrentCrosshair.CrosshairSprite;
m_CrosshairRectTransform.sizeDelta = m_CurrentCrosshair.CrosshairSize * Vector2.one;
}
CrosshairImage.color = Color.Lerp(CrosshairImage.color, m_CurrentCrosshair.CrosshairColor,
Time.deltaTime * CrosshairUpdateshrpness);
m_CrosshairRectTransform.sizeDelta = Mathf.Lerp(m_CrosshairRectTransform.sizeDelta.x,
m_CurrentCrosshair.CrosshairSize,
Time.deltaTime * CrosshairUpdateshrpness) * Vector2.one;
}
void OnWeaponChanged(WeaponController newWeapon)
{
if (newWeapon)
{
CrosshairImage.enabled = true;
m_CrosshairDataDefault = newWeapon.CrosshairDataDefault;
m_CrosshairDataTarget = newWeapon.CrosshairDataTargetInSight;
m_CrosshairRectTransform = CrosshairImage.GetComponent<RectTransform>();
DebugUtility.HandleErrorIfNullGetComponent<RectTransform, CrosshairManager>(m_CrosshairRectTransform,
this, CrosshairImage.gameObject);
}
else
{
if (NullCrosshairSprite)
{
CrosshairImage.sprite = NullCrosshairSprite;
}
else
{
CrosshairImage.enabled = false;
}
}
UpdateCrosshairPointingAtEnemy(true);
}
}
}