006_2D Ruby 项目脚本
CogBulletController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CogBulletController : MonoBehaviour {
Rigidbody2D rigidbody2D;
// Start is called before the first frame update
void Start() {
}
private void Awake() {
rigidbody2D = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update() {
//飞行距离超过100单位后,自动销毁
if(transform.position.magnitude > 100f) {
Destroy(gameObject);
}
}
//direction:方向,force:力
public void Launch(Vector2 direction, float force) {
//对游戏对象施加一个力,使其移动
rigidbody2D.AddForce(direction * force);
}
private void OnCollisionEnter2D(Collision2D collision) {
//获取子弹碰撞到的游戏对象脚步组件
EnemyController enemyController = collision.gameObject.GetComponent<EnemyController>();
if (enemyController != null) {
enemyController.Fix();
}
//打印子弹碰撞到的游戏对象
Debug.Log($"齿轮子弹碰撞到了: {collision.gameObject}");
//销毁子弹
Destroy(gameObject);
}
}
DamageZone.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DamageZone : MonoBehaviour
{
//每次掉血量
public int damageNum = -1;
//刚体在触发器内的每一帧都会调用此函数,而不是在刚体刚进入时仅调用一次。
private void OnTriggerStay2D(Collider2D collision)
{
RubyController rubyController = collision.gameObject.GetComponent<RubyController>();
if(rubyController != null )
{
rubyController.ChangeHealth(damageNum);
}
}
}
EnemyController.cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class EnemyController : MonoBehaviour {
//每次掉血量
public int damageNum = -1;
//敌人移动速度
public float speed = 3f;
//声明刚体对象
Rigidbody2D rigidbody2D;
//移动方向
public float horizontal = 0;
public float vertical = 1;
//移动时间
public float moveTime = 3;
//移动计时器
float moveTimer;
//动画管理组件
Animator animator;
//粒子系统
public ParticleSystem smokeEffect;
//robot是否修复
bool repaired;
AudioSource audioSource;
private void Start() {
rigidbody2D = GetComponent<Rigidbody2D>();
moveTimer = moveTime;
animator = GetComponent<Animator>();
audioSource = GetComponent<AudioSource>();
}
private void Update() {
//如果robot已修复,就不再移动
if (repaired) {
return;
}
moveTimer -= Time.deltaTime;
if (moveTimer < 0) {
vertical *= -1;
horizontal *= -1;
moveTimer = moveTime;
}
}
//固定时间间隔执行的更新方法
private void FixedUpdate() {
//如果robot已修复,就不再移动
if (repaired) {
return;
}
//获取对象当前位置
Vector2 position = rigidbody2D.position;
//更改位置,Time.deltaTime 每帧的时间间隔,float 类型
position.x = position.x + speed * horizontal * Time.deltaTime;
position.y = position.y + speed * vertical * Time.deltaTime;
//新位置给游戏对象
rigidbody2D.position = position;
animator.SetFloat("Move X", position.x);
animator.SetFloat("Move Y", position.y);
}
//刚体碰撞事件方法
private void OnCollisionEnter2D(Collision2D collision) {
RubyController rubyController = collision.gameObject.GetComponent<RubyController>();
if (rubyController != null) {
rubyController.ChangeHealth(damageNum);
}
}
public void Fix() {
//robot已修复
repaired = true;
//让robot不再受碰撞,刚体对象取消物理引擎效果
rigidbody2D.simulated = false;
//播放修复后的动画
animator.SetTrigger("Fixed");
//特效在生命周期后停止
smokeEffect.Stop();
audioSource.Stop();
}
}
HealthCollectible.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HealthCollectible : MonoBehaviour
{
public AudioClip collectedClip;
//音频音量
public float soundVol = 1.0f;
//草莓加的血量
public int amount = 1;
//碰撞次数
int collideCount;
//添加触发器碰撞事件
private void OnTriggerEnter2D(Collider2D collision)
{
collideCount++;
Debug.Log($"和当前物体发生碰撞的对象是:{collision},当前是第{collideCount}次碰撞!");
//获取Ruby游戏对象的脚本组件对象
RubyController rubyController = collision.GetComponent<RubyController>();
if (rubyController != null)
{
Debug.Log($"ruby health is {rubyController.health}");
if (rubyController.health < rubyController.maxHealth)
{
//更改血量
rubyController.ChangeHealth(amount);
//销毁当前游戏对象:草莓
Destroy(gameObject);
//播放吃草莓的音频
rubyController.PlaySound(collectedClip, soundVol);
}
else
{
Debug.Log("当前玩家角色生命是满的,不需要加血");
}
}
else
{
Debug.LogError("rubyController游戏组件并未获取到");
}
}
}
NonPlayerCharacter.cs
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class NonPlayerCharacter : MonoBehaviour {
//对话显示时长
public float displayTime = 4.0f;
//对话框游戏对象
public GameObject dialogBox;
//文本框计时器
float displayTimer;
//TMP控件
public GameObject tmpGameObject;
//游戏组件类
TextMeshProUGUI tmpTextBox;
//当前页数
int currentPage = 1;
//总页数
int totalPages;
// Start is called before the first frame update
void Start() {
//游戏开始不显示对话框
dialogBox.SetActive(false);
//计时器开始不可用
displayTimer = -1.0f;
tmpTextBox = tmpGameObject.GetComponent<TextMeshProUGUI>();
}
// Update is called once per frame
void Update() {
if (displayTimer >= 0.0f) {
//循环翻页
if (Input.GetKeyDown(KeyCode.Space)) {
if (currentPage < totalPages) {
currentPage++;
} else {
currentPage = 1;
}
tmpTextBox.pageToDisplay = currentPage;
}
displayTimer -= Time.deltaTime;
} else {
dialogBox.SetActive(false);
}
}
public void DisplayDialog() {
//获取对话框总页数
totalPages = tmpTextBox.textInfo.pageCount;
//重置对话框显示时间
displayTimer = displayTime;
dialogBox.SetActive(true);
}
}
RubyController.cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.PlayerLoop;
using UnityEngine.UIElements;
using UnityEngine.WSA;
public class RubyController : MonoBehaviour {
//声明音频源对象,用来后期进行音频播放控制
AudioSource audioSource;
//子弹预制件对象
public GameObject cogBulletPrefab;
//无敌时间
public float invincibleTime = 2.0f;
//无敌时间计时器
public float invincibleTimer;
//是否无敌的标志
bool isInvincible;
//最大生命值
public int maxHealth = 5;
//C#中支持面向对象程序设计中的封装概念,对数据成员的保护
//数据成员变量,默认一般都应该设置为私有,只能通过当前类的方法或属性进行访问
//属性是公有的,可以通过取值器get、赋值器 set设定对应字段的访问规则,满足规则才能够访问
public int health {
get { return currentHealth; }
//set { currentHealth = value; }
}
//当前生命值
int currentHealth;
// 将速度暴露出来,使其可调
public float speed = 4f;
//声明刚体对象
Rigidbody2D rigidbody2D;
//获取用户输入
public float horizontal = 0f;
public float vertical = 0f;
//动画管理组件
Animator animator;
Vector2 move;
// 在第一次帧更新之前调用 Start
private void Start() {
//获取当前游戏对象的刚体组件
rigidbody2D = GetComponent<Rigidbody2D>();
//游戏开始,玩家满血
currentHealth = 3;
Debug.Log($"currentHealth:{currentHealth}");
move = new Vector2(1, 0);
animator = GetComponent<Animator>();
audioSource = GetComponent<AudioSource>();
}
// 每帧调用一次 Update
void Update() {
/* 根据按键移动上下左右的位置:每帧移动0.1 */
//获取水平输入,按向左会获得-1.0f,按向右会获得1.0f
horizontal = Input.GetAxis("Horizontal");
//获取垂直输入按向下会获得-1.0f,按向上会获得1.0f
vertical = Input.GetAxis("Vertical");
if (!Mathf.Approximately(horizontal, 0f) || !Mathf.Approximately(vertical, 0f)) {
move = new Vector2(horizontal, vertical);
move.Normalize();
animator.SetFloat("Look X", move.x);
animator.SetFloat("Look Y", move.y);
animator.SetFloat("Speed", move.magnitude);
} else {
animator.SetFloat("Speed", 0);
}
//是否处于无敌状态
if (isInvincible) {
//无敌计数器减去一帧的时间
invincibleTimer -= Time.deltaTime;
if (invincibleTimer < 0) {
isInvincible = false;
}
}
//按住Shift加快移速
if(Input.GetKeyDown(KeyCode.LeftShift)) {
speed = 8f;
} else if(Input.GetKeyUp(KeyCode.LeftShift)) {
speed = 4f;
}
//按下鼠标左键发射子弹
if (Input.GetMouseButtonDown(0)) {
Launch();
}
if(Input.GetKeyDown(KeyCode.E)) {
//创建射线投射碰撞对象,接收射线投射碰撞信息
//参数1:射线投射的位置
//参数2:投射方向
//参数3:投射距离
//参数4:射线生效的层
RaycastHit2D hit = Physics2D.Raycast(rigidbody2D.position + Vector2.up * 0.2f, move, 1.5f, LayerMask.GetMask("NPC"));
if (hit.collider != null) {
Debug.Log($"射线投射碰撞到的对象是:{hit.collider.gameObject}");
NonPlayerCharacter npc = hit.collider.GetComponent<NonPlayerCharacter>();
if (npc != null) {
npc.DisplayDialog();
}
}
}
}
//固定时间间隔执行的更新方法
private void FixedUpdate() {
//获取对象当前位置
Vector2 position = rigidbody2D.position;
//更改位置,Time.deltaTime 每帧的时间间隔,float 类型
position.x = position.x + speed * horizontal * Time.deltaTime;
position.y = position.y + speed * vertical * Time.deltaTime;
//新位置给游戏对象
rigidbody2D.position = position;
}
//更改生命值的方法
public void ChangeHealth(int amount) {
if (amount < 0) {
animator.SetTrigger("Hit");
if (isInvincible) {
return;
}
isInvincible = true;
invincibleTimer = invincibleTime;
}
//限制方法,限制当前生命值的赋值范围:0~最大生命值
currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
Debug.Log("当前生命值:" + currentHealth + "/" + maxHealth);
UIHealthBar.instance.SetValue(currentHealth/(float)maxHealth);
}
private void Launch() {
//创建子弹游戏对象
GameObject cogBulletObject = Instantiate(cogBulletPrefab, rigidbody2D.position + Vector2.up * 0.5f, Quaternion.identity);
//获取子弹游戏对象的脚步组件
CogBulletController cogBullet = cogBulletObject.GetComponent<CogBulletController>();
//通过脚步对象调用子弹移动的方法
//params:移动的方向,力
cogBullet.Launch(move, 600);
//发射动画
animator.SetTrigger("Launch");
}
//播放音频
public void PlaySound(AudioClip audioClip, float soundVol) {
audioSource.PlayOneShot(audioClip, soundVol);
}
}
UIHealthBar.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIHealthBar : MonoBehaviour {
//创建公有静态成员,获取当前血条本身
public static UIHealthBar instance { get; private set; }
public Image mask;
float originalSize;
void Awake() {
instance = this;
}
// Start is called before the first frame update
void Start() {
//获取遮罩层图形的初始宽度
originalSize = mask.rectTransform.rect.width;
}
// Update is called once per frame
void Update() {
}
public void SetValue(float value) {
//设置mask遮罩层的宽度
mask.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, originalSize*value);
}
}