基于PF规则的CRPG制作尝试(十)动态先攻检定
在之前的先攻检定中,我直接默认场景中只有两个角色进入了战斗,因此使用了枚举状态enum,但实际的战斗中并不一定是这样的。在我看来,实际战斗的游戏回转应是这样的:
1.查找目前场景中进入战斗的全部角色并存入动态数组中。
2.根据角色的名字查找gameobject,根据gameobject的tag,来getcomponent它的ActorController类或MonsterController中的先攻检定函数并执行。将先攻检定值保存到另一个动态数组中。(其实用二维动态数组更好,但我太菜了)
3.将先攻检定进行排序,并根据排序的变动改变角色名数组的顺序。
4.游戏回转的实现。
以下是具体实现
一、查找目前场景中进入战斗的全部角色并存入动态数组
这一步并不复杂,使用FindObjectsOfTypeAll方法,查找当前场景中active,且tag为“player”或“monster”的gameobject,最后将以上物体保存到名为character的数组中。
具体代码如下:
public int actornum = 0;
ArrayList character = new ArrayList();
void Start()
{
var all = Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[];
foreach (var item in all)
{
if (item.scene.isLoaded && (item.tag == "player" || item.tag == "monster") && item.activeInHierarchy == true)
{
actornum++;
character.Add(item.name);
}
}
}
二、获取并执行以上gameobject的先攻检定函数并存入数组
没什么可说的,直接上代码:
ArrayList namelist = new ArrayList();
ArrayList inilist = new ArrayList();
public void Inicheck()
{
for (int i = 0; i < actornum ; i++)
{
GameObject a = GameObject.Find(character[i].ToString());
if (a.tag == "player")
{
namelist.Add(a.name);
inilist.Add(a.GetComponent<ActorController>().Iniroll());
}
else if (a.tag == "monster")
{
namelist.Add(a.name);
inilist.Add(a.GetComponent<MonsterController>().Iniroll());
}
}
}
三、将先攻检定进行排序,并根据排序的变动改变角色名数组的顺序
使用了冒泡排序,当所有先攻检定的值都不相等的时候就能很简单的进行排序,但当两个角色的先攻检定相同时,就需要比较其先攻修正,如果先攻修正再相同的话就需要投100面骰比较结果(投骰子的具体方法请看第七节),将角色名数组的顺序根据先攻值数组的变动同时地进行变动。
void Start()
{
Inicheck();
}
public void Inicheck()
{
//获取并保存角色名数组,roll先攻并保存进先攻值数组
for (int i = 0; i < actornum ; i++)
{
GameObject a = GameObject.Find(character[i].ToString());
if (a.tag == "player")
{
namelist.Add(a.name);
inilist.Add(a.GetComponent<ActorController>().Iniroll());
}
else if (a.tag == "monster")
{
namelist.Add(a.name);
inilist.Add(a.GetComponent<MonsterController>().Iniroll());
}
}
//冒泡排序,角色名数组根据先攻值数组顺序的调整而调整顺序
for (int i = 0; i < actornum - 1; i++)
{
for (int j = 0; j < actornum - 1 - i; j++)
{
if ((int)inilist[j] < (int)inilist[j + 1])
{
object m = inilist[j];
object n = namelist[j];
inilist[j] = inilist[j + 1];
namelist[j] = namelist[j + 1];
inilist[j + 1] = m;
namelist[j + 1] = n;
print("按大小进行了一次排序");
}
//如果先攻值相同,比较先攻修正
else if ((int)inilist[j] == (int)inilist[j + 1])
{
int inicom1 = 0, inicom2 = 0;
GameObject a = GameObject.Find(namelist[i].ToString());
GameObject b = GameObject.Find(namelist[i + 1].ToString());
if (a.tag == "player")
{
inicom1 = a.GetComponent<ActorData>().INI;
}
else if (a.tag == "monster")
{
inicom1 = a.GetComponent<MonsterData>().INI;
}
if (b.tag == "player")
{
inicom2 = b.GetComponent<ActorData>().INI;
}
else if (b.tag == "monster")
{
inicom2 = b.GetComponent<MonsterData>().INI;
}
if (inicom1 < inicom2)
{
object m = inilist[j];
object n = namelist[j];
inilist[j] = inilist[j + 1];
namelist[j] = namelist[j + 1];
inilist[j + 1] = m;
namelist[j + 1] = n;
print("先攻相同,比较先攻修正,改变了顺序");
}
//如果先攻修正也相同,那就rd100比较结果
else if (inicom1 == inicom2)
{
if (Inicheckloop() == false)
{
object m = inilist[j];
object n = namelist[j];
inilist[j] = inilist[j + 1];
namelist[j] = namelist[j + 1];
inilist[j + 1] = m;
namelist[j + 1] = n;
print("先攻修正相同,进行roll点,改变了顺序");
}
else
print("先攻修正相同,进行roll点,未改变顺序");
}
else
print("先攻相同,比较先攻修正,未改变顺序");
}
}
}
PrintArray(namelist);
PrintArray(inilist);
}
//返回true,意味着不需要改变顺序,返回false,意味着需要改变顺序
public bool Inicheckloop()
{
int check1 = Dice100();
int check2 = Dice100();
if (check1 < check2)
{
return false;
}
else if (check1 == check2)
{
//如果还想等,就再来一遍
return Inicheckloop();
}
else
return true;
}
//打印数组
void PrintArray(ArrayList A)
{
string S = "[";
for (int i = 0; i < A.Count; i++)
{
S += A[i].ToString();
if (i != A.Count - 1)
{
S += ',';
}
}
S += "]";
print(S);
}
四、实现游戏回转
之前我使用了状态枚举enum来实现游戏回转,但enum多用于表达稳定的分类标准。几乎没有任何改变的可能或者趋势。因此当我想要动态设置状态来实现游戏回转时,我发现使用enum是不恰当的。因此我最后使用最笨的方法,public了一个string类型的gamestate来表示游戏状态。同时public了一个int类型的gsNo来表达游戏状态的序号。
public string gamestate ;
public int gsNo = 0;
void Start()
{
//开始的时候gamestate为ORD,此时gsNo为0
gamestate = "ORD";
}
void Update()
{
//print(actornum);
//点击Q切换状态,gamestate变为下一个角色名
if (Input.GetKeyDown(KeyCode.Q))
{
if (gsNo < actornum)
{
gsNo++;
gamestate = namelist[gsNo - 1].ToString();
}
//到最后一个角色时再按Q,回到第一个角色的状态
else
{
gsNo = 1;
gamestate = namelist[gsNo - 1].ToString();
}
}
//按P回到ORD状态
if (Input.GetKeyDown(KeyCode.P))
{
gsNo = 0;
gamestate = "ORD";
}
}
然后在ActorController或MonsterController中用gm.gamestate == gameObject.name或gm.gamestate==“ORD”来表示游戏状态相关的逻辑判定。
以上