Hi I'm Shendi
小Bug修复
这个bug是之前没有初始化状态导致的,找好久才找到问题
问题如下:切换武器后开始游戏,火箭筒拥有第二个武器的攻速,切换到第二个武器,第二个武器拥有火箭筒的攻速...
经过查找后,发现是因为加成没有移除,然后就开始了游戏导致的
拥有加成会保存当前武器的攻速/冷却等,当加成移除,就会将当前武器的攻速/冷却恢复为保存的就导致这样的bug了
在 Main 中开始游戏处初始化即可
// 初始化加成
buffAttackTotol = 0;
buffCoolTotol = 0;
历史分数制作
因为最终是要发布为小游戏,所以这里历史分数就不做本地记录了,直接以数组+字典的方式记录
历史分数记录的是结算部分的几个数据就可以了,如下
- gold - 金币字符串
- score - 得分
- time - 时间
还可以将使用的武器记录
Main 中定义代码如下
public GameObject pageHistory;
/** 历史分数 */
public List<Dictionary<string,string>> scoreHisotry = new List<Dictionary<string, string>>();
将历史分数界面拖入摄像机的main部分
在 State 的结算中增加记录
/** 结算 */
public static void Settle()
{
int scoreGold = Main._instance.score / 50, resultGold = (int) (scoreGold + Main._instance.buffGold);
var goldText = resultGold + "(" + scoreGold + " + " + (int)(Main._instance.buffGold) + "(格外))";
Main._instance.settleGold.text = "金币:" + goldText;
gold += resultGold;
Main._instance.settleScore.text = "得分:" + Main._instance.score;
Main._instance.settleTime.text = "时间:" + (int)(Main._instance.time/50) + "秒";
Dictionary<string, string> map = new Dictionary<string, string>();
map.Add("gold", goldText);
map.Add("score", ""+Main._instance.score);
map.Add("time", (int)(Main._instance.time / 50) + "秒");
map.Add("weapon", State.playerWeapon.GetComponent<Weapon>().name);
Main._instance.scoreHisotry.Add(map);
}
界面制作
顶部同商店一样,一个标题一个关闭按钮
内容同之前使用 ScrollView,滚动视图,制作第一个将其作为预制体,在代码内动态生成就可以了
可以将商店的内容复制过来(商店需要先显示,否则复制的无法显示)
Main 中增加点击事件
/// <summary>
/// 历史分数页面是否显示
/// </summary>
/// <param name="isShow">true则显示,false隐藏</param>
public void PageScoreHistory(bool isShow)
{
if (isShow)
{
pageHistory.SetActive(true);
pageMain.SetActive(false);
}
else
{
pageHistory.SetActive(false);
pageMain.SetActive(true);
}
}
给关闭按钮与历史分数按钮增加点击事件,关闭按钮不勾选,历史分数按钮勾选
滚动视图部分,最开始展示最高分与最长坚持时间,然后后面都是记录列表
给滚动视图的Viewport下的Content增加 Verticle Layout Group
组件,这样 Content内的元素是上下排序,而不会重叠
在Content下新建一个面板,用来显示最高分数与最高坚持时间
如果面板没有显示,那么调整右边属性面板的宽度和高度
然后新建一个Panel,作为历史分数的模板,有序号和历史分数所保存的记录,效果如下
其中上面的1.字体大小20,其余文字字体大小18,将其拖入预制体文件夹
分数列表
在 State 中定义变量,拿到预制体
/** 历史分数面板 */
public static GameObject historyPanel = Resources.Load<GameObject>("Prefabs/scorePanel");
然后在显示历史面板时动态增加分数面板,在隐藏历史面板时销毁动态增加的分数面板
在Main中定义以下变量
/// <summary>
/// 最高分数
/// </summary>
[HideInInspector]
public int maxScore;
/// <summary>
/// 最高分数的ui
/// </summary>
public Text historyMaxScore;
/// <summary>
/// 最高时间
/// </summary>
[HideInInspector]
public int maxTime;
/// <summary>
/// 最高时间的ui
/// </summary>
public Text historyMaxTime;
/// <summary>
/// 历史分数的内容部分
/// </summary>
public GameObject historyContent;
将对象拖入摄像机的Main脚本中后,需要获取最高分与最长时间,在结算部分处理
State 中的 Settle 增加如下代码
// 是否为最高分,是则替换
if (Main._instance.score > Main._instance.maxScore)
{
Main._instance.maxScore = Main._instance.score;
}
// 是否为最长时,是则替换
if ((int)(Main._instance.time / 50) > Main._instance.maxTime)
{
Main._instance.maxTime = (int)(Main._instance.time / 50);
}
动态增加了物体后需要更改Content的高度,Main 中历史分数事件代码如下
/// <summary>
/// 历史分数页面是否显示
/// </summary>
/// <param name="isShow">true则显示,false隐藏</param>
public void PageScoreHistory(bool isShow)
{
if (isShow)
{
historyMaxScore.text = "最高分:" + maxScore;
historyMaxTime.text = "最高时间:" + maxTime;
// 倒序
for (var i = scoreHisotry.Count - 1; i >= 0; i--)
{
var map = scoreHisotry[i];
var historyPanel = Instantiate(State.historyPanel, historyContent.transform);
// 0序号,1得分,2金币,3时间,4武器
historyPanel.transform.GetChild(0).GetComponent<Text>().text = (i+1) + ".";
historyPanel.transform.GetChild(1).GetComponent<Text>().text = "得分:" + map["score"];
historyPanel.transform.GetChild(2).GetComponent<Text>().text = "金币:" + map["gold"];
historyPanel.transform.GetChild(3).GetComponent<Text>().text = "时间:" + map["time"];
historyPanel.transform.GetChild(4).GetComponent<Text>().text = "武器:" + map["weapon"];
}
// 更新Content高度
historyContent.GetComponent<RectTransform>().sizeDelta = new Vector2(historyContent.GetComponent<RectTransform>().sizeDelta.x,
scoreHisotry.Count * State.historyPanel.GetComponent<RectTransform>().sizeDelta.y + scoreHisotry.Count * 20 + 100);
pageHistory.SetActive(true);
pageMain.SetActive(false);
}
else
{
// 销毁 content 除0外的所有子对象
for (var i = 1; i < historyContent.transform.childCount; i++)
{
Destroy(historyContent.transform.GetChild(i).gameObject);
}
pageHistory.SetActive(false);
pageMain.SetActive(true);
}
}
金币部分字符串比较长,所以文本框对应的也要拉大一点,否则会导致显示不全的情况
这样,历史分数就制作完成了
音乐制作
制作游戏音乐我使用的 Audition
非专业,仅仅让游戏有个声音就可以了
目前就制作以下几个声音就可以了
- 首页背景音乐
- 方块被销毁的声音
- 游戏结束的声音
打开 Audtion,右键左上角空白处,新建,多轨混音项目,命名为background
新建完后就可以看到右边出现了多个轨道
背景音乐制作
从无到制作音乐可以使用 效果 - 生成部分的几个选项
在主轨道制作背景音乐主要的内容,背景音乐使用音调来制作,生成 - 音调
音乐会由多个音调组成,点击音调后,会要求创建一个音频文件,创建后就在音频文件内制作第一个音调
凡是须先研究,才会明白,这里有基频,调制深度,调制速率三个调节器,将其都置为0,调节后点击左下角播放听听有什么不同,以下是我试出来的效果
基频过低/过高都没有声音,基频越小,声音越偏向 “嘟”,越大,声音就越尖锐
调制深度于调制速率都是配合基频使用,基频没声音调整这两个也没声音
调制深度于速率也是配合使用(自行体会)
我生产的第一个音调是基频200,深度80,速率100,右边频率为150,振幅0,时间0.5秒
一个轻微嘟的声音,在末尾继续插入一个音调,这次调高一点,还是嘟,基频2000,深度300,速率100,频率200,时间0.5秒,声音为赌度,这样再来一个第一个音调比较好 - 嘟度嘟,复制前0.5秒或将播放杆拉到最后照着第一个音调在生成一个
第四个音调调的更高一点,基频4000,深度400,速率150,频率240,时间依然是0.5
有了这四个音调,开启循环播放试下效果,发现还可以,除了音调过少外
接下来就靠着多轨来生成更多的声音了,靠着重叠和裁剪声音,给整体加个噪音,在多轨 - 节拍器启用节拍器...
最终声音效果如下
方块被摧毁的声音
新建一个音频文件
首先一个音调比较高的声音(长),然后一个音调低点的声音(短)
第一个音调,基频1500,深度1000,速率800,频率300,时间0.3秒
第二个音调,基频800,深度300,速率250,频率180,时间0.2秒
将第一个音频分贝减少5
声音如下
游戏结束的声音
新建一个音频文件,游戏结束就一个很高的音调就可以了
就一个音调,基频18000,深度600,速率200,频率2200,持续时间0.3
再给其加个和声,效果 - 调制 - 和声,使用预设突发梦魇
声音如下
给游戏加入音乐
音乐制作好,在Unity内Assets下新建一个文件夹Audio作为音乐的文件夹
将背景音乐拖到摄像机下,其余两个音乐也拖到摄像机下,并将两个音乐的物体拖到预制体内
编写一个脚本,用于定时销毁,命名为TimeDestory,代码如下
/// <summary>
/// 多少秒后销毁,50一秒
/// </summary>
public int totol = 50;
private void FixedUpdate()
{
if (--totol < 0)
{
Destroy(gameObject);
}
}
将脚本拖给两个声音预制体,然后在 State 中拿到预制体
public static GameObject audioBox = Resources.Load<GameObject>("Prefabs/方块摧毁的声音");
public static GameObject audioGameOver = Resources.Load<GameObject>("Prefabs/游戏结束的声音");
在Main中的游戏结束与销毁方块部分播放声音
Instantiate(State.audioBox, transform);
Instantiate(State.audioGameOver, transform);
静音
有了声音就需要提供静音功能,在主界面右上角制作
在 State 中增加声音状态
/// <summary>
/// 声音是否开启
/// </summary>
public static bool isAudio = true;
在 Main 中增加点击事件
/// <summary>
/// 声音状态切换
/// </summary>
public void switchAudio()
{
var obj = EventSystem.current.currentSelectedGameObject;
if (State.isAudio)
{
obj.transform.GetChild(0).GetComponent<Text>().text = "开";
AudioListener.volume = 0;
}
else
{
obj.transform.GetChild(0).GetComponent<Text>().text = "关";
AudioListener.volume = 1;
}
State.isAudio = !State.isAudio;
}
本文链接:https://sdpro.top/blog/html/article/1073.html
♥ 赞助 ♥
尽管去做,或许最终的结果不尽人意,但你不付出,他不付出,那怎会进步呢?