【续】强行在C# Winform中渲染Cocos2d-x 3.6
【前言】
上一篇讲了怎么把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行的方法:
static void _checkPath()
{
if (0 == s_resourcePath.length())
{
char pathBuffer[MAX_PATH] = { 0 };
WCHAR wszPath[MAX_PATH] = { 0 };
int nNum = WideCharToMultiByte(CP_ACP, 0, wszPath,
GetCurrentDirectory(sizeof(wszPath), wszPath),
pathBuffer, MAX_PATH, NULL, NULL);
pathBuffer[nNum] = '\\'; s_resourcePath = pathBuffer;
}
}
8、 为C++项目添加代码
首先添加一个标准DLL源文件dllmain.cpp(名字必须是这个):
// dllmain.cpp : Defines the entry point for the DLL application.
#include <windows.h> BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
//instance will be deleted automatically
break;
}
return TRUE;
}
然后将Classes文件夹中的源码加入到项目中:

最后添加接口(文件名自定,我使用的API.h和API.cpp),头文件:
#pragma once #define DLLEXPORT __declspec(dllexport) extern "C"
{
DLLEXPORT void Initialize(HWND parent);
DLLEXPORT void MainLoop();
DLLEXPORT void Destory();
};
实现:
#include "API.h" #include "cocos2d.h"
#include "AppDelegate.h" extern "C"
{
AppDelegate app;
DLLEXPORT void Initialize(HWND parent)
{
cocos2d::GLViewImpl::SetParent(parent);
cocos2d::Application::getInstance()->run();
} DLLEXPORT void MainLoop()
{
auto director = cocos2d::Director::getInstance();
director->mainLoop();
director->getOpenGLView()->pollEvents();
} DLLEXPORT void Destory()
{
auto director = cocos2d::Director::getInstance();
director->getOpenGLView()->release();
director->end();
director->mainLoop();
}
}
之后可以根据需求在接口中添加更多的函数。
⑨、 修改C#项目的属性
设置输出路径:

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

10、 为C#项目添加代码
添加一个调用DLL代码的类,我使用的名字叫NativeInterface:
using System;
using System.Runtime.InteropServices; namespace Cocos2dxCSharp
{
class NativeInterface
{
const string DLL_NAME = "App.dll"; [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void Initialize(int parent); [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void MainLoop(); [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void Destory();
}
}
在窗体编辑器中,对窗体添加Load和FormClosing两个事件响应方法,再拖一个Panel控件和一个Timer控件到窗体上。Timer控件的Interval值设为10,并添加Tick事件的响应方法。
然后完成方法:
private void Form1_Load(object sender, EventArgs e)
{
this.timer1.Start();
NativeInterface.Initialize(this.panel1.Handle.ToInt32());
} private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
this.timer1.Stop();
NativeInterface.Destory();
} private void timer1_Tick(object sender, EventArgs e)
{
NativeInterface.MainLoop();
}
11、 运行起来
如果编译没有出错的话,运行起来会看到这个样子:

【字符串传递处理】
普通的数据类型(int,float这些)是可以直接作为参数或返回值传递的。虽然C#中的string类型和C++中的const char*类型也是对应的,但是在调试过程中,如果不做处理会报错。
因为调试时C#的托管堆栈和C++的DLL堆栈并不属于同一块内存,就好比你拿着“城隍庙”这个地址,在成都找到的是各种电子元件,在上海找到的是各种小吃。
这里有篇博文讲了参数如何传递,我大概整理了一下:
1、字符串作为参数
C++:参数为char*
C#:参数为string,用[MarshalAs(UnmanagedType.LPStr)]修饰
[DllImport("A.dll)"]
static extern void Function([MarshalAs(UnmanagedType.LPStr)]string val);
2、字符串作为返回值
C++:返回值为char*
C#:返回值为string,使用[return:MarshalAs(UnmanagedType.LPStr)]修饰
[DllImport("A.dll)"]
[return:MarshalAs(UnmanagedType.LPStr)]
static extern string Function();
3、字符串作为输入输出参数
C++:参数为char*
C#:参数为byte[](那篇博文提到的用StringBuilder我这里传不了,不解)
[DllImport("A.dll)"]
static extern void Function(byte[] intoutVal);
如果要传递宽字符,使用UnmanagedType.LPWStr即可。
【续】强行在C# Winform中渲染Cocos2d-x 3.6的更多相关文章
- 强行在MFC窗体中渲染Cocos2d-x 3.6
[前言] 把Cocos2dx渲染到另一个应用程序框架中的方法,在2.x时代有很多大神已经实现了,而3.x的做法网上几乎找不着.这两天抽空强行折腾了一下,不敢独享,贴出来供大家参考. [已知存在的问题] ...
- 在 WinForm 中使用 Direct2D
在 C# 的 WinForm 应用中,界面的绘制使用的是 GDI+.不过在一些特别的应用中,可能需要用硬件加速来提高绘制的效率.下面就来介绍两种在 WinForm 应用中嵌入 Direct2D 的方法 ...
- 转载:WinForm中播放声音的三种方法
转载:WinForm中播放声音的三种方法 金刚 winForm 播放声音 本文是转载的文章.原文出处:http://blog.csdn.net/jijunwu/article/details/4753 ...
- C# Winform 中如何实现音乐播放和视频播放
C# Winform 中如何实现音乐播放和视频播放 namespace WindowsFormsApplication1 { public partial class Form2 : Form { ...
- 另一种在WINFORM中使用XNA的方法
之前在写化学分子模型制作程序的时候,使用一种方法,将WINFORM控件嵌入到XNA窗体中,从而实现了即使用WINFORM窗体控件又使用XNA.最近在写另一个物理运动学课件制作程序,同样使用XNA,但从 ...
- winform中dataGridView单元格根据值设置新值,彻底解决绑定后数据类型转换的困难
// winform中dataGridView单元格在数据绑定后,数据类型更改困难,只能迂回实现.有时候需要将数字变换为不同的文字描述,就会出现int32到string类型转换的异常,借助CellFo ...
- winform中ComboBox实现text和value,使显示和值分开,重写text和value属性
winform的ComboBox中只能赋值text,显示和值是一样的,很多时候不能满足根本需要,熟悉B/S开发的coder最常用的就是text和value分开的,而且web下DropDownList本 ...
- winform中dataGridView隔行显示不同的背景色,鼠标移动上显示不同颜色,离开后变回原色
winform中dataGridView隔行显示不同的背景色,鼠标移动上显示不同颜色,离开后变回原色 先设置奇数行颜色,这个有个自带的属性AlternatingRowsDefaultCellStyle ...
- winform中button点击后再点击其他控件致使button失去焦点,此时button出现黑色边线,去掉黑色边线的方法
winform中button点击后再点击其他控件致使button失去焦点,此时button出现黑色边线,去掉黑色边线的方法 button的FlatAppearence属性下,设置BorderSize= ...
随机推荐
- 阿里云CentOS安装firefox闪退
安装完vnc远程连接,接着安装firefox,点firefox木有任何提示就退 直接命令下运行,发现错误如下: /usr/lib/firefox/firefox: symbol lookup erro ...
- Scroll View 深入
转载自:http://mobile.51cto.com/hot-430409.htm 可能你很难相信,UIScrollView和一个标准的UIView差异并不大,scroll view确实会多一些方法 ...
- SDAU课程练习--problemG(1006)
题目描述 Problem Description The highest building in our city has only one elevator. A request list is m ...
- Direct3D中的绘制
1.顶点缓存和索引缓存 一个顶点缓存是一个包含顶点数据的连续内存空间:一个索引缓存是一个包含索引数据的连续内存空间. 顶点缓存用接口IDirect3DVertexBuffer9表示:索引缓存用接口ID ...
- Android Studio的使用(二)--Debug调试
使用Android Studio进行Debug调试,这里有一篇比较详细的介绍 http://www.2cto.com/kf/201506/408358.html 故不再重复介绍.
- egret GUI 文本混排+文本链接的聊天解决方案【取巧法】
ui方面: <e:Scroller verticalScrollPolicy="auto" width="468" height="620&qu ...
- SQL面试题——查询课程
题目: 成绩表(Grade),包含字段:GradeID(Int,自增), SNO(int, 学号), CNO(int, 课程号), Score(float,分数) 查询每门课程的平均(最高/最低)分及 ...
- windows矢量字体点阵数据的提取(转)
源:windows矢量字体点阵数据的提取 问题参考:windows api 获取字库点阵的问题 1.提取原理 在windows系统当中提取矢量字体的字模有很多方法,下面介绍一种利用GetGlyphOu ...
- Cocos2dx 学习笔记整理----开发环境搭建
最近在学习cocos2dx,预备将学习过程整理成笔记. 需要的工具和环境整理一下: 使用的版本 cocos2dx目前已经出到了v3.1.1,学习和项目的话还是用2.2.3为宜,毕竟不大想做小白鼠,并且 ...
- 170112、solr从服务器配置整合到项目实战
整合网上资源后 100%可运行的配合步骤,部署在tomcat 为例. 一:下载solr,版本为5.2.1 地址:http://pan.baidu.com/s/1eRAdk3o 解压出来. 1.在解压的 ...