Unity管理VN风格游戏中的角色精灵/图像



让我先解释一下我要做的场景。我试图创造一个VN游戏,其中的人物改变他们的形象取决于一天的时间。例如,在白天8点到11点之间,npc角色Benjamin会站在场景中的池塘边,11点之后,他会坐在场景中的篝火旁。这意味着每个npc角色都有许多不同的精灵/图像,但只有一个应该根据一天中的时间被激活。

当涉及到编码和构建我的脚本如何工作时,我想遵循最佳实践。所以我不想要一些有用但做得很乱的东西,我觉得它可以改进。我是这样做的:

public class Benjamin : MonoBehaviour
{
public GameObject BenjaminStanding;
public GameObject BenjaminSitting;
void Update()
{
//If Time logic Between 8:00AM - 11:00AM
ActivateBenjaminStanding();
//if Time logic is After 11:00AM
ActivateBenjamindSitting();
}
//Activate Benjamin standing image
public void ActivateBenjaminStanding()
{      
BenjaminSitting.SetActive(false);
BenjaminStanding.SetActive(true);
}
//Activate Benjamin sitting image
public void ActivateBenjamindSitting()
{
BenjaminStanding.SetActive(false);
BenjaminSitting.SetActive(true);
}
}

在我的层次结构中,我有一个空的游戏对象Benjamin,然后是父对象下的所有图像,像这样:

便雅悯

  • BenjaminStanding
  • BenjaminSitting

我将脚本附加到我的Benjamin对象上,并执行所有必要的图像引用。

现在上面的代码工作,但我觉得这是非常混乱的方式做事情,因为如果我有更多的字符,我必须为每个字符单独的脚本,有些可能有很少的图像,有些可能有很多。我必须在激活每个图像时为它们创建一个方法。那么有没有更好的办法呢?

我在找更快、更干净、更有效的东西。我将非常感谢任何帮助或建议。谢谢!

你可以为你的字符创建一个基类。使它成为抽象类,并添加所有字符应该具有的变量和方法。

public abstract class Character : MonoBehaviour
{
public GameObject characterStanding;
public GameObject characterSitting;
internal virtual void Update()
{
//If Time logic Between 8:00AM - 11:00AM
ActivateCharacterStanding();
//if Time logic is After 11:00AM
ActivateCharacterSitting();
}
//Activate Benjamin standing image
public void ActivateCharacterStanding()
{      
characterSitting.SetActive(false);
characterStanding.SetActive(true);
}
//Activate Benjamin sitting image
public void ActivateSitting()
{
characterStanding.SetActive(false);
characterSitting.SetActive(true);
}
}

然后你可以创建子类并继承字符类

public class Benjamin : Character
{
}
public class Marting: Character
{

}
public class John: Character
{
// You can change main class function and override it
override Update(){
// If you remove this doesn't apply base class function.
base.ActivateCharacter();

}}

但是如果每个字符都有相似的属性,并且您创建了许多这样的属性,那么这种方法根本没有用。你可以使用Scriptable Object,你可以为每个角色创建资产,并将Scriptable Object分配给场景对象或预制件,选择哪种方式对你的设置有益。

如果您有多个图像,通常的做法是为每个添加一个检查器变量,该变量为数组

public ImageOrSomething[] avatars;

请注意,然后在检查器中,您可以随心所欲地放入许多图像,而无需更改代码。

注意我说的"ImageOrSomething"那可以是任何东西……一个Texture,一个Image,一个完整的动画角色,一些精灵表……无论你的情况如何。

进一步…

你可以在你的资源文件夹中组织图片,然后按名称加载它们.

这样,当你的设计部门制作或更改图像,或添加不同的时间,你不需要更改代码。

这里有一个随机的例子,将纹理加载到一张卡片上(想象一下扑克牌),

private int _Cardnumber = 1;
public int Cardnumber
{
get { return _Cardnumber; }
set
{
.. obviously check for valid numbers, etc
string f = "bonuscards/bonus_" + Cardnumber.ToString();
Texture t = Resources.Load(f, typeof(Texture)) as Texture;
ri.texture = t;
}
}

在示例中,图像将由您的美术部门命名"bonus_3.png"bonus_4.png"等等。

您还可以自动确定文件夹中有哪些项目,并随机选择一个(或其他情况)。

关于你的"一天中的时间"的例子…

更聪明的方法是在图像名称中添加实际时间

比如

cat_03.png
cat_09.png
cat_13.png

将意味着您分别在0300,0900和1300更改这些图像。

假设你想为睡觉的猫添加一个新的,并且你希望它发生在晚上10点。你所要做的就是添加新的图像,

cat_22.png

只要把它放到你的资源文件夹里,它就会自动从那里开始。

你可以通过将你的GameObjects组织成一个数据结构并使用一个函数在图像之间切换来减少你的劳动。

通过这样做,您可以将Benjamin类泛化为任何给定字符的更通用的类,从而使组件具有可重用性。

这个例子使用Dictionary来组织每个GameObject的名称,并假设每个图像共享相同的名称作为GameObject,这样游戏对象就可以通过名字来引用。这样,我们就不用为每张图片都写变量和方法了,我们可以调用单个函数(例如:Activate("BenjaminStanding"))。

public class ClassNameHere : MonoBehaviour
{
public GameObject[] images;
private Dictionary<string, GameObject> imageDict;
private GameObject currentImage;
void Awake()
{
imageDict = new Dictionary<string, GameObject>();
foreach (GameObject image in images)
{
imageDict.Add(image.name, image);
}
}
void Activate(string name)
{
if (currentImage) currentImage.SetActive(false);
var image = imageDict[name];
image.SetActive(true);
currentImage = image;
}
void Update()
{
//If Time logic Between 8:00AM - 11:00AM
Activate("BenjaminStanding");
//if Time logic is After 11:00AM
Activate("BenjaminSitting");
}
}

最新更新