context.GetSelection
报错System.StackOverflowException
:C#与C++通信需要内存对齐。托管代码与非托管代码之间需要封送数据。需要运用MarshalAs
特性1。
此属性是可选的,因为每个数据类型都有默认的封送处理行为。 仅当给定类型可以封送到多种类型时,此属性才是必需的。
接口ITfContext
中函数需要改为HRESULT GetSelection([In] TfEditCookie ec, [In] uint ulIndex, [In] uint ulCount, [Out] TF_SELECTION[] pSelection, [NullAllowed] out uint pcFetched);
函数需要改为HRESULT GetSelection([In] TfEditCookie ec, [In] uint ulIndex, [In] uint ulCount, [Out,MarshalAs(UnmanagedType.LPArray)] TF_SELECTION[] pSelection, [NullAllowed] out uint pcFetched);
之前使用的是ITfContext::GetStart
获取到ITfRange
,调用ITfRange::SetText
来插入文字。插入的位置默认为文章首,个别程序会插入到光标处,并且后退(eg. Windows记事本)。
后改用ITfcontext::GetSelection
获取TF_fSelection
实例后,通过获取range
属性来获取ITfRange
。解决了插入问题。
但是,这里出现了光标不向后移动的问题。就算给TfAnchor
设置了重力和合并,均改变不了输入以后光标的位置。最后,找到一个开源的输入法——狼毫输入法2——通过阅读源码,才解决问题(ps 通过阅读源码,感觉这个开源代码的写的挺优美的。简简单单的几行就解决问题了。
修改后的相关代码如下:
_selections = new TF_SELECTION[1];
var res = _context.GetSelection(ec, 4294967295, 1, _selections, out var pcFetched);
if (pcFetched == 1)
{
var range = _selections[0].range;
res = range.SetText(ec, 0, _words, _words.Length);
range.Collapse(ec, TfAnchor.TF_ANCHOR_END);
var selection = new TF_SELECTION
{
range = range,
style = new TF_SELECTIONSTYLE
{
ase = TfActiveSelEnd.TF_AE_END,
fInterimChar = false
}
};
_context.SetSelection(ec, 1, selection);
}
在2002年,李晓磊等人在动物群体智能行为研究的基础上提出的一种新型方盛优化算法,该算法根据水域中鱼生存数目最多的地方就是本水域中富含营养物质最多的地方这一特点来模拟鱼群的觅食行为而实现寻优。算法主要利用鱼的三大基本行为:觅食、聚群和追尾行为,采用自上而下的寻优模式从构造个体的底层行为开始,通过鱼群中各个体的局部寻优,达到全局最优值在群体中凸显出来的目的3。
现在人工智能成功用于游戏的案例有4
此外还有AI修复古建筑5
将一个请求封装为一个对象,从而允许你使用不同的请求、队列或者日志将客户端参数化,同时支持请求操作的撤销与恢复。
命令就是面向对象的回调。
对应代码c++:
// 基类
class Command
{
public:
virtual ~Command(){}
virtual void execute(GameActor& actor)=0;
};
class JumpCommand: public Command
{
public:
virtual void execute(GameActor& actor){
actor.jump();
}
}
class FireCommand :public Command
{
virtual void execute(GameActor& actor){
actor.fireGun();
}
}
// ...
// 空值命令对象模式
class NullCommand: public Command
{
virtual void execute(GameActor& actor){}
}
// 输入处理
class InputHandler
{
public:
Command* handleInput();
// 绑定其他命令
private:
Command* buttonX_;
Command* buttonY_;
Command* buttonA_;
Command* buttonB_;
}
void InputHnadler: handleInput()
{
if (isPressed(BUTTON_X)) return buttonX_;
else if (isPressed(BUTTON_Y)) return buttonY_;
else if (isPressed(BUTTON_A)) return buttonA_;
else if (isPressed(BUTTON_B)) return buttonB_;
}
// 角色执行命令
Command* command = inputHandler.handleInput();
if(command)
{
command->exectue(actor);
}
在命令与角色之间加入间接层,可以使得玩家以及AI操控任意的角色。如果我们把命令序列化,便可以通过网络发送数据流,这个是多人游戏中主要的一部分。
c++:
// 基类
class Command
{
public:
virtual ~Command(){}
virtual void execute(GameActor& actor)=0;
virtual void undo()=0;
};
class MoveUnitCommand: public Command
{
public:
MoveUnitCommand(Unit* unit,int x,int y): unit_(unit),x_(x),y_(y)
{}
virtual void execute()
{
unit_->moveTo(x_,y_);
}
private:
Unit* unit_;
int x_;
int y_;
}
与备忘录相比,节约内存。
重做在游戏中不常见,但回放很常见。
JS实现(使用闭包)
function makeMoveUnitCommand(unit,x,y){
var xBefore,yBefore;
return function(){
execute:function(){
xBefore = unit.x();
yBefore = unit.y();
unit.moveTo(x,y);
},
undo: function(){
unit.moveTo(xBefore,yBefore)
}
}
}
class TreeModel
{
private:
Mesh mesh_;
Texture bark_;
Texture leaves_;
}
class Tree
{
private:
TreeModel* model_;
Vector position_;
double height_;
double thicknes_;
Color barkTint_;
Color leafTint_;
}
与类型对象模式对比:
类型对象通过把“类型”对象化,可以尽可能较少定义新类型的数量,而享元模式却更加注重效率。
应用:
TiledMap
* 一般来说,享元对象总是不可变的。
Unity为Unity Technologies 公司开发的三维游戏制作引擎。其凭借自身的跨平台性与开放性优势已经逐渐成为当今世界范围内的主流游戏引擎6。由于手机游戏的流行,目前2D游戏开发的需求量也越来越大了,因此Unity3D游戏引擎也增加了2D游戏开发的支持7。
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能8。
xLua为Unity、 .Net、 Mono等C#环境增加Lua脚本编程的能力,借助xLua,这些Lua代码可以方便的和C#相互调用9。
原因为游戏为横版弹幕游戏设计,弹幕的子弹变化万千,犹如夜空中中热烈绽放的烟花一样,绚丽多彩。需要一个高效的解释性语言去控制每个子弹和怪物的没帧逻辑。而Lua正好胜任此工作。
由于Lua没有类继承,因此写了Class
函数来生成实例,利用原型链来实现继承。核心代码如下:
-- 对应新类
function Class(base)
base = base or object
local result = {}
result.is_class = true
result.init = base.init
result.frame = base.frame
result.kill = base.kill
result.base = base
--setmetatable(result,_met)
return result
end
生成的实例可以由New
来直接运行:
function New(obj, ...)
local new = Class(obj)
new:init(...)
return new
end
逻辑定义全在init,由Lua协程来控制每帧操作:
添加CSharpCallLua标签。比如:
public class LuaObject : MonoBehaviour
{
[XLua.CSharpCallLua]
public delegate void KillDelegate(int index);
[CSharpCallLua]
private delegate void DoFrameDelegate();
private LuaEnv luaEnv = null;
private DoFrameDelegate DoFrame;
public KillDelegate Kill;
void Start()
{
//...
DoFrame = luaEnv.Global.Get<DoFrameDelegate>("DoFrame");
Kill = luaEnv.Global.GetInPath<KillDelegate>("Kill");
}
}
如果还是存在问题的话,清除并重新生成代码。
Xlua-> Clear Generated Code
Xlua-> Generate Code
即可解决问题。
这边只更新Lua更新部分
void Update()
{
if (IsRunning)
{
luaEnv?.Tick();
var current = Time.realtimeSinceStartup;
var needUpdateframeNum = (current - startTime) * 60 - frameNum;
if(needUpdateframeNum>45)
{
// 卡
Debug.LogError("太卡了!");
// 勉勉强强让玩家继续
needUpdateframeNum = 1;
frameNum = 0;
startTime = Time.realtimeSinceStartup;
}
for (var i=0;i<needUpdateframeNum;i++)
{
DoFrame();
frameNum++;
}
}
}
MarshalAsAttribute 类 (System.Runtime.InteropServices) | Microsoft Docs https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.interopservices.marshalasattribute?view=netframework-4.8 ↩︎
rime/weasel: 【小狼毫】Rime for Windows ↩︎
人工鱼群算法详解_wp_csdn的专栏-CSDN博客 https://blog.csdn.net/wp_csdn/article/details/54577567 ↩︎
《游戏行业发展概况》 https://game.academy.163.com/live?id=ga-1601284961961 ↩︎
AI还原古代遗迹,一文多图带你穿越时空!_进行 https://www.sohu.com/a/413542857_587438 ↩︎
Unity 3D简介 http://c.biancheng.net/unity3d/10/ ↩︎
[Unity2D]游戏引擎介绍_weixin_34204057的博客-CSDN博客 https://blog.csdn.net/weixin_34204057/article/details/86275226 ↩︎
Lua 教程 | 菜鸟教程 https://www.runoob.com/lua/lua-tutorial.html ↩︎
Tencent/xLua: xLua is a lua programming solution for C# ( Unity, .Net, Mono) , it supports android, ios, windows, linux, osx, etc. https://github.com/Tencent/xLua ↩︎