【前言】

  上一篇讲了怎么把Cocos2d-x 3.6渲染进MFC窗体,这里来讲一下怎么在C# Winform中做到同样的功能。如果你不熟悉MFC的使用但对C# Winform比较在行,请往下看。

  这一篇是作为上一篇的副属文,所以文中提到的部分操作需要在上一篇中找……博主懒逼不在这复制粘贴了。


【核心思想】

  同上一章不同的是,C#是托管环境,并不能直接用“对象.方法()”这样的形式来访问Cocos层的代码。我们需要在其间建立一个DLL层(C++编写)作为Cocos层的接口,让C#通过接口来控制Cocos层。


【需要的工具】

  1、    安装了C#组件的Visual Studio 2013

  2、    Cocos2d-x 3.6

  3、    GLFW (下载地址:点我

  4、    CMake(下载地址:点我


【操作步骤】

  1、    创建C# Winform项目

    .NET的版本随意,使用默认的即可。

    

  2、    拷贝必要文件

    参考上一篇

  3、    创建空的C++项目

    VS2013创建的C++ DLL项目默认是Win8.1平台的,不知道里面装了什么奇怪的东西进去……于是手动创建干净的DLL项目。项目名称自定,我使用的是“App”

    

    添加完成后,将App项目设为C#项目的依赖项。

  4、    在解决方案中加入Cocos项目

    将libcocos2d,libbox2d,libspine加入解决方案中,并把libcocos2d设为App项目的依赖项。

  5、    修改C++项目的属性

    在属性管理器(视图——属性管理器)中为项目添加cocos2dx的两个属性表。属性表位于解决方案目录\cocos2d\cocos\2d:

    

    常规页面,按照打框处设置:

    

    调试页面,设置工作目录:

    

    

    附加包含目录中加入:

    $(EngineRoot)cocos\audio\include
    $(EngineRoot)external
    $(EngineRoot)external\chipmunk\include\chipmunk
    $(EngineRoot)extensions
    ..\Classes
    ..
    %(AdditionalIncludeDirectories)
    $(_COCOS_HEADER_WIN32_BEGIN)
    $(_COCOS_HEADER_WIN32_END)

  

    预处理器定义中加入:

    _WIN32
    _WINDOWS
    COCOS2D_DEBUG=1
    _CRT_SECURE_NO_WARNINGS

    附加库目录中加入:

    $(_COCOS_LIB_PATH_WIN32_BEGIN)

    $(_COCOS_LIB_PATH_WIN32_END)

  

    附加依赖项加入:

    $(_COCOS_LIB_WIN32_BEGIN)

    $(_COCOS_LIB_WIN32_END)

    libcocos2d.lib

  6、    修改GLFW

    同上一篇

  7、    修改Cocos层

    同上一篇,以及修改CCFileUtils-win32.cpp 59行的方法:

  1. static void _checkPath()
  2. {
  3. if (0 == s_resourcePath.length())
  4. {
  5. char pathBuffer[MAX_PATH] = { 0 };
  6. WCHAR wszPath[MAX_PATH] = { 0 };
  7. int nNum = WideCharToMultiByte(CP_ACP, 0, wszPath,
  8. GetCurrentDirectory(sizeof(wszPath), wszPath),
  9. pathBuffer, MAX_PATH, NULL, NULL);
  10. pathBuffer[nNum] = '\\';
  11.  
  12. s_resourcePath = pathBuffer;
  13. }
  14. }

  

  8、    为C++项目添加代码

    首先添加一个标准DLL源文件dllmain.cpp(名字必须是这个):

  1. // dllmain.cpp : Defines the entry point for the DLL application.
  2. #include <windows.h>
  3.  
  4. BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
  5. {
  6. switch (ul_reason_for_call)
  7. {
  8. case DLL_PROCESS_ATTACH:
  9. case DLL_THREAD_ATTACH:
  10. break;
  11. case DLL_THREAD_DETACH:
  12. case DLL_PROCESS_DETACH:
  13. //instance will be deleted automatically
  14. break;
  15. }
  16. return TRUE;
  17. }

  

    然后将Classes文件夹中的源码加入到项目中:

    

    最后添加接口(文件名自定,我使用的API.h和API.cpp),头文件:

  1. #pragma once
  2.  
  3. #define DLLEXPORT __declspec(dllexport)
  4.  
  5. extern "C"
  6. {
      DLLEXPORT void Initialize(HWND parent);
  7.   DLLEXPORT void MainLoop();
  8.   DLLEXPORT void Destory();
  9. };

    实现:

  1. #include "API.h"
  2.  
  3. #include "cocos2d.h"
  4. #include "AppDelegate.h"
  5.  
  6. extern "C"
  7. {
  8. AppDelegate app;
  9. DLLEXPORT void Initialize(HWND parent)
  10. {
  11. cocos2d::GLViewImpl::SetParent(parent);
  12. cocos2d::Application::getInstance()->run();
  13. }
  14.  
  15. DLLEXPORT void MainLoop()
  16. {
  17. auto director = cocos2d::Director::getInstance();
  18. director->mainLoop();
  19. director->getOpenGLView()->pollEvents();
  20. }
  21.  
  22. DLLEXPORT void Destory()
  23. {
  24. auto director = cocos2d::Director::getInstance();
  25. director->getOpenGLView()->release();
  26. director->end();
  27. director->mainLoop();
  28. }
  29. }

    之后可以根据需求在接口中添加更多的函数。

  ⑨、    修改C#项目的属性

    设置输出路径:

    

    设置工作目录和启用本机代码调试(勾上后可以调试C++层):

    

  10、    为C#项目添加代码

    添加一个调用DLL代码的类,我使用的名字叫NativeInterface:

  1. using System;
  2. using System.Runtime.InteropServices;
  3.  
  4. namespace Cocos2dxCSharp
  5. {
  6. class NativeInterface
  7. {
  8. const string DLL_NAME = "App.dll";
  9.  
  10. [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
  11. public static extern void Initialize(int parent);
  12.  
  13. [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
  14. public static extern void MainLoop();
  15.  
  16. [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
  17. public static extern void Destory();
  18. }
  19. }

    在窗体编辑器中,对窗体添加Load和FormClosing两个事件响应方法,再拖一个Panel控件和一个Timer控件到窗体上。Timer控件的Interval值设为10,并添加Tick事件的响应方法。

    然后完成方法:

  1. private void Form1_Load(object sender, EventArgs e)
  2. {
  3. this.timer1.Start();
  4. NativeInterface.Initialize(this.panel1.Handle.ToInt32());
  5. }
  6.  
  7. private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  8. {
  9. this.timer1.Stop();
  10. NativeInterface.Destory();
  11. }
  12.  
  13. private void timer1_Tick(object sender, EventArgs e)
  14. {
  15. NativeInterface.MainLoop();
  16. }

  

  11、    运行起来

    如果编译没有出错的话,运行起来会看到这个样子:

    


【字符串传递处理】

  普通的数据类型(int,float这些)是可以直接作为参数或返回值传递的。虽然C#中的string类型和C++中的const char*类型也是对应的,但是在调试过程中,如果不做处理会报错。

  因为调试时C#的托管堆栈和C++的DLL堆栈并不属于同一块内存,就好比你拿着“城隍庙”这个地址,在成都找到的是各种电子元件,在上海找到的是各种小吃。

  这里有篇博文讲了参数如何传递,我大概整理了一下:

  1、字符串作为参数
    C++:参数为char*
    C#:参数为string,用[MarshalAs(UnmanagedType.LPStr)]修饰

  1. [DllImport("A.dll)"]
  2. static extern void Function([MarshalAs(UnmanagedType.LPStr)]string val);

  

  2、字符串作为返回值
    C++:返回值为char*
    C#:返回值为string,使用[return:MarshalAs(UnmanagedType.LPStr)]修饰

  1. [DllImport("A.dll)"]
  2. [return:MarshalAs(UnmanagedType.LPStr)]
  3. static extern string Function();

  

  3、字符串作为输入输出参数
    C++:参数为char*
    C#:参数为byte[](那篇博文提到的用StringBuilder我这里传不了,不解)

  1. [DllImport("A.dll)"]
  2. static extern void Function(byte[] intoutVal);

  如果要传递宽字符,使用UnmanagedType.LPWStr即可。

【续】强行在C# Winform中渲染Cocos2d-x 3.6的更多相关文章

  1. 强行在MFC窗体中渲染Cocos2d-x 3.6

    [前言] 把Cocos2dx渲染到另一个应用程序框架中的方法,在2.x时代有很多大神已经实现了,而3.x的做法网上几乎找不着.这两天抽空强行折腾了一下,不敢独享,贴出来供大家参考. [已知存在的问题] ...

  2. 在 WinForm 中使用 Direct2D

    在 C# 的 WinForm 应用中,界面的绘制使用的是 GDI+.不过在一些特别的应用中,可能需要用硬件加速来提高绘制的效率.下面就来介绍两种在 WinForm 应用中嵌入 Direct2D 的方法 ...

  3. 转载:WinForm中播放声音的三种方法

    转载:WinForm中播放声音的三种方法 金刚 winForm 播放声音 本文是转载的文章.原文出处:http://blog.csdn.net/jijunwu/article/details/4753 ...

  4. C# Winform 中如何实现音乐播放和视频播放

    C#  Winform 中如何实现音乐播放和视频播放 namespace WindowsFormsApplication1 { public partial class Form2 : Form { ...

  5. 另一种在WINFORM中使用XNA的方法

    之前在写化学分子模型制作程序的时候,使用一种方法,将WINFORM控件嵌入到XNA窗体中,从而实现了即使用WINFORM窗体控件又使用XNA.最近在写另一个物理运动学课件制作程序,同样使用XNA,但从 ...

  6. winform中dataGridView单元格根据值设置新值,彻底解决绑定后数据类型转换的困难

    // winform中dataGridView单元格在数据绑定后,数据类型更改困难,只能迂回实现.有时候需要将数字变换为不同的文字描述,就会出现int32到string类型转换的异常,借助CellFo ...

  7. winform中ComboBox实现text和value,使显示和值分开,重写text和value属性

    winform的ComboBox中只能赋值text,显示和值是一样的,很多时候不能满足根本需要,熟悉B/S开发的coder最常用的就是text和value分开的,而且web下DropDownList本 ...

  8. winform中dataGridView隔行显示不同的背景色,鼠标移动上显示不同颜色,离开后变回原色

    winform中dataGridView隔行显示不同的背景色,鼠标移动上显示不同颜色,离开后变回原色 先设置奇数行颜色,这个有个自带的属性AlternatingRowsDefaultCellStyle ...

  9. winform中button点击后再点击其他控件致使button失去焦点,此时button出现黑色边线,去掉黑色边线的方法

    winform中button点击后再点击其他控件致使button失去焦点,此时button出现黑色边线,去掉黑色边线的方法 button的FlatAppearence属性下,设置BorderSize= ...

随机推荐

  1. 新手常见的python报错及解决方案

    此篇文章整理新手编写代码常见的一些错误,有些错误是粗心的错误,但对于新手而已,会折腾很长时间才搞定,所以在此总结下我遇到的一些问题.希望帮助到刚入门的朋友们.后续会不断补充. 目录 1.NameErr ...

  2. C++多线程一

    CreateThread()创建一个新的线程. ExitThread()正常的结束一个线程的执行. CloseHandle()关闭一个线程的句柄. CreateThread()函数原型如下: HAND ...

  3. CG之菲涅尔效果简单实现

    菲涅尔效果,指当光到达两种材质的接触面时,一些光在接触面的表面被反射出去,而另一部分光将发生折射穿过接触面. 现在要用shader来实现这种效果,如果要精确地描述这种底层的物理,其计算公式是非常复杂的 ...

  4. mysql查询的cache

    Mysql SQL_NO_CACHE不生效的问题 贾春春 1 票 1224 我想通过SQL_NO_CACHE得知某个query查询速度,但似乎无法实现 例如首次查询: mysql> select ...

  5. PHP 代码跟踪

    怎么知道代码的执行过程呢,也就是说怎么知道:是先执行哪些代码,然后执行哪些代码呢? 这里有一个非常犀利的函数,可以让你知道代码的执行过程 debug_backtrace()  函数. 来一段代码: L ...

  6. 使用windows上 mxnet 预编译版本

    操作系统: 64位Windows10 mxnet的Windows预编译版本:下载地址 分为不支持GPUs和支持GPUs版并,一般选择GPUs版本. 将下载的压缩包解压,比如解压到D:\mxnet.然后 ...

  7. Bootstrap环境及屏幕适配-(一)

    一.环境搭建 1.目录结构 需要引用的文件有, jquery.js.bootstrap.min.js 和 bootstrap.min.css 文件,下面看下在线的文档Hello Word <!D ...

  8. uvc摄像头代码解析1

    一.FAQ 1.判断自己的摄像头是否支持uvc标准 输入lsusb //列出usb设备 [cpp]   Bus 001 Device 001: ID 1d6b:0002 Linux Foundatio ...

  9. margin 相关 bug 系列

    原文地址:margin系列之bug巡演 by @doyoe IE6浮动双倍margin bug 这当是IE6最为经典的bug之一. 触发方式 元素被设置浮动 元素在与浮动一致的方向上设置margin值 ...

  10. iOS10适配——相机,通讯录,麦克风等权限设置

    崩溃:[access] This app has crashed because it attempted to access privacy-sensitive data without a usa ...