GalGame相比其它类型的游戏场景简单,游戏要素不多,靠的是精美的画面和动人的剧情以及舒服的BGM。游戏根据玩家做出的不同选择产生不同的结局,而这个触发条件往往是和主角的好感度有关。
对于这样的游戏来说,Unity开发起来尤为方便。如果创建一个简易剧本读取器,就能满足一款GalGame的基本功能。
1、剧本格式
这里使用普通txt来保存剧本,为了便于解析,我们定义如下的格式:
类型 | 角色位置 | 角色名称 | 角色对话内容 | 角色图片 |
0/1 | left/right | 阿黄 | 你好 | Test.png |
类型:0:代表载入背景图片 1:代表载入人物对话内容
角色位置:就是人物出现的位置,左啊有啊,当然后期也能加入自定义位置的功能...
角色名称:对话框显示的角色名字
角色对话内容:同上
角色图片:需要载入
图片:根据类型载入的图片,例如是人物图片或者背景图片
下面是根据基本存储格式的创建的一个简单数据类。
using UnityEngine;
using System.Collections;
public class ScriptData {
public int type;
public string pos;
public string name;
public string talk;
public string picName;
public ScriptData(int type,string pos,string name,string talk,string picName)
{
this.type = type;
this.pos = pos;
this.name = name;
this.talk = talk;
this.picName = picName;
}
public ScriptData(int type, string picName)
{
this.type = type;
this.picName = picName;
}
}
2、剧本解析
有了剧本,就可以对剧本进行解析了。在项目文件夹下创建一个文件夹Scripts用来存放剧本文件。
这里脚本内容如下:
0,back.jpg
1,left,角色1名称,说了第一句话,left.jpg
1,right,角色2名称,说了第二句话,right.jpg
1,left,角色1名称,说了第三句话,left.jpg
1,right,角色2名称,说了第四句话,right.jpg
下面是读取解析剧本的一个类,并且创建了一个实例和当前读取的索引。
using UnityEngine;
using System.Collections;
using System.IO;
using System.Collections.Generic;
public class LoadScripts : MonoBehaviour {
public static LoadScripts instance;
int index;
List<string> txt;
// Use this for initialization
void Awake()
{
instance = this;
index=0;
}
void Start () {
}
public void loadScripts(string txtFileName)
{
index=0;
txt = new List<string>();
StreamReader stream = new StreamReader("Scripts/" + txtFileName);
while (!stream.EndOfStream)
{
txt.Add(stream.ReadLine());
}
stream.Close();
}
public ScriptData loadNext()
{
if (index < txt.Count)
{
string[] datas = txt[index].Split(',');
int type = int.Parse(datas[0]);
if (type == 0)
{
string picName = datas[1];
index++;
return new ScriptData(type, picName);
}
else
{
string pos = datas[1];
string name = datas[2];
string talk = datas[3];
string picName = datas[4];
index++;
return new ScriptData(type, pos, name, talk, picName);
}
}
else
{
return null;
}
}
}
3、剧本播放
编辑完剧本,就可以实现剧本播放的功能了。这里简单地实现了一个对话场景。
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.IO;
public class GameManager : MonoBehaviour {
public Text name;
public Text talk;
public Image background;
public Image left;
public Image right;
// Use this for initialization
void Start () {
LoadScripts.instance.loadScripts("first.txt");
handleData(LoadScripts.instance.loadNext());
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
handleData( LoadScripts.instance.loadNext());
}
}
public void setText(Text text, string content)
{
print(content);
text.text = content;
}
public void setImage(Image image,string picName)
{
image.sprite = loadPicture("Picture/" + picName);
}
public Sprite loadPicture(string picPath)
{
//创建文件读取流
FileStream fileStream = new FileStream(picPath, FileMode.Open, FileAccess.Read);
fileStream.Seek(0, SeekOrigin.Begin);
//创建文件长度缓冲区
byte[] bytes = new byte[fileStream.Length];
//读取文件
fileStream.Read(bytes, 0, (int)fileStream.Length);
//释放文件读取流
fileStream.Close();
fileStream.Dispose();
fileStream = null;
//创建Texture
int width = Screen.width;
int height = Screen.height;
Texture2D texture = new Texture2D(width, height);
texture.LoadImage(bytes);
//创建Sprite
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
return sprite;
}
public void handleData(ScriptData data)
{
if (data == null)
return;
if (data.type == 0)
{
setImage(background,data.picName);
print(data.picName);
handleData(LoadScripts.instance.loadNext());
}
else
{
if (data.pos.CompareTo("left") == 0)
{
left.gameObject.SetActive(true);
setImage(left, data.picName);
right.gameObject.SetActive(false);
}
else
{
right.gameObject.SetActive(true);
setImage(right, data.picName);
left.gameObject.SetActive(false);
}
setText(name, data.name);
setText(talk, data.talk);
}
}
}
