首页 > 其他分享 >【Unity项目实践】GameJam活动总结——新手做一个完整游戏项目的时候会有什么问题

【Unity项目实践】GameJam活动总结——新手做一个完整游戏项目的时候会有什么问题

时间:2022-10-21 18:05:05浏览次数:73  
标签:GameJam ScriptableObject void cat Unity Animal 新手 using public

前几天参加了Unity的GameJam,作为第一次参加比赛的萌新,不指望能做出什么惊天动地的内容,但是希望能够从中有所收获。

现在复盘一下我在游戏项目中用到的一些技巧和Unity知识点,以后再接再励呀。

作品的地址在此:​​https://www.bilibili.com/video/BV1184y1q7YY/?vd_source=e99f21b5eb43aa3bce10e93c333f70d7​

【Unity项目实践】GameJam活动总结——新手做一个完整游戏项目的时候会有什么问题_ide

一个完整项目的构成要素和一些难点:

  • UI系统:包括UI交互框架、场景转换等,主要是用到UGUI、SceneManagement,还可以用DOTween进行辅助来做一些额外的效果。
  • 声音系统:需要弄清楚AudioSource和AudioClip之间的区别,本次项目中使用了一个贯穿始终的AudioSource来播放背景音乐。
  • 主体游戏逻辑:就是下面说到的一笔画逻辑了。
  • 数据体系:数据读取采用ScriptableObject,数据保存采用了PlayerPrefs。

泛型单例

本次项目中的泛型单例类代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
private static T instance;

public static T Instance
{
get { return instance; }
}

protected virtual void Awake()
{
if (instance != null)
Destroy(gameObject);
else
instance = (T)this;
}

protected virtual void OnDestroy()
{
if (instance == this)
{
instance = null;
}
}

public static bool IsInitialized
{
get { return instance != null; }
}
}

使用中的时候只需要继承这个单例就好,如果是跨场景的物体,可以在Awake中加上以下代码,用在需要全局存在的GameController、非常简单好用。

 protected override void Awake()
{
base.Awake();
DontDestroyOnLoad(this.gameObject);
}


观察者模式

本次游戏中会涉及到四个关卡,四个关卡会有很多共性的内容,所以采用了一个跨场景存在的GameController来管理游戏逻辑,比如,记录游戏当前关卡、已经解锁的关卡数量、加载一些共性的Prefab等。

这种情况下天然很适合用观察者模式,采用多播委托来完成一对多的监听关系。(PS:del悄悄复习一下,Action和Event都是特殊的委托,可以详细看一下这个文章:​​https://gamedevbeginner.com/events-and-delegates-in-unity/​​)如果不用观察者模式来进行监听,可能我们就只能在Update中每一帧都调用了,这种方式就原始的可怕,会导致巨大的运算量。

以“猫来了,老鼠们开始跑”为例:

  • 发布者的类中新增一个委托,并且写好触发函数
  • 订阅者的构造函数或者Start函数中通过“+=”进行订阅,并且写好事件处理器
  • 在响应的脚本中调用触发函数

以下是代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

//这里介绍观察者模式
//例子是:猫来了,所有的老鼠开始逃跑

public class Animal
{
protected string strName;

public Animal(string name)
{
this.strName = name;
}

public virtual void Run()
{

}
}

public class Cat: Animal
{
public Action action;//发布者
public Cat(string name):base(name)
{

}

public void Coming(/*Animal mouseA, Animal mouseB, Animal mouseC*/)
{
Debug.Log(strName + "来了");
//mouseA.Run();
//mouseB.Run();
//mouseC.Run();
//在没有观察者模式的时候需要挨个调用

if (action != null)
action();//触发事件;通过多播委托完成一对多的关系

this.Run();
}

public override void Run()
{
Debug.Log(strName + "开始追");
}
}

public class Mouse: Animal
{
public Mouse(string name, Cat cat):base(name)
{
cat.action += this.Run;//订阅者
}

public override void Run()//事件处理器
{
Debug.Log( strName + "开始逃跑");
}

}

public class ObserverPattern : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Cat cat = new Cat("小野猫");

Animal mouseA = new Mouse("mouseA", cat);
Animal mouseB = new Mouse("mouseB", cat);
Animal mouseC = new Mouse("mouseC", cat);
Animal mouseD = new Mouse("mouseD", cat);

//cat.Coming(mouseA, mouseB, mouseC);
cat.Coming();
}

// Update is called once per frame
void Update()
{

}
}


ScriptableObject

在不调用数据库的情况下,可以用ScriptableObject存储少量的数据。本次项目中四个关卡的设置数据就用ScriptableObject进行保存。

创建一个SO类型的脚本,主要包含两个要素:头部的标题栏和对于ScriptableObject的继承。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "GamePlay_SO", menuName = "Game Data/GamePlay_SO")]
public class GamePlay_SO : ScriptableObject
{
[Header("游戏逻辑数据")]
public List<Conections> lineConections;


[System.Serializable]
public class Conections
{
public int from;
public int to;
}


使用PlayerPref保存游戏数据

PlayerPref是Unity自带的数据存储工具

//数据存储
PlayerPrefs.SetInt("UnlockLevel", unlockLevel);
//这里除了整数还可以存储别的类型


//数据读取
if (PlayerPrefs.HasKey("UnclockLevel"))
{
Debug.Log(PlayerPrefs.GetInt("UnlockLevel"));
}

DOTween

一个简单易用的动画插件,用法如下:

//头部引用
using DG.Tweening;

//一个旋转的使用案例
Tweener t = LevelGameManager.Instance.resetGame.gameObject.transform.DORotate(new Vector3(0, 0, 270), 2.0f);


一些编辑器中容易混淆的点

图片格式问题

  • Texture2D:可以赋值给Material,可以作为游戏的Icon;
  • Sprite:通过图集Slice出来的都是这种格式,不可以转换成其他两种;这种格式不能作为Material的albedo原图;
  • Image:UI中的概念,Image有OverrideSprite的属性,但是Sprite没有。

图层遮挡关系

主要的概念有Sorting Layer、Order In Layer,两者是递进关系,Order In Layer表示在Layer里面的顺序。

一笔画的逻辑

纯纯自己摸索出来的逻辑写法,可能不是最好的,但是确实我目前能想出来的。

场景生成:需要去相应的场景摆放好,然后读取ScriptableObject中每一关的游戏数据,Instantitate一个LinePrefab自动生成连线。

通关的逻辑判断:玩家操作之后新生成的线的数量和ScriptableObject中的数据一样。


暂时就是这些了,虽然自己很菜,但是还是要日拱一卒,加油加油!


标签:GameJam,ScriptableObject,void,cat,Unity,Animal,新手,using,public
From: https://blog.51cto.com/u_15639010/5784396

相关文章