终于进入代码部分了,反正我很早就跃跃欲试了,虽然中途遇到很多问题,但还是一一解决了,废话不多说,直接步入正题。
这本教材中提到可以用C++,C#,和lua三种语言编写代码,书中还给了个示例,但是C++的链接已经无效了,所以我们只能不管它,我把C#写的工程示例下载了下来,也是有很多问题,所以今天我们先用C++来创建自定义Node。
在正式开始之前,版本问题还真得考虑一下。VS只能是2010以上的版本,在这里我使用的是VS2013。而对于CE3的版本,如果大家使用的是3.5系列的话,应该在CE3根目录下直接就有Code文件夹,若果是高一点的版本,比如3.6系列,就只能解压它的压缩包了。还需要说明的一点是,在我们进行编译之前,大家最好把32和64位下的dll备份一下,因为我们实际上就是重新定制自己的dll,如果不备份,会把原先的覆盖掉,这样一旦编译错误,就只能重新解压CE3的SDK了。
然后,找到c++的解决方案(3.5系列是这个文件:CryEngine_GameCodeOnly),打开它,右键编译一下,看看是否有错误。如果能正确生成dll文件,恭喜你,就可以直接用了,如果提示了很多错误的话,就得根据不同的原因折腾一大会儿了。我这边也是出了很多问题,最后经网上一位大神的指点,总算是解决了。
下图为成功生成dll
这里具体会遇到哪些问题我也不知道,这就看大家VS玩的怎么样了,我这边出现了中英文字符的问题,降低了一下警告的等级,不把警告视为错误,然后就好了。如果大家在这一步有问题的话,欢迎提出来,我们一起想办法解决。降低警告的方法:右键CryGameSDK,选择属性,然后就是下图了:
好吧,准备工完成后,我们就正式进入编程这一步。在这里我提前说明一下,我也是刚刚接触CE3的编码,所以里面很多封装好的函数具体的作用什么的也不是分的很清。我觉得在这种情况下,我们不用做太多的纠结,直接先跟着教程来做就是了,慢慢的接触的多了自然就会知道。
好,那我们就动手吧!C++编写自定义节点共有如下几个步骤:
(一).新建一个cpp文件。
书上说,我们的Node信息不会在工程的其他区域涉及到,所以不必添加.h文件。
在CryGameSDK下找到Node文件夹,右键建立cpp文件,取名“TotorialNode.cpp”(totorial:翻译为示例)。然后再文件中需要添加头文件、建立一个类,具体代码为如下:
#include "StdAfx.h"
#include "Nodes\G2FlowBaseNode.h"
class CTutorialNode :public CFlowBaseNode < eNCT_Instanced >
{
};
REGISTER_FLOW_NODE("Tutorial:Multiplier", CTutorialNode);
书中解释:
(1)G2FlowBaseNode虽然不是CE3严格意义上的一个组件,但是它封装了许多实用的函数。
(2)书中对类的定义是这么解释的:CTutorialNode继承自CFlowBaseNode,后面的< eNCT_Instanced >表明了这个node将会成为游戏运行过程中的一个实例。(这句话的理解、还得琢磨琢磨,想一想,我水品有限,也只能翻译到这个地步)。
(3)REGISTER_FLOW_NODE("Tutorial:Multiplier", CTutorialNode);是用来完成在开始运行时node的注册。
(二)重写父类的函数
//书中解释:我们不需要存储任何静态的变量,所以我们就简单的使用Public
public:
CTutorialNode(SActivationInfo *pActInfo)
{
}
virtual IFlowNodePtr Clone(SActivationInfo *pActInfo)
{
return new CTutorialNode(pActInfo);
}
//端口被触发时调用,我们大部分都在这个地方写逻辑
virtual void ProcessEvent(EFlowEvent evt, SActivationInfo *pActInfo)
{
}
//配置节点的显示,输入和输出
virtual void GetConfiguration(SFlowNodeConfig &config)
{
}
//这个函数并不需要我们重写任何的实现,我们在在内存为这个函数只需要添加一个声明
virtual void GetMemoryUsage(ICrySizer *s) const
{
}
//添加枚举类型
enum EInput
{
EIP_Activate,
EIP_Left,
EIP_Right
};
enum EOutput
{
EOP_Result
};
//配置节点的显示,输入和输出
virtual void GetConfiguration(SFlowNodeConfig &config)
{
static const SInputPortConfig inputs[] =
{
InputPortConfig_Void("Activate", "MyDes:Trigger the calculation"),
//端口名,默认值,描述
InputPortConfig("Left", 0, "MyDes2:The left side of the calculation"),
InputPortConfig("Right", 0, "MyDes2:The right side of the calculation"),
{ 0 }
};
static const SOutputPortConfig outputs[] =
{
OutputPortConfig("Reslut", "The Result of the calculation"),
{ 0 }
};
config.pInputPorts = inputs;
config.pOutputPorts = outputs;
config.sDescription = _HELP("Multiplies two numbers");
config.SetCategory(EFLN_APPROVED);
}
(四)实现ProcessEvent函数
//端口被触发时调用,我们大部分都在这个地方写逻辑
virtual void ProcessEvent(EFlowEvent evt, SActivationInfo *pActInfo)
{
switch (evt)
{
case IFlowNode::eFE_Activate:
{
if (IsPortActive(pActInfo, EIP_Activate))
{
float left = GetPortFloat(pActInfo, EIP_Left);
float right = GetPortFloat(pActInfo, EIP_Right);
float ans = left * right;
//把ans值更新到输出端口数组
ActivateOutput(pActInfo, EOP_Result, ans);
}
}
break;
}
}
/*
这是个添加自定义节点的代码
*/
#include "StdAfx.h"
#include "Nodes\G2FlowBaseNode.h"
class CTutorialNode :public CFlowBaseNode < eNCT_Instanced >
{
//添加枚举类型
enum EInput
{
EIP_Activate,
EIP_Left,
EIP_Right
};
enum EOutput
{
EOP_Result
};
//书中解释:我们不需要存储任何静态的变量,所以我们就简单的使用Public
public:
CTutorialNode(SActivationInfo *pActInfo)
{
}
virtual IFlowNodePtr Clone(SActivationInfo *pActInfo)
{
return new CTutorialNode(pActInfo);
}
//端口被触发时调用,我们大部分都在这个地方写逻辑
virtual void ProcessEvent(EFlowEvent evt, SActivationInfo *pActInfo)
{
switch (evt)
{
case IFlowNode::eFE_Activate:
{
if (IsPortActive(pActInfo, EIP_Activate))
{
float left = GetPortFloat(pActInfo, EIP_Left);
float right = GetPortFloat(pActInfo, EIP_Right);
float ans = left * right;
//把ans值更新到输出端口数组
ActivateOutput(pActInfo, EOP_Result, ans);
}
}
break;
}
}
//配置节点的显示,输入和输出
virtual void GetConfiguration(SFlowNodeConfig &config)
{
static const SInputPortConfig inputs[] =
{
InputPortConfig_Void("Activate", "MyDes:Trigger the calculation"),
//端口名,默认值,描述
InputPortConfig("Left", 0, "MyDes2:The left side of the calculation"),
InputPortConfig("Right", 0, "MyDes2:The right side of the calculation"),
{ 0 }
};
static const SOutputPortConfig outputs[] =
{
OutputPortConfig("Reslut", "The Result of the calculation"),
{ 0 }
};
config.pInputPorts = inputs;
config.pOutputPorts = outputs;
config.sDescription = _HELP("Multiplies two numbers");
config.SetCategory(EFLN_APPROVED);
}
//这个函数并不需要我们重写任何的实现,我们在在内存为这个函数只需要添加一个声明
virtual void GetMemoryUsage(ICrySizer *s) const
{
s->Add(*this);
}
};
REGISTER_FLOW_NODE("Tutorial:Multiplier", CTutorialNode);
打开相应CE3的版本,就可以看到我们添加的自定义Node了
好了,今天就先到这里,明天我试着尝试用C#编辑一下,如果成功的话,就和大家分享经验,如果不成功的话,就暂时只能先放在一边了,除此之外,做个总结,教程第三章就算完成了!如果大家有问题可以直接留言,更希望如果大神能看到这篇文章,能给出一些指点!