我用Unity制作的第一款游戏Demo
Immortal(不朽)这是我使用 Unity 制作的第一款游戏Demo,一款2D的RPG游戏。
游戏中所有工作均为本人独立完成。
美术方面
哎,早知道该好好学学画画的,对队来说制作这个Demo最耗时、最难的工作就是画画了,画个老半天还是惨不忍睹。
为了不至于不堪入目,果断选择了2D像素风格,游戏中所有的Sprite和Image都是使用Aseprite制作的,比起PS,Aseprite绘制像素画太方便了,爱了爱了。
不知不觉都肝了150多个小时了。。。
角色移动动画
爆炸动画
每个像素都是泪呀T T
技术方面
比较难的点就是对象池的制作,为了保证可扩展性,对象池是用字典存储的,字典通过结构体数组的方式序列化(能在Inspector里直接添加对象简直舒服)。下面是对象池实现的C#代码:
/// <summary> /// 对象池 /// </summary> public class ObjectPool : MonoBehaviour { //单例模式 public static ObjectPool instance; //对象类别 public enum ObjectType { Shadow, FireBall, FireExplosion, Wind } #region 字典的序列化 [System.Serializable] //可序列化的结构体数组(为了序列化字典) public struct ObjectDetail { public ObjectType type; //类别 public GameObject prefab; //预制体 public int count; //数量 } [Header("对象池中的内容")] public ObjectDetail[] objectDetails; #endregion //缓存字典<对象类别, 对象队列> public Dictionary<ObjectType, Queue<GameObject>> cache = new Dictionary<ObjectType, Queue<GameObject>>(); private void Awake() { //单例模式 instance = this; //初始化对象池 Initialization(); } /// <summary> /// 初始化对象池并填满 /// </summary> private void Initialization() { foreach (var item in objectDetails) { cache.Add(item.type, new Queue<GameObject>()); for (int i = 0; i < item.count; i++) { var newObject = Instantiate(item.prefab); newObject.transform.SetParent(transform); newObject.SetActive(false); cache[item.type].Enqueue(newObject); } } } /// <summary> /// 填满对象池 /// </summary> /// <param name="objectType">对象类别</param> public void FillPoll(ObjectType type) { foreach (var item in objectDetails) { if (item.type == type) { for (int i = 0; i < item.count; i++) { var newObject = Instantiate(item.prefab); newObject.transform.SetParent(transform); newObject.SetActive(false); cache[type].Enqueue(newObject); } return; } } } /// <summary> /// 返还给对象池 /// </summary> /// <param name="type">对象类别</param> /// <param name="gameObject">对象</param> public void ReturnPool(ObjectType type, GameObject gameObject) { gameObject.SetActive(false); cache[type].Enqueue(gameObject); } /// <summary> /// 取出一个对象 /// </summary> /// <param name="type">对象类别</param> /// <returns>取出的对象</returns> public GameObject GetFromPool(ObjectType type) { if (cache[type].Count == 0) { FillPoll(type); } //出队 var outObject = cache[type].Dequeue(); //启用 outObject.SetActive(true); return outObject; } }
技能系统的设计也比较难,为了保证可扩展性,代码改了又改,下面是技能类的实现和火球术的实现。
技能类的实现:
/// <summary> /// 技能类 /// </summary> public class Skill { protected PlayerSkillController playerSkillController; //玩家技能控制器 public Image CDImage; //CD的UI组件 //冷却时间 protected float coolDown; //冷却时间计时器 protected float cdTimer; //技能在技能栏中的位置 private int index; //是否可用 public bool Available { get; set; } /// <summary> /// 构造函数 /// </summary> /// <param name="coolDown">冷却时间</param> /// <param name="index">技能在技能栏中的位置</param> protected Skill(float coolDown, int index, PlayerSkillController playerSkillController) { this.coolDown = coolDown; cdTimer = coolDown; Available = true; this.index = index; this.playerSkillController = playerSkillController; } /// <summary> /// 计算冷却时间 /// </summary> protected void UpdateCD() { if (cdTimer < coolDown) { cdTimer += Time.deltaTime; } else { cdTimer = coolDown; } CDImage.fillAmount = (coolDown - cdTimer) / coolDown; } /// <summary> /// 使用技能 /// </summary> /// <returns>使用成功返回true; 失败返回false</returns> protected bool Use() { if (cdTimer == coolDown && Available) { cdTimer = 0; return true; } return false; } }
火球术的实现:
/// <summary> /// 火球术 /// </summary> public class FireBall : Skill, ISkill { /// <summary> /// 构造函数 /// </summary> /// <param name="coolDown">冷却时间</param> /// <param name="index">技能在技能栏中的位置</param> /// <param name="playerSkillController">玩家技能控制器</param> public FireBall(float coolDown, int index, PlayerSkillController playerSkillController) : base(coolDown, index, playerSkillController) { CDImage = GameObject.FindWithTag("FireBallCD").GetComponent<Image>(); } public void Update() { UpdateCD(); } public new bool Use() { if (base.Use()) { cdTimer = 0; GameObject fireBall = ObjectPool.instance.GetFromPool(ObjectPool.ObjectType.FireBall); fireBall.GetComponent<FireBallController>().SetProperty( playerSkillController.fireBallActiveTime, playerSkillController.fireBallDamage, playerSkillController.fireBallSpeed, playerSkillController.skillDirection, playerSkillController.transform.position ); return true; } return false; } }
游戏内容
游戏目前实现了人物的移动和三种不同类型的技能,怪物的移动和两种不同类型的技能,人物与怪物的受伤提示(颜色变化)和死亡效果,告示牌的互动对话UI系统,游戏的菜单UI系统,游戏的暂停、重开和退出功能,小地图功能等。
技能介绍:
火球术:通过对象池实现。使用了拖尾效果和粒子系统,包括飞行时间限制、碰撞检测、击中碰撞器发生爆炸的效果。
疾步:通过对象池实现人物残影效果,移速增加Buff。
掌心雷:通过Trigger实现检测怪物与三段伤害,通过RaycastHit2D实现遮挡识别。
怪物技能:
旋风:通过对象池实现,通过旋转矩阵实现8个方向同时发射。
风阵:通过Trigger实现检测玩家与持续伤害。
怪物实现:
通过仇恨距离与RaycastHit2D实现怪物仇恨系统与追随玩家功能。
通过随机方式选择怪物技能。
部分C#脚本:
图片来源:http://www.hp91.cn/ h5游戏