Cocos2d-x lua 模拟器日志输出

  • 感想

从接触Cocos引擎到现在,我一直使用的Lua脚本语言开发项目,只是现在,大多数同行都转战Cocos Creator或者U3D了,每次逛官方网站,都没有几个关于Cocos2d-x的帖子了,也不知道现在还有多少人坚持在用Lua开发。好在Cocos官方也一直没有放弃Lua,还能再战几年

  • 前言

Cocos使用的日志输出,是一个命令行窗口,方便开发者查看日志输出,但其实不怎么好用。从我进入游戏行业开始,我就一直用的是当年带我入行的老大写的一个Windows Form程序接受日志输出,这个程序对我们都是公开的,自己也研究学习过。后来离开那个公司之后,就借鉴了这个日志输出程序,自己写了一个,后续也慢慢集成了一些自己写的工具。一直想把这个工具分享出来,只是或忙或忘,都没做成。

至于为什么要写这个东西,主要是嫌弃Cocos自带的黑窗口,另外本来项目就需要一些工具,就集成到一起了。用的比较多的功能就是看日志了,其他的都是些辅助功能和工具。

  • 正文

目前,我自己使用的这个,我就不分享了,因为只注重实用,都没怎么在乎界面什么的,大家伙看看就好了,我这里就只分享核心代码,基本上任何一个程序员都会用VS创建一个Windows窗口程序吧,只需要在这个窗口程序里面合适的位置加上我的代码就行了,怎么显示,怎么布局这个日志输出程序,那就是各位自己的事情了。




(这是我自己写的,界面丑,各位下手轻点)

既然Cocos能把游戏程序输出到命令行窗口,那么我们也同样能做到,把日志输出到Winform窗口,下面是Winform接受日志输出的核心代码:

//这是启动程序的代码
Process process = new Process();
// filename是要启动的程序的路径
process.StartInfo.FileName = filename;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
// process_Exited是进程退出的时候的回调
process.Exited += process_Exited;
// process_OutputDataReceived是进程接受到数据的时候的回调
process.OutputDataReceived += process_OutputDataReceived;	
process.Start();
process.BeginOutputReadLine();
process.WaitForInputIdle();

下面是另外两个回调的实现和使用

public void Process_Exited(object sender, EventArgs e)
{
    process.kill();// 可不调用,不记得以前为什么要加这个,好像是当程序自己崩溃的时候会导致接受输出报错才写的吧
    process.CancelOutputRead();
}




public void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    Console.writeLine(e.Data);
}

这里接受到的数据,只是进行了简单的打印,各位自行实现使用List存储这些日志,然后输出到Winform里面的Listview或者其他什么控件里面去。

简单的讲解一下,创建一个Winform程序,放个按钮,点击的时候启动指定程序(自个儿测试的时候写死路径吧,写活就是OpenFileDialog这个控件去选择一个exe程序啦)。
再就是把日志输出到ListView控件里面去,拖一个ListView到你的界面上,再动态插入对象就行,注意几个问题:

  1. Process_OutputDataReceived函数不是主线程调用的,如果直接在这个函数里面操作ListView对象,比如插入,会报错,就是不能在非主线程操作UI,相信很多人遇到过这个问题,因为安卓和iOS也是这样的。所以建议这里使用一个List存储,另起一个定时器Timer刷新ListView(只要List里面有新的,就取出来插入到ListView里面去);

  2. ListView频繁插入时,会导致界面闪烁,各位自行百度c#双缓存ListView的实现,减少闪烁;

  3. ListView跳到最下面:ListView_1.EnsureVisible();

  4. e.Data会打印很多无用日志,比如空字符串,比如一串*******,等等,自行过滤就行

  5. 过滤这一块也可以自己写控制器,比如是否过滤Cocos警告信息,是否过滤服务器发过来的数据信息等等,自行实现。


其他功能说明

  1. 调整模拟器大小,这个就是读取了cofig.lua文件里面的一个全局变量,改动的时候再写回去。这个主要是有时候要启动多个程序,但模拟器设定的窗口大小太大了,调整小一点,就方便看了。

  2. 调整连接服务器的IP,这个也是读取和修改config.lua里面的变量,方便每个开发人员连接到不同的服务器的(自己的 服务器,内网服务器,外网服务器等等),切换方便

  3. 图片资源压缩,这个要配套引擎代码的修改,这边怎么加密,引擎那边就怎么解密,这个就没什么好说的了

  4. 子游戏包压缩,以前做的是子游戏包下载,图方便,写了一键压缩,用到了一个库,ICSharpCode.SharpZipLib.dll,自行百度用法

  5. 解析csd文件,生成一些自动化的代码(没研究过怎么解析加密之后的csb文件,所以退而求其次,解析csd文件)


内嵌应用程序:
就是把程序内嵌到我们自己写的Winform里面,我在右边专门留了一个Panel,这是内嵌的时候的显示效果:

游戏程序没有窗口边界,主要用到的函数如下

// 这些是用到的函数的声明
[DllImport("user32.dll ", EntryPoint = "SetParent")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

[DllImport("user32.dll ", EntryPoint = "ShowWindow")]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

[DllImport("user32.dll ", EntryPoint = "SetWindowLong")]
public static extern int SetWindowLong(IntPtr hwnd, int nCmdShow, int ntemp);

[DllImport("user32.dll ", EntryPoint = "MoveWindow")]
public static extern int MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

            




// 这是具体使用方法
// 参数 parent是Winform里面的一个控件,我用的panel
// 函数里面使用到的GlobalVariable.appWin是一个全局静态变量,我另外有用到,所以单独拎出来了
// 可以通过前面的process拿到(process.MainWindowHandle)
// 要注意,这个值在程序启动的时候是拿不到的,所以我用的while,一直等着拿到这个值为止)
// 设定父窗口,设定窗口隐藏边框,设定窗口位置(有一些写死的几十个像素的移动,是为了放到合适的位置)
public void SetGameForm(System.Windows.Forms.Control parent)
{
    // Put it into this form
    SetParent(GlobalVariable.appWin, parent.Handle);
    // Remove border and whatnot
    SetWindowLong(GlobalVariable.appWin, GlobalVariable.GWL_STYLE, GlobalVariable.WS_VISIBLE);

    // Move the window to overlay it on this window
    MoveWindow(GlobalVariable.appWin, 5, 5, GlobalVariable.gameFormRect.Right - GlobalVariable.gameFormRect.Left-16, GlobalVariable.gameFormRect.Bottom - GlobalVariable.gameFormRect.Top-39, true);
}




最后,我本意只是分享这个接受日志输出的核心代码,管杀不管埋,出了问题各位自行解决,问题贴到帖子下面大家讨论也行,我也不是很擅长c#相关的知识,我自己写的工具我自己能用就行。

1赞

厉害啊

哇,几个月过去了,都没人看的嘛

我也在研究内嵌exe,或是子窗口的,多谢楼主提供思路