目录
最近又跟着做了一个游戏,这是学习Unity以来这算是第三个完整的实战游戏项目了。效果演示看下面的动图。
先简单介绍一下:
- 进入界面可以选择角色,丧尸会根据时间的推移出现的种类也不同,一共四种类型。
- 武器有近战和远程两个,升级还可以选择随机的道具进行升级。
- 玩家存活时间来决定游戏的输赢,存活时间倒计时可以设置。
- 不管是丧尸还是玩家的攻击,都是通过碰撞检测来判定的。
01. Unity Vampire Survivors Like Dev Course is coming!_哔哩哔哩_bilibili这是原教程链接,up主在油管上搬运过来的。
之前做的实例都是PC端的,做这个的初衷是想探索一下移动端的游戏是怎么做的(做完之后我的理解就是输入设备的不同。PC端通过键盘鼠标控制角色,移动端则通过虚拟摇杆和虚拟按键控制;还有就是打包方式的不同)。
这里先放一部分核心代码:
一、游戏管理器
GameManager游戏管理器就和它的命名一样,通过单例模式管理着游戏的各个方面,比如游戏存活的倒计时、玩家信息(血条、经验值、击杀数等)、游戏用到的预制体等。
public class GameManager : MonoBehaviour
{
public static GameManager instance;
[Header("# Game Control")]
public bool isLive;
public float gameTime;
public float maxGameTime = 2 * 10f;
[Header("# Player Info")]
public int playerId;
public float health;
public float maxHealth = 100;
public int level;
public int kill;
public int exp;
public int[] nextExp = { 10, 30, 60, 100, 150, 210, 280, 360, 450, 600 };
[Header("# Game Object")]
public PoolManager pool;
public Player player;
public LevelUp uiLevelUp;
public Result uiResult;
public Transform uiJoy;
public GameObject enemyCleaner;
}
GameManager脚本会变成齿轮的图标,作为小白我是第一次知道😪
二、对象池管理器
PoolManager,为了节省内存资源防止内存碎片化的产生,将游戏中对象放在一起统一管理(管理游戏对象的生成和销毁)。
public class PoolManager : MonoBehaviour
{
public GameObject[] prefabs;
List<GameObject>[] pools;
void Awake()
{
pools = new List<GameObject>[prefabs.Length];
for (int index = 0; index < pools.Length; index++)
{
pools[index] = new List<GameObject>();
}
}
public GameObject Get(int index)
{
GameObject select = null;
foreach (GameObject item in pools[index])
{
if (!item.activeSelf)
{
select = item;
select.SetActive(true);
break;
}
}
if (!select)
{
select = Instantiate(prefabs[index],transform);
pools[index].Add(select);
}
return select;
}
}
三、无限地图
无限地图的原理是给玩家设置一个比游戏窗口大的矩形框作为触发器,当触发器触碰到地图的边界后地图位置就会发生移动来实现无限地图的效果。
public class Reposition : MonoBehaviour
{
Collider2D coll;
void Awake()
{
coll = GetComponent<Collider2D>();
}
void OnTriggerExit2D(Collider2D collision)
{
if (!collision.CompareTag("Area"))
return;
Vector3 playerPos = GameManager.instance.player.transform.position;
Vector3 myPos = transform.position;
switch (transform.tag)
{
case "Ground":
float diffX = playerPos.x - myPos.x;
float diffY = playerPos.y - myPos.y;
float dirX = diffX < 0 ? -1 : 1;
float dirY = diffY < 0 ? -1 : 1;
diffX = Mathf.Abs(diffX);
diffY = Mathf.Abs(diffY);
if (diffX > diffY)
{
transform.Translate(Vector3.right * dirX * 40);
}
else if (diffX < diffY)
{
transform.Translate(Vector3.up * dirY * 40);
}
break;
case "Enemy":
if (coll.enabled)
{
Vector3 dist = playerPos - myPos;
Vector3 ran = new Vector3(Random.Range(-3, 3), Random.Range(-3, 3), 0);
transform.Translate(ran + dist * 2);
}
break;
}
}
}
四、升级系统
当玩家经验进度条满后会对道具进行升级属性的加成。比如说我当前的武器枪的等级为1,属性值射速为5;伤害为3,当玩家选择给枪进行升级等级为2,枪的属性值射速就变成了6;伤害为3.5。
关于道具属性值升级的数据就记录在了 ItemData 中。
[CreateAssetMenu(fileName = "Item",menuName = "Scriptable Object/ItemData")]
public class ItemData : ScriptableObject
{
public enum ItemType
{
Melee,
Range,
Glove,
Shoe,
Heal
}
[Header("# Main Info")]
public ItemType itemType;
public int itemId;
public string itemName;
[TextArea]
public string itemDesc;
public Sprite itemIcon;
[Header("# Level Data")]
public float baseDamage;
public int baseCount;
public float[] damages;
public int[] counts;
[Header("# Weapon")]
public GameObject projectile;
public Sprite hand;
}
public class Item : MonoBehaviour
{
public ItemData data;
public int level;
public Weapon weapon;
public Gear gear;
Image icon;
Text textLevel;
Text textName;
Text textDesc;
void Awake()
{
icon = GetComponentsInChildren<Image>()[1];
icon.sprite = data.itemIcon;
Text[] texts = GetComponentsInChildren<Text>();
textLevel = texts[0];
textName = texts[1];
textDesc = texts[2];
textName.text = data.itemName;
}
void OnEnable()
{
textLevel.text = "Lv." + (level + 1);
switch (data.itemType)
{
case ItemData.ItemType.Melee:
case ItemData.ItemType.Range:
textDesc.text = string.Format(data.itemDesc,data.damages[level] * 100,data.counts[level]);
break;
case ItemData.ItemType.Glove:
case ItemData.ItemType.Shoe:
textDesc.text = string.Format(data.itemDesc,data.damages[level] * 100);
break;
default:
textDesc.text = string.Format(data.itemDesc);
break;
}
}
//选择其中一个道具升级,根据ItemData进行属性加成
public void OnClick()
{
switch (data.itemType)
{
case ItemData.ItemType.Melee:
case ItemData.ItemType.Range:
if (level == 0)
{
GameObject newWeapon = new GameObject();
weapon = newWeapon.AddComponent<Weapon>();
weapon.Init(data);
}
else
{
float nextDamage = data.baseDamage;
int nextCount = 0;
nextDamage += data.baseDamage * data.damages[level];
nextCount += data.counts[level];
weapon.LevelUp(nextDamage,nextCount);
}
level++;
break;
case ItemData.ItemType.Glove:
case ItemData.ItemType.Shoe:
if (level == 0)
{
GameObject newGear = new GameObject();
gear = newGear.AddComponent<Gear>();
gear.Init(data);
}
else
{
float nextRate = data.damages[level];
gear.LevelUp(nextRate);
}
level++;
break;
case ItemData.ItemType.Heal:
GameManager.instance.health = GameManager.instance.maxHealth;
break;
}
if (level == data.damages.Length)
{
GetComponent<Button>().interactable = false;
}
}
}
五、虚拟摇杆的制作
窗口 ——》 包管理器 ——》 Input System,导入 On-Screen Controls
导入后新建 Image 把贴图资源放上去,然后把 Stick 拖到新建好的Image里(我这里改名为Joy)
然后调整好你想要放置的位置
Movement Range 数值越大,虚拟摇杆的活动范围就越大。
这样玩家就可以通过虚拟摇杆控制游戏角色了。
六、导出安卓系统apk文件
要导出apk文件这些Unity的安卓模块要安装好
打开 file ——》 Build Settings 切换到 Android
根据实际情况进行玩家设置后点击生成按钮,这样就可以导出apk文件了
七、导出WebGL
和导出apk文件流程差不多,不过我在运行的时候碰到问题了。
后边参考大佬的这篇文章解决了
Unity WebGL项目打包后本地打开报错问题解决方法_failed to download file build/安装包.data.br. loading-CSDN博客https://blog.csdn.net/qq_32803337/article/details/131240516额。。。不过目前这游戏放Web端运行好像不太合适
八、导出微信小程序
导出微信小程序参考大佬的这篇文章:Unity 之 发布WebGL转微信小游戏过程详解_unity转微信小游戏-CSDN博客https://blog.csdn.net/Czhenya/article/details/125049115
中文显示乱码我就换成英文了。。
单对于这个游戏来说是要配置CDN的,我这里把游戏资源上传到了微信云开发控制台上
另外发布微信小程序还需要提交材料并各种审核,审核通过后才会上架到微信小程序,游戏中用到的素材不是我的,我也很懒没有写审核材料就没提交(可以说离发布就剩提交材料和审核通过两步了)💦
大佬的这篇文章介绍了上架微信小程序步骤以及具体材料,想上架微信小程序的可以参考。微信小游戏个人开发者上架:从注册到上线的详细步骤_微信小游戏上架-CSDN博客https://blog.csdn.net/Czhenya/article/details/131897891
看发布过的人说审核流程要好久,现在对个人开发者上架小程序确实繁琐了很多。
转换为微信小游戏之后代码可以通过微信开发者工具直接提交。
体验了一下移动端游戏制作到发布到安卓、Web和小程序的过程,今天先到这里,祝大家五一快乐,拜拜┏(^0^)┛