今天考完了大学最后一门考试,是瞬间感觉轻松了一点,花了一天多的时间预习一本书,马上就去考试了,就结果而言还是不错的。但是不知道是一种解脱,还是马上要戴上的一种新的枷锁。总归还是不错的。好了,闲话少扯,继续谈谈如何制作一款ARPG游戏,sunset在上两篇博客中已经介绍过了几种常见的ARPG游戏的人物控制方式,都比较简单,易于理解。接下来来看看制作ARPG游戏还需要什么,先从玩家可操作的角色出发,我们还需要人物的血量,或者用于释放魔法的魔量,这样就转入一种新的概念——人物属性。下面开始sunset个人编写的可视化人物属性编辑器:
人物属性分析
我们不能还没有经过分析或者思考就去动手写代码,这样只会一味给自己增加难度,延后代码编写完成的时间,这也是软件工程的基本理论。在首先编写代码之前,先来分析一下:我们需要什么?一个属性编辑器;这个编辑器中包含哪些属性?只要玩过一定数量的游戏,就会明白游戏人物一般都会有移动速度,攻击速度,攻击力,防御力等等属性值。我举例一款对属性比较看重的游戏——《Dota2》。虽然这款游戏是一款Moba游戏,但是丝毫不妨碍我们对属性经行分析,《Dota2》里英雄的属性包括:力量、敏捷、智力、攻击力、护甲、移动速度、转身速率、攻击速度、攻击距离等等等等。通过一款优秀的游戏可以得出我们所需要的解决的问题的答案,我们是否也需要敏捷、智力等等属性呢?一切都由你来决定,因为这是你的游戏。
sunset在个人制作的ARPG游戏项目中采用了这样一些属性:等级(LV)、血量(HP)、魔法值(MP)、攻击力(Attack)、防御力(Defend)、强壮(Strength)、敏捷(Agility)、智力(Intelligence)、体力(Power)、移动速度(MoveSpeed)、转身速度(RotationSpeed)、攻击距离(AttackRange)、暴击伤害百分比(CriticalDamage)、暴击概率(CriticalRate)等。这些属性值基本上满足了一款ARPG游戏的属性要求。接下来sunset给出的属性编辑器也基本上是基于这些属性进行编写的。
编辑器编写思考
经过属性中基本的属性量的定义后,我们还要进一步思考脚本该怎么编写才能使其更加易用与将来可能出现的武器属性加成或者被动技能属性加成等问题。所以将属性又分别分成几种类型:1)基础属性(BaseAttribute);2)额外(附加)属性(AdditiveAtribute);3)当前属性(CurrentAttribute);4)升级属性(GrowthAttribute);5)总属性(SumAttribute)等。这部分必须进行仔细思考,当写到一半才发觉还需要定义新的属性类型才能完成编写而不得不回头的时候,你会感觉非常无奈而致使完成时间向后拖延,所以经过仔细思考后再动手会事半功倍(个人经验)。
编写第一步——定义属性类
C#是面向对象的编程语言,所以我们直接定义“属性”类,并定义类属性,针对每个类的实例对象编写实现方法。代码如下:
[System.Serializable]
public class BaseAttribute
{
//等级
public int LV;
/// <summary>
///血量,魔量
/// </summary>
public float HP, MP;
/// <summary>
///攻击力, 防御力, 力量, 智力, 敏捷, 体力
/// </summary>
public float Attack, Defend, Strong, Intelligence, Agility, Power;
/// <summary>
/// 攻击速度,散步速度,跑步速度,后退速度,转身移动速度,转身速度,攻击范围,经验值,暴击概率,暴击伤害百分比;
/// </summary>
public float AttackSpeed, MoveSpeed, RotationSpeed, AttackRange, Exp, CriticalRate, CriticalDamage;
/// <summary>
/// 每秒血量回复,每秒魔量回复
/// </summary>
public float HPRecoverPerSecond, MPRecoverPerSecond;
}
[System.Serializable]
public class AdditionAttribute
{
/// <summary>
///血量,魔量
/// </summary>
public float HP, MP;
/// <summary>
///攻击力, 防御力, 力量, 智力, 敏捷, 体力
/// </summary>
public float Attack, Defend, Strong, Intelligence, Agility, Power;
/// <summary>
/// 攻击速度,散步速度,跑步速度,后退速度,转身移动速度,转身速度,攻击范围,暴击概率,暴击伤害百分比;//暴击概率和攻击范围仅由装备影响。
/// </summary>
public float AttackSpeed, MoveSpeed, RotationSpeed, AttackRange, CriticalRate,CriticalDamage;
/// <summary>
/// 每秒血量回复,每秒魔量回复
/// </summary>
public float HPRecoverPerSecond, MPRecoverPerSecond;
}
[System.Serializable]
public class CurAttribute
{
/// <summary>
///血量,魔量
/// </summary>
public float CurHP, CurMP;
/// <summary>
///攻击力, 防御力, 力量, 智力, 敏捷, 体力
/// </summary>
public float CurAttack, CurDefend, CurStrong, CurIntelligence, CurAgility, CurPower;
/// <summary>
/// 当前攻击速度,当前散步速度,当前跑步速度,当前后退速度,当前转身移动速度,当前转身速度,当前攻击范围,当前暴击概率, 当前暴击伤害百分比;
/// </summary>
public float CurAttackSpeed, CurMoveSpeed, CurRotationSpeed, CurAttackRange, CurCriticalRate, CurCriticalDamage;
/// <summary>
/// 每秒血量回复,每秒魔量回复
/// </summary>
public float HPRecoverPerSecond, MPRecoverPerSecond;
}
[System.Serializable]
public class SumAttribute
{
/// <summary>
///血量,魔量
/// </summary>
public float HP, MP;
/// <summary>
///攻击力, 防御力, 力量, 智力, 敏捷, 体力
/// </summary>
public float Attack, Defend, Strong, Intelligence, Agility, Power;
/// <summary>
/// 攻击速度,移动速度,转身速度,攻击范围,暴击概率,暴击伤害百分比;
/// </summary>
public float AttackSpeed, MoveSpeed, RotationSpeed, AttackRange, CriticalRate, CriticalDamage;
/// <summary>
/// 每秒血量回复,每秒魔量回复
/// </summary>
public float HPRecoverPerSecond, MPRecoverPerSecond;
}
[System.Serializable]
public class AttributeGrowth
{
/// <summary>
///血量,魔量
/// </summary>
public float HP, MP;
/// <summary>
///攻击力, 防御力, 力量, 智力, 敏捷, 体力
/// </summary>
public float Attack, Defend, Strong, Intelligence, Agility, Power;
}
注释的相当仔细,一看就懂。
然后我们还需要定义一些单独存在的量:比如最高等级,最大经验值、当前等级所需经验,如果有各种动画状态,还需要单独定义步行速度(WalkSpeed)、跑步速度(RunSpeed)、左右转身时向左或向右移动的速度(TurnSpeed),或者还可以定义后退时的移动速度(BackwardSpeed),看个人需求。然后定义出上文代码中定义的类对象的实例对象,编写过程中主要是使用类的实例对象。代码:
/// <summary>
/// 最高等级
/// </summary>
public int MaxLV;
/// <summary>
/// 当前等级所需要的经验总量
/// </summary>
public float NeedExpPerLV;
//当前等级到下一个等级还需要的经验量
public float EXP2NextLV;
//到当前为止所获得的所有经验量
public float MaxExp;
//各类的实例对象:
public BaseAttribute BaseStatus;
public AdditionAttribute AddStatus;
public CurAttribute CurStatus;
public SumAttribute SumStatus;
public AttributeGrowth attributeGrowth, growthPoint;
//定义各种速度:
public float RunSpeed;
public float WalkSpeed;
public float TurnSpeed;
public float BackSpeed;
嗯,基本需要用到的量都已经定义好了,下一步开始编写方法使用这些量。
编写第二步——实施方法
我们首先来编写人物经验的计算方法,这里sunset个人所用的经验计算公式是:基数A * 当前等级 * 当前等级 + 基数B * 当前等级。这算是一种较为简单的计算方法了,一个一元二次方程。这个可以自行决定。先计算到当前为止所获得的所有经验量(包括当前等级到下一级),然后计算当前等级所需经验:(这里所采用的基数A和B分别为40和60)
void CalculateExp()
{
//更新到当前等级为止的所有经验,包括本级到下一级
MaxExp = 40.0f * BaseStatus.LV * BaseStatus.LV + 60.0f * BaseStatus.LV;
//更新本级到下一级所需要的经验值;
NeedExpPerLV = MaxExp - (40.0f * (BaseStatus.LV - 1) * (BaseStatus.LV - 1) + 60.0f * (BaseStatus.LV - 1));
}
然后更新当前经验值:
public void UpdateExp()//更新经验值
{
if (BaseStatus.LV >= MaxLV)
{
BaseStatus.Exp = NeedExpPerLV;
BaseStatus.LV = MaxLV;
}
else
{
if(BaseStatus.Exp >= NeedExpPerLV)
{
GetLvUp =