本节最终效果演示
【独游开发记录】一个人开发的,类森林,七日杀生存游戏
文章目录
- 本节最终效果演示
- 系列目录
- 前言
- 泛型单例
- 添加声音
- 脚步声
- 鸭子动物音效
- 人物各种操作音效
- 砍树音效
- 效果
- 源码
- 完结
系列目录
前言
欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第23篇中,我们将探索如何制作一个类似于七日杀和森林的生存游戏。
本篇内容会比较多,我会分几篇来实现,感兴趣的可以关注一下,以免错过内容更新。
本节主要引入泛型单例和添加各种游戏音效。
泛型单例
随着脚本越来越多,重复配置单例无疑是相对麻烦的,这里写一个通用的泛型单例脚本,节约时间,优化带
//简单的泛型单例
public class Singleton<T> : MonoBehaviour where T : Component
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<T>();
if (instance == null)
{
GameObject newInstance = new GameObject();
instance = newInstance.AddComponent<T>();
}
}
return instance;
}
}
public void Awake()
{
instance = this as T;
}
}
使用参考
public class AudioManager : Singleton<AudioManager> {}
添加声音
声音就大家自行去找了,网上都挺多的
脚步声
【Unity小技巧】3D人物移动脚步和跳跃下落音效控制
获取人物移动状态,修改PlayerState
[Header("判断人物状态")]
public bool isMove;//是否在移动
public bool isWalking;//是否正在行走
public bool isRuning; //是否正在奔跑
public bool isCrouching; //是否正在下蹲
//。。。
private void Update()
{
isMove = MovementScript.Instance.isGround && MovementScript.Instance.moveDirection.sqrMagnitude > 0;
isRuning = MovementScript.Instance.isRun && isMove;
isCrouching = MovementScript.Instance.isCrouching;
isWalking = !isRuning && !isCrouching && isMove;
//。。。
}
脚步声控制
//脚步声
public class FootStepSound : MonoBehaviour
{
public LayerMask layerMask; // 检测层级
public RaycastHit hit; // 射线检测结果
public GameObject RayGo; // 射线起点对象
public AudioClip[] clipsMetal, clipsTree, clipsGrass, clipsDirt, clipsWater; // 不同类型表面的声音剪辑数组
public float dist = 2; // 射线的长度
private string tagProv; // 上一次射线检测到的地面标签
private int go = 0; // 控制播放声音的变量,0表示重新播放,1表示继续播放
public AudioSource AS; // 声音源组件
//该属性控制音频的播放速度,1.0 表示正常速度,小于 1.0 表示慢速播放,大于 1.0 表示快速播放。
public float PitchRun, PitchWalk, PitchCrouch;
// 创建一个列表用于存储之前选择过的音效索引
private List<int> playedIndexes = new List<int>();
//判断child是否是parent的子集
bool IsChildOf(Transform child, Transform parent)
{
while (child != null)
{
if (child == parent)
{
return true;
}
child = child.parent;
}
return false;
}
void Update()
{
if (PlayerState.Instance.isRuning)
AS.pitch = PitchRun; //则设置为奔跑音调
else if(PlayerState.Instance.isWalking){
AS.pitch = PitchWalk;
}else{
AS.pitch = PitchCrouch;
}
if (PlayerState.Instance.isMove)
{
if (Physics.Raycast(RayGo.transform.position, Vector3.down, out hit, dist, layerMask)) // 向下发射射线检测地面
{
if (hit.collider)
{
if (hit.collider.tag != tagProv) go = 0;
tagProv = hit.collider.tag;
switch (hit.collider.tag) // 根据地面的标签选择对应的声音类型
{
case "Metal":
PlayRandomSound(clipsMetal); // 播放金属声音
break;
case "Tree":
PlayRandomSound(clipsTree); // 播放树木声音
break;
case "Grass":
PlayRandomSound(clipsGrass); // 播放草地声音
break;
case "Dirt":
PlayRandomSound(clipsDirt); // 播放土地声音
break;
case "Water":
PlayRandomSound(clipsWater); // 播放水声音
break;
default:
StopSound(); // 停止播放声音
break;
}
}
}
}
else
{
// StopSound(); // 停止播放声音
}
}
// 从给定的声音剪辑数组中随机播放一个声音
void PlayRandomSound(AudioClip[] clips)
{
if (go == 0) // 如果需要重新设置音频剪辑
{
AS.clip = null;
go = 1;
}
if (!AS.isPlaying) // 如果当前没有正在播放的声音
{
// AS.clip = clips[Random.Range(0, clips.Length)]; // 随机选择一个声音剪辑
int randomIndex = GetUniqueRandomIndex(clips.Length); // 获取一个未播放过的随机索引
AS.clip = clips[randomIndex]; // 根据索引选择一个声音剪辑
AS.Play(); // 播放声音
}
}
// 获取一个未播放过的随机索引
int GetUniqueRandomIndex(int arrayLength)
{
int randomIndex;
do
{
randomIndex = Random.Range(0, arrayLength); // 生成一个随机索引
} while (playedIndexes.Contains(randomIndex)); // 循环判断该索引是否已经播放过
playedIndexes.Add(randomIndex); // 将新的索引添加到已播放列表中
if (playedIndexes.Count >= arrayLength)
{
playedIndexes.Clear(); // 如果已播放列表包含所有索引,则清空列表,重新开始播放
}
return randomIndex;
}
// 停止播放声音并重置go变量
void StopSound()
{
AS.Stop(); // 停止播放声音
go = 0; // 重置go变量
}
}
配置地面层级和标签,目前先只有一个地面Grass
配置代码
鸭子动物音效
本来打算开启直接播放音效的,但是声音太过密集了,所以这里用修改代码随机播放声音
配置因为鸭子的声音是3D的,所以需要修改AudioSource配置
代码随机默认声音,修改AI_Movement
[Header("声音")]
public AudioSource callAudioSource;
void Start()
{
//。。。
StartCoroutine(PlaySound());
}
IEnumerator PlaySound()
{
while (true)
{
yield return new WaitForSeconds(Random.Range(3, 10));
callAudioSource.Play();
}
}
配置
人物各种操作音效
可以看看之前这篇文章:【unity小技巧】Unity音乐和音效管理器
public class AudioManager : Singleton<AudioManager>
{
//定义音乐和音效的Sound数组
public Sound[] musicSounds, sfxSounds;
//音乐和音效的AudioSource
public AudioSource musicSource, sfxSource;
private void Start() {
PlayMusic("森林环境");
}
//播放音乐的方法,参数为音乐名称
public void PlayMusic(string name)
{
//从音乐Sounds数组中找到名字匹配的Sound对象
Sound s = Array.Find(musicSounds, x => x.name == name);
//如果找不到对应的Sound,输出错误信息
if (s == null)
{
Debug.Log("没有找到音乐");
}
//否则将音乐源的clip设置为对应Sound的clip并播放
else
{
musicSource.clip = s.clip;
musicSource.Play();
}
}
//播放音效的方法,参数为音效名称
public void PlaySFX(string name)
{
//从音效Sounds数组中找到名字匹配的Sound对象
Sound s = Array.Find(sfxSounds, x => x.name == name);
//如果找不到对应的Sound,输出错误信息
if (s == null)
{
Debug.Log("没有找到音效");
}
//否则播放对应Sound的clip
else
{
sfxSource.PlayOneShot(s.clip);
}
}
}
配置参数
调用案例
AudioManager.Instance.PlaySFX("制作");
砍树音效
新增TreeSound,控制树声
//树声控制
public class TreeSound : MonoBehaviour
{
[SerializeField] private AudioClip[] hitSounds; // 击中树声音数组
[SerializeField] private AudioClip fallSound; // 倒下声音
private AudioSource audioSource;
private void Start()
{
audioSource = GetComponent<AudioSource>();
}
//击中树声音
public void PlayHitAudio()
{
int n = UnityEngine.Random.Range(1, hitSounds.Length);
audioSource.clip = hitSounds[n]; // 随机选择一个声音
audioSource.PlayOneShot(audioSource.clip);
//播放过的脚步声放置第一位,避免连续播放相同的脚步声
hitSounds[n] = hitSounds[0];
hitSounds[0] = audioSource.clip;
}
//倒下声音
public void PlayFallAudio()
{
audioSource.clip = fallSound;
audioSource.Play();
}
}
挂载在树预制体上
修改ChoppableTree,调用
private TreeSound treeSound;
treeSound = GetComponent<TreeSound>();
treeSound.PlayHitAudio();
treeSound.PlayFallAudio();
效果
【独游开发记录】一个人开发的,类森林,七日杀生存游戏
源码
源码不出意外的话我会放在最后一节
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~