1. 开始场景搭建
创建场景,自己去搭建,没有技术难点。
丰富场景视觉效果
可以设置一些脚本,让场景中的物品来回移动。
比如,让金币上下移动和旋转。
using UnityEngine;
public class GoldUpDown : MonoBehaviour
{
[SerializeField]float upDownSpeed = 0.05f;
[SerializeField] float rotateSpeed = 130f;
void Update()
{
transform.Translate(0, upDownSpeed * Time.deltaTime, 0, Space.Self);
transform.Rotate(Vector3.up, rotateSpeed * Time.deltaTime);
if(transform.position.y > 3.2)
{
upDownSpeed = -upDownSpeed;
}else if(transform.position.y < 2.8)
{
upDownSpeed = -upDownSpeed;
}
}
}
2. UI面板框架搭建
主要是面板的显示与隐藏,还有多个按钮的点击事件,执行不同的方法。
BasePanel类
SettingPanel类
点击保存,将当前的设置保存到本地
滑动音量时,改变它的大小
BeginPanel类
RankSlot类
卡槽,排行榜的一条显示UI信息。可以修改这条信息的排行、名字、分数、通关时间。
RankPanel类
控制排行榜面板的一些UI信息。
控制关闭按钮
控制实时排行显示:读取数据类拿到信息,实例化排行卡槽
GamePanel类
点击设置
设置血条
QuitPanel类
关闭该面板
继续游戏按钮
确定退出按钮
计时器
3. 数据框架搭建
PlayerPrefsDataMgr类
这是一个工具类,用于将数据对象类保存在本地。提供两个方法。
注意;这个类我们只将属性字段保存到本地。
public object Load(Type type, string keyName)
通过名字从本地加载数据到object里面,如果使用的话,可以进行强转即可
type就是你要保存的数据类的类型,可以通过 typeof(类名)
public void Save(object obj, string keyName)
将传过来的对象保存到数据中
using System;
using System.Collections;
using System.Reflection;
using UnityEngine;
namespace DY.Tools
{
/// <summary>
/// 数据持久化管理类,对数据进行保存和加载
/// 定义key的规则:keyName_类名_属性类型_属性名
/// 只适用于:int、float、bool、string、List、Direction、自定义类型
/// </summary>
public class PlayerPrefsDataMgr
{
private static PlayerPrefsDataMgr instace = new PlayerPrefsDataMgr();
public static PlayerPrefsDataMgr Instance {
get {
return instace;
}
}
private PlayerPrefsDataMgr() { }
/// <summary>
/// 对传入的数据进行保存
/// </summary>
/// <param name="obj">传入的对象</param>
/// <param name="keyName">唯一的标识</param>
public void Save(object obj, string keyName)
{
// 获得传入对象的属性
if (obj == null)
{
throw new ArgumentNullException("传入的obj参数为空");
}
Type type = obj.GetType();
// 1. 获得类中所有的公共成员属性
// 2. 定义key的规则:keyName_类名_属性类型_属性名
string savekeyName = "";
PropertyInfo[] info = type.GetProperties();
for (int i = 0; i < info.Length; i++)
{
PropertyInfo member = info[i];
savekeyName = keyName + "_" + type.Name + "_" + member.PropertyType.Name + "_" + member.Name;
SaveValue(member.GetValue(obj), savekeyName);
}
}
private void SaveValue(object value, string savekeyName)
{
Type type = value.GetType();
if(type == typeof(int))
{
PlayerPrefs.SetInt(savekeyName, (int)value);
} else if(type == typeof(float))
{
PlayerPrefs.SetFloat(savekeyName, (float)value);
}else if(type == typeof(string))
{
PlayerPrefs.SetString(savekeyName, (string)value);
}else if(type == typeof(bool))
{
// 自定义bool类型的存储规则
PlayerPrefs.SetInt(savekeyName, (bool)value ? 1 : 0);
}else if (typeof(IList).IsAssignableFrom(type)) // 存储泛型
{
IList lists = value as IList;
PlayerPrefs.SetInt(savekeyName, lists.Count);
for(int i = 0; i < lists.Count; i++)
{
SaveValue(lists[i], savekeyName + i);
}
}else if (typeof(IDictionary).IsAssignableFrom(type)) // 存储字典
{
IDictionary dictionary = value as IDictionary;
PlayerPrefs.SetInt(savekeyName, dictionary.Count);
int index = 0;
foreach (var key in dictionary.Keys)
{
SaveValue(key, savekeyName + "_key_" + index);
SaveValue(dictionary[key], savekeyName + "_value_" + index);
++index;
}
}else // 不是基本数据类型,而是自定义类型
{
Save(value, savekeyName);
}
}
/// <summary>
/// 通过唯一标识,加载type对应的类型
/// </summary>
/// <param name="type">对象类型</param>
/// <param name="keyName">唯一表示</param>
/// <returns></returns>
public object Load(Type type, string keyName)
{
// 创建实例
object obj = Activator.CreateInstance(type);
// 通过反射获得属性
PropertyInfo[] propertyInfos = type.GetProperties();
string loadkeyname = "";
for(int i = 0;i<propertyInfos.Length; i++)
{
PropertyInfo memberProperty = propertyInfos[i];
// key的规则:keyName_类名_属性类型_属性名
loadkeyname = keyName + "_" + type.Name + "_" + memberProperty.PropertyType.Name + "_" + memberProperty.Name;
memberProperty.SetValue(obj, LoadValue(memberProperty.PropertyType, loadkeyname));
}
return obj;
}
private object LoadValue(Type type, string loadkeyname)
{
object value = null;
if(type == typeof(int))
{
value = PlayerPrefs.GetInt(loadkeyname);
return value;
}else if(type == typeof(float))
{
value = PlayerPrefs.GetFloat(loadkeyname);
return value;
}else if(type == typeof(string))
{
value = PlayerPrefs.GetString(loadkeyname);
}else if(type == typeof(bool))
{
value = PlayerPrefs.GetInt(loadkeyname) == 1;
}else if(typeof(IList).IsAssignableFrom(type))
{
IList lists = Activator.CreateInstance(type) as IList;
int listLen = PlayerPrefs.GetInt(loadkeyname);
for(int i = 0; i < listLen; i++)
{
lists.Add(LoadValue(type.GenericTypeArguments[0], loadkeyname + i));
}
return lists;
}else if (typeof(IDictionary).IsAssignableFrom(type))
{
IDictionary dictionary = Activator.CreateInstance(type) as IDictionary;
int dicLen = PlayerPrefs.GetInt(loadkeyname);
for(int i = 0; i < dicLen; i++)
{
dictionary.Add(LoadValue(type.GenericTypeArguments[0], loadkeyname + "_key_" + i),
LoadValue(type.GenericTypeArguments[1], loadkeyname + "_value_" + i));
}
return dictionary;
}
else
{
value = Load(type, loadkeyname);
}
return value;
}
}
}
GameDataManager类
用于管理各种数据的
项目一但启动,就会从本地加载数据
如果某个数据改变了,就会调用这个类里面的方法,将数据保存到本地,所以说这个类也是单例的。
MusicData类
与声音有关的数据,必须保证里面的数据必须是属性字段。
RankInfo类和RankListData类
RankInfo类:一条排行榜信息
RankListData类:存储所有的排行信息
4. 音频框架搭建
BackGroundMusic类
控制背景音乐的声音
一开始时,从本地读取音量,从而设置背景音乐
5. 游戏场景搭建
没有什么技术难点。就是耗时间,自己去搭建。
6. 坦克行为
TankBase类
玩家和敌人坦克的一些公共属性,如攻击力、防御力、血量、最大血量等。
玩家和敌人坦克的一些公共行为,如受伤,死亡 等。
PlayerTank类
ws 前进
ad 旋转
鼠标控制炮台方向
开火
7. 地图
创建另外一个摄像机。俯视看着坦克。
跟随坦克
评论区