存档

2013年7月 的存档

cocos2d-x创建新项目模板

2013年7月31日 没有评论

  1、起因

    长期使用项目中自带的HelloWorldScene来创建模板工程,不知大家有木有感到厌烦?

    我是个懒人,所以就弄了个新的模板工程。这样最起码可以不用每次都把HelloWorldScene删掉再创建一个Scene了,求不被鄙视…… 另外因为通常都会用cocosBuilder作为界面的编辑工具,我就将ccbi文件也加进模板项目中了。

2、内容概述

    这个模板项目大致包含有:

1、主Scene变更为GameScene。其中有两个层,分别是GameLayer与HudLayer。

        2、HudLayer中包含一个cocosBuilder导出的状态显示层。

        3、HudLayer中包含自动更新检测与退出按钮。

    有图有真相:

cocos2d-x创建新项目模板

   项目运行起来是这样的:

  cocos2d-x创建新项目模板

    像素设定为1024×768。

    工程目录是这样的:

        cocos2d-x创建新项目模板

 3、原理

    vs项目模板是在VS2012/VC/vcprojects中。我们当然可以直接在其中做更改。不过有个更好的方式是从通过示例项目添加入手,编写一个与之对应的新模板项目。
    找到cocos2d-2.1.2/template/msvc这个文件夹。当初我们添加vs项目时运行的就是InstallWizardForVS2012.js这个脚本。我们只要复制这个过程,定位到一个新的项目中,是不是就可以了呢?说干就干。

4、动手更改

    首先复制一份InstallWizardForVS2012.js。

    不要运行,以编辑的方式打开这个新的副本。

    找到这部分:

 // Wizard Info
    var nNumWizards = 1;

    var astrWizardName = new Array();
    astrWizardName[0] = "CCAppWiz.win32";

    var nCntr;
    for (nCntr = 0; nCntr < nNumWizards; nCntr++) {
        var strSourceFolder = FileSys.BuildPath(strScriptPath, astrWizardName[nCntr]);
......

    CCAppWiz.win32是项目名,这就是我们要找的了。所以我们还要复制一份CCAppWiz.win32。我重命名为layerWithHud.win32。项目名改了。项目内容自然也要改。把文件夹中的CCAppWiz都改掉,效果如下:

    cocos2d-x创建新项目模板

     下面我们来编辑文件内容。 首先是.vsdir。

     这个文件是与VS模板所对应的。我将其更改如下:

layerWithHud.win32.vsz| |LayerWithHud Application |1|Create A Application With Basic Layer and Hud.| |6777|4096|#1154

     第一个字段表示所对应的.vsz文件的名字。第二个字段是模板的名字。第四个是描述。改好保存。

    

    然后我们打开VS的项目。将自己之前调试好的类,正确的加入到项目中。这个项目是08生成的,我正好也有,就没转换项目,用vs2012打开并进行调整效果也是一样的。

      cocos2d-x创建新项目模板

    接下来是Templates/1033/Templates.inf。这个文件描述了要复制到新项目的文件都有些什么:

proj.win32/res/root.ico
proj.win32/root.rc
proj.win32/resource.h

proj.win32/main.h
proj.win32/main.cpp

Classes/AppDelegate.h
Classes/AppDelegate.cpp

[! if CC_USE_LUA]
../../../../../scripting/lua/cocos2dx_support/LuaCocos2d.cpp
../../../../../scripting/lua/cocos2dx_support/LuaCocos2d.h
../../../../../scripting/lua/cocos2dx_support/CCLuaEngine.cpp
../../../../../scripting/lua/cocos2dx_support/CCLuaEngine.h
../../../../../scripting/lua/cocos2dx_support/Cocos2dxLuaLoader.h
../../../../../scripting/lua/cocos2dx_support/Cocos2dxLuaLoader.cpp
../../../../../scripting/lua/cocos2dx_support/tolua_fix.c
../../../../../scripting/lua/cocos2dx_support/tolua_fix.h
[! else]
Classes/CCBHud.h
Classes/CCBHud.cpp
Classes/GameLayer.h
Classes/GameLayer.cpp
Classes/GameScene.h
Classes/GameScene.cpp
Classes/HudLayer.h
Classes/HudLayer.cpp
[! endif]

[! if CC_USE_LUA]
Resources/Default.png
Resources/crop.png
Resources/farm.jpg
Resources/land.png
Resources/menu2.png
Resources/Icon.png
Resources/dog.png
Resources/hello.lua
Resources/hello2.lua
Resources/menu1.png
Resources/background.mp3
Resources/effect1.wav
[! else]
Resources/CloseSelected.png
Resources/CloseNormal.png
Resources/HelloWorld.png
Resources/Texture/Time_New_Roman.fnt
Resources/Texture/Time_New_Roman.png
Resources/Texture/Time_New_Roman_small.fnt
Resources/Texture/Time_New_Roman_small.png
Resources/Texture/back.png
Resources/HudHorizontal.ccbi
CCBProject_Hub.rar
[! endif]

    如果定义了Lua,即:向导勾选了Lua,则进入Lua的条件语句。目前与Lua的逻辑无关。我的Class中的文件要复制过去,所以加入到其中。相应的ccbi文件与字体图片什么的也要一并写进去。每个文件都写有些麻烦,有人知道怎么添加整个文件夹,希望能告诉我。最后那个rar是cocosBuilder的项目。我打成一个rar随项目资源一起复制过去。

    

    改了一圈最终可以改动InstallWizardForVS2012.js这个副本文件啦,我们把它重命名为InstallLayerWizardForVS2012.js 找到之前那部分,改为:

 // Wizard Info
    var nNumWizards = 1;

    var astrWizardName = new Array();
    astrWizardName[0] = "layerWithHud.win32";

    var nCntr;
    for (nCntr = 0; nCntr < nNumWizards; nCntr++) {
        var strSourceFolder = FileSys.BuildPath(strScriptPath, astrWizardName[nCntr]);
    ......

    还有需要更改一处:

    // Read and write additional CCAppWiz.vsdir, add path to the wizard location
    try {
        var strDest = FileSys.BuildPath(strDestCCFolder, "LayerWithHud.vsdir");

        var ForWriting = 2;

        var fileDest = FileSys.OpenTextFile(strDest, ForWriting, true);
    ......

    这个.vsdir是储存在项目模板中的文件的名称,如果不更改,会将之前HelloWorldScene模板替换掉。

5、收尾

    运行刚刚改好的InstallLayerWizardForVS2012.js 弹出App Wizard successfully installed for VS2012!则说明安装正确了。如果不正确可能是目录的问题,检查一下相应的文件。

     如果一切顺利,重启VS即可看到你的新项目模板了。


本篇博客出自阿修罗道,转载请注明出处:http://blog.csdn.net/fansongy/article/details/9672375

分类: cocos2d-x 标签:

HTML5 Canvas中实现文字链接

2013年7月31日 没有评论

HTML5 Canvas中没有关于链接的API,所以我们只有自己来实现了。

首先,我们来想一下,链接有什么特点。第一个想到的估计就是它能跳转,这是链接最显著的特点,当然这也是废话,要不怎么能叫链接?第二个想到的可能就是文字下方的下划线;第三可能就是当鼠标盘旋在它上空时,鼠标要变成一只手。这些都不难实现,因为跳转可以用window.open()来实现,下划线用html5 canvas API就能实现,更改鼠标的样式用css改就OK。接下来就来讲一下如何实现这些。

本次开发依然用到了开源引擎lufylegend,引擎的一些信息如下:

引擎官方网站:

http://lufylegend.com/lufylegend

引擎API文档:

http://lufylegend.com/lufylegend/api

一,LLink类

首先我们来创建一个LLink类。代码如下:

function LLink(url,text,type,color,font,size){
	var self = this;
	base(self,LSprite,[]);
	
	self.type = "LLink";
	self.url = url;
	self.openType = type || "blank";
	
	self.x = 0;
	self.y = 0;
}

这只是一个很基本的类,有6个参数,分别是打开【链接的地址】,【显示文字】,【链接打开的类型】,【链接颜色】,【链接字体】,【链接尺寸】。由于这个类是继承自LSprite,所以它享有LSprite的一切属性和函数,比如x,y,addChild()等。(注:在lufylegend中base()函数可用于继承,用法可参照API文档。LSprite的用法亦可以参照API文档上的说明)

接着我们更改它的type属性,以便和其他类进行区分。然后用url属性保存链接,用openType保存链接打开的类型。如果链接类型没有设置,就默认为"blank",表示在新的标签页打开。至于xxx || yyy的用法以前也讲过,意思是如果xxx的值为null之类的,就将值设置为yyy。

由于是继承自LSprite,所以不能直接显示文字。因此要加入一个属性text,这个属性是一个LTextField(用法见API文档)对象,用于显示文字,具体代码如下:

self.text.color = color || "blue";
self.text.font = font || "urf-8";
self.text.size = size || 12;
self.text.x = 0;
self.text.y = 0;
self.text.text = text || url;
self.addChild(self.text);

从上面的代码可以看出,如果不设置链接的显示文字,显示文字就为网址。不设置颜色就自动设置为蓝色

为了方便加一个下划线,我们建立一个名为underLine的LSprite对象,然后通过LSprite实现画线,具体代码如下:

self.underLine = new LSprite();
self.underLine.graphics.drawRect(0,self.text.color,[0,0,self.text.getWidth(),Math.floor(self.text.size * 0.1)],true,self.text.color);
self.underLine.x = 0;
self.underLine.y = parseInt(self.text.getHeight()) + Math.floor(self.text.size * 0.3);
self.addChild(self.underLine);

由于LTextField类没有鼠标事件,所以我们没法判断链接文字是否被点击,为了实现点击事件,我特地问了lufy,lufy给我提了一个dirty way(虽说是一个dirty way,不过还真的好使 ^_^):在文本上方画一个与文本大小一样的透明矩形,由于LSprite是可以加入事件的,而且矩形是可以响应事件的,所以就给自身加一个鼠标事件,如果点到文字上,相当于点到透明矩形上,然后就触发事件。于是我们加一个LSprite:

self.back = new LSprite();
self.back.graphics.drawRect(0,"transparent",[0,0,self.text.getWidth(),self.text.getHeight()],true,"transparent");
self.addChild(self.back);

然后加入鼠标事件:

self.addEventListener(LMouseEvent.MOUSE_DOWN,self._jump);

到现在为止,LLink里的代码有这些:

function LLink(url,text,type,color,font,size){
	var self = this;
	base(self,LSprite,[]);
	
	self.type = "LLink";
	self.url = url;
	self.openType = type || "blank";
	
	self.x = 0;
	self.y = 0;
	
	self.text = new LTextField();
	self.text.color = color || "blue";
	self.text.font = font || "urf-8";
	self.text.size = size || 12;
	self.text.x = 0;
	self.text.y = 0;
	self.text.text = text || url;
	self.addChild(self.text);
	
	self.underLine = new LSprite();
	self.underLine.graphics.drawRect(0,self.text.color,[0,0,self.text.getWidth(),Math.floor(self.text.size * 0.1)],true,self.text.color);
	self.underLine.x = 0;
	self.underLine.y = parseInt(self.text.getHeight()) + Math.floor(self.text.size * 0.3);
	self.addChild(self.underLine);
	
	self.back = new LSprite();
	self.back.graphics.drawRect(0,"transparent",[0,0,self.text.getWidth(),self.text.getHeight()],true,"transparent");
	self.addChild(self.back);
	
	self.addEventListener(LMouseEvent.MOUSE_DOWN,self._jump);
}

二,跳转网页

在上面的代码中我们已经实现了下划线,和链接文字,并且加入了鼠标事件。

接下来要实现一下如何跳转网页。前面我们说了,跳转网页的的话可以用到window.open(),这个函数的用法如下

语法:

window.open(URL,name,features,replace)
参数 描述
URL 一个可选的字符串,声明了要在新窗口中显示的文档的 URL。如果省略了这个参数,或者它的值是空字符串,那么新窗口就不会显示任何文档。
name 一个可选的字符串,该字符串是一个由逗号分隔的特征列表,其中包括数字、字母和下划线,该字符声明了新窗口的名称。这个名称可以用作标记 <a> 和 <form> 的属性 target 的值。如果该参数指定了一个已经存在的窗口,那么 open() 方法就不再创建一个新窗口,而只是返回对指定窗口的引用。在这种情况下,features 将被忽略。
features 一个可选的字符串,声明了新窗口要显示的标准浏览器的特征。如果省略该参数,新窗口将具有所有标准特征。在窗口特征这个表格中,我们对该字符串的格式进行了详细的说明。
replace

一个可选的布尔值。规定了装载到窗口的 URL 是在窗口的浏览历史中创建一个新条目,还是替换浏览历史中的当前条目。支持下面的值:

  • true – URL 替换浏览历史中的当前条目。
  • false – URL 在浏览历史中创建新的条目。

(以上内容来自w3school,网址:http://www.w3school.com.cn/htmldom/met_win_open.asp

有了以上的介绍,我想实现跳转已经是很简单的了。

由于我们的鼠标事件触发的是_jump成员函数,所以加入_jump方法,代码如下:

LLink.prototype._jump = function(event,self){
	var openType = "_" + self.openType;
	window.open(self.url, openType);
}

三,更改鼠标样式

首先,为了了解css如何更改鼠标样式,我先介绍一下css里的cursor属性:

实例

一些不同的光标:
span.crosshair {cursor:crosshair;}
span.help {cursor:help;}
span.wait {cursor:wait;}

可能的值

描述
url

需使用的自定义光标的 URL。

注释:请在此列表的末端始终定义一种普通的光标,以防没有由 URL 定义的可用光标。

default 默认光标(通常是一个箭头)
auto 默认。浏览器设置的光标。
crosshair 光标呈现为十字线。
pointer 光标呈现为指示链接的指针(一只手)
move 此光标指示某对象可被移动。
e-resize 此光标指示矩形框的边缘可被向右(东)移动。
ne-resize 此光标指示矩形框的边缘可被向上及向右移动(北/东)。
nw-resize 此光标指示矩形框的边缘可被向上及向左移动(北/西)。
n-resize 此光标指示矩形框的边缘可被向上(北)移动。
se-resize 此光标指示矩形框的边缘可被向下及向右移动(南/东)。
sw-resize 此光标指示矩形框的边缘可被向下及向左移动(南/西)。
s-resize 此光标指示矩形框的边缘可被向下移动(北/西)。
w-resize 此光标指示矩形框的边缘可被向左移动(西)。
text 此光标指示文本。
wait 此光标指示程序正忙(通常是一只表或沙漏)。
help 此光标指示可用的帮助(通常是一个问号或一个气球)。

测试链接:http://www.w3school.com.cn/tiy/t.asp?f=csse_cursor

(以上内容均来自w3school,网址:http://www.w3school.com.cn/css/pr_class_cursor.asp

有了这些就好办多了,lufylegend中有MOUSE_MOVE事件,它是用来判断鼠标是否盘旋在某对象上。用这个事件很显然能做出这个效果,但是出现了一个问题,那就是不能判断鼠标是否在对象之外,换句话说,就是不能把鼠标转换为正常样式。因此,我们就只能自己来做这个事件了。

由于我初略得研究过lufylegend这个引擎,所以了解了LEvent这个类。因此我先用它给整个canvas加一个鼠标移动事件,在LLink构造器中加入代码如下:

LEvent.addEventListener(LGlobal.object,LMouseEvent.MOUSE_MOVE,LStage._addLinkEvent);

由于我们不能直接给对象加入事件,因此取不出对象当前的位置,从而无法判断鼠标是否盘旋在某对象上面。为了解决这个问题,我建立一个列表,把所有的LLink对象都加进去。代码如下:

LStage._linkList = new Array();

给列表添加对象的代码要写到LLink构造器中,如下:

LStage._linkList.push(self);

因为我们加的canvas事件触发LStage._addLinkEvent这个函数,所以把LStage._addLinkEvent代码展示如下:

LStage._addLinkEvent = function(event){ 
	for(var i in LStage._linkList){
		o = LStage._linkList[i];
		if(event.offsetX < parseInt(o.x) + parseInt(o.getWidth()) && event.offsetY < parseInt(o.y) + parseInt(o.getHeight()) + parseInt(Math.floor(o.text.size * 0.4)) && event.offsetX > parseInt(o.x) && event.offsetY > parseInt(o.y)){
			document.body.style.cursor = "pointer";
			return;
		}else{
			document.body.style.cursor = "default";
		}
	}
}

这个代码也不难理解,就是遍历一下上面定义的列表,判断鼠标的位置是否在遍历到的对象上,如果在上面,就更改鼠标样式为一只手,如果不在就改回来。

但是给canvas加事件应该只用加一次,所以我们判断一下是否已经加入,如果是就不再加了,不是的话就继续,说白了就是个判断,因此加一个属性:

LStage._isAddLinkEvent = false;

然后给加事件的地方加一个判断就行了,LLink构造器最后的完整代码如下:

function LLink(url,text,type,color,font,size){
	var self = this;
	base(self,LSprite,[]);
	
	self.type = "LLink";
	self.url = url;
	self.openType = type || "blank";
	
	self.x = 0;
	self.y = 0;
	
	self.text = new LTextField();
	self.text.color = color || "blue";
	self.text.font = font || "urf-8";
	self.text.size = size || 12;
	self.text.x = 0;
	self.text.y = 0;
	self.text.text = text || url;
	self.addChild(self.text);
	
	self.underLine = new LSprite();
	self.underLine.graphics.drawRect(0,self.text.color,[0,0,self.text.getWidth(),Math.floor(self.text.size * 0.1)],true,self.text.color);
	self.underLine.x = 0;
	self.underLine.y = parseInt(self.text.getHeight()) + Math.floor(self.text.size * 0.3);
	self.addChild(self.underLine);
	
	self.back = new LSprite();
	self.back.graphics.drawRect(0,"transparent",[0,0,self.text.getWidth(),self.text.getHeight()],true,"transparent");
	self.addChild(self.back);
	
	LStage._linkList.push(self);
	
	self.addEventListener(LMouseEvent.MOUSE_DOWN,self._jump);
	
	if(LStage._isAddLinkEvent == false){
		LEvent.addEventListener(LGlobal.object,LMouseEvent.MOUSE_MOVE,LStage._addLinkEvent);
		LStage._isAddLinkEvent = true;
	}
}

本次开发所有的代码如下,要用的朋友尽管拿去用,代码也不多,完全免费:

/**
*LLink.js
*/
LStage._linkList = new Array();
LStage._isAddLinkEvent = false;
LStage._addLinkEvent = function(event){
	for(var i in LStage._linkList){
		o = LStage._linkList[i];
		if(event.offsetX < parseInt(o.x) + parseInt(o.getWidth()) && event.offsetY < parseInt(o.y) + parseInt(o.getHeight()) + parseInt(Math.floor(o.text.size * 0.4)) && event.offsetX > parseInt(o.x) && event.offsetY > parseInt(o.y)){
			document.body.style.cursor = "pointer";
			return;
		}else{
			document.body.style.cursor = "default";
		}
	}
}
function LLink(url,text,type,color,font,size){
	var self = this;
	base(self,LSprite,[]);
	
	self.type = "LLink";
	self.url = url;
	self.openType = type || "blank";
	
	self.x = 0;
	self.y = 0;
	
	self.text = new LTextField();
	self.text.color = color || "blue";
	self.text.font = font || "urf-8";
	self.text.size = size || 12;
	self.text.x = 0;
	self.text.y = 0;
	self.text.text = text || url;
	self.addChild(self.text);
	
	self.underLine = new LSprite();
	self.underLine.graphics.drawRect(0,self.text.color,[0,0,self.text.getWidth(),Math.floor(self.text.size * 0.1)],true,self.text.color);
	self.underLine.x = 0;
	self.underLine.y = parseInt(self.text.getHeight()) + Math.floor(self.text.size * 0.3);
	self.addChild(self.underLine);
	
	self.back = new LSprite();
	self.back.graphics.drawRect(0,"transparent",[0,0,self.text.getWidth(),self.text.getHeight()],true,"transparent");
	self.addChild(self.back);
	
	LStage._linkList.push(self);
	
	self.addEventListener(LMouseEvent.MOUSE_DOWN,self._jump);
	
	if(LStage._isAddLinkEvent == false){
		LEvent.addEventListener(LGlobal.object,LMouseEvent.MOUSE_MOVE,LStage._addLinkEvent);
		LStage._isAddLinkEvent = true;
	}
}
LLink.prototype._jump = function(event,self){
	var openType = "_" + self.openType;
	window.open(self.url, openType);
}

要写的时候就直接这样写:

var link = new LLink("http://lufylegend.com","链接测试");
addChild(link);

Over,是不是很简单?

最后奉上演示地址:http://www.cnblogs.com/yorhom/articles/3227576.html
截图如下:

HTML5 Canvas中实现文字链接

点击链接后跳转网页:

HTML5 Canvas中实现文字链接

—————————————————————-

欢迎大家转载我的文章。

转载请注明:转自Yorhom’s Game Box

http://blog.csdn.net/yorhomwang

欢迎继续关注我的博客

分类: 未分类 标签:

Cocos2D & ccDrawLine – Drawing smooth lines

2013年7月28日 没有评论

I have some troubles when I try to draw lines with cocos2d! I store points, got from touchMoved method, in a NSMutableArray, and pass that array to a subclass of CCNode called Lines that I use to draw the lines from the array of points. The problem is that the line is not smooth when I swipe slowly, but when I swipe faster, the line is way much smoother. See the pictures below :

Slow Swipe :
Cocos2D &amp; ccDrawLine - Drawing smooth lines

Fast Swipe :
Cocos2D &amp; ccDrawLine - Drawing smooth lines

I tried to solve the problem with ccpDistance, which calculate the distance between the last saved point and if it’s not far enough I don’t save it. I also tried to draw little circles at each saved positions, but this isn’t really nice neither. Here’s my code :

In my GameScene :

- (void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
    CGPoint location = [touch locationInView:[touch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];

    if (ccpDistance(lastPoint, location) > 10) {
        //SAVE THE POINT
        [linePoints addObject:[NSValue valueWithCGPoint:location]];

        [line updatePoints:linePoints];

        lastPoint = location;
    }
}

And my Line Class :

- (void) updatePoints:(NSMutableArray *)_point
{
    points = _point;
}

- (void) draw
{
    if ([points count] > 0) {
        ccGLEnable(GL_LINE_STRIP);

        ccDrawColor4B(209, 75, 75, 255);

        float lineWidth = 6.0 * CC_CONTENT_SCALE_FACTOR();

        glLineWidth(lineWidth);

        int count = [points count];

        for (int i = 0; i < (count - 1); i++){
            CGPoint pos1 = [[points objectAtIndex:i] CGPointValue];
            CGPoint pos2 = [[points objectAtIndex:i+1] CGPointValue];

            ccDrawLine(pos1, pos2);
            ccDrawSolidCircle(pos2, 2.5, 20);
        }
    }
}

Also, is there something in my code that could be done better to improve performance? Right now I don’t have any problems even with 1000+ points, but just in case…

Any help will be greatly appreciated! Thanks in advance!

Ok, I found a website explaining really clearly how to do smooth lines, and it worked wonderfully! There’s still anti-aliasing that’s left to do, but maybe I will never do, since it looks really great on retina devices. Here’s the website : Drawing Smooth Lines with Cocos2D

And here’s the result :
Cocos2D &amp; ccDrawLine - Drawing smooth lines

Also, for those interested in the finished code, here it is :

Line.m

- (void) drawCurPoint:(CGPoint)curPoint PrevPoint:(CGPoint)prevPoint
{
    float lineWidth = 6.0;
    ccColor4F red = ccc4f(209.0/255.0, 75.0/255.0, 75.0/255.0, 1.0);

    //These lines will calculate 4 new points, depending on the width of the line and the saved points
    CGPoint dir = ccpSub(curPoint, prevPoint);
    CGPoint perpendicular = ccpNormalize(ccpPerp(dir));
    CGPoint A = ccpAdd(prevPoint, ccpMult(perpendicular, lineWidth / 2));
    CGPoint B = ccpSub(prevPoint, ccpMult(perpendicular, lineWidth / 2));
    CGPoint C = ccpAdd(curPoint, ccpMult(perpendicular, lineWidth / 2));
    CGPoint D = ccpSub(curPoint, ccpMult(perpendicular, lineWidth / 2));

    CGPoint poly[4] = {A, C, D, B};

    //Then draw the poly, and a circle at the curPoint to get smooth corners
    ccDrawSolidPoly(poly, 4, red);
    ccDrawSolidCircle(curPoint, lineWidth/2.0, 20);
}

- (void) draw
{
    if ([points count] > 0) {
        ccGLEnable(GL_LINE_STRIP);

        ccColor4F red = ccc4f(209.0/255.0, 75.0/255.0, 75.0/255.0, 1.0);
        ccDrawColor4F(red.r, red.g, red.b, red.a);

        float lineWidth = 6.0 * CC_CONTENT_SCALE_FACTOR();

        glLineWidth(lineWidth);

        int count = [points count];

        for (int i = 0; i < (count - 1); i++){
            CGPoint pos1 = [[points objectAtIndex:i] CGPointValue];
            CGPoint pos2 = [[points objectAtIndex:i+1] CGPointValue];

            [self drawCurPoint:pos2 PrevPoint:pos1];
        }
    }
}

As for the GameScene, nothing changed there (See the question for the code)! Note that you can change the line if (ccpDistance(lastPoint, location) > X), where X is the minimum distance between two points before the game saves another one. The lower X is, the smoother the line will be, but you will have way more points in your array, which could affect performance!

Anyway, thank you guys for your suggestions and your help, it helped me to get in the right way!

I think that you could smooth up your line drawing with some averaging.

- (void) updatePoints:(NSMutableArray *)_point
{
    points = _point;
    int count = [points count];
    for (int i = 3; i < (count - 4); i++) {
        CGPoint pos1 = [[points objectAtIndex:i - 2] CGPointValue];
        CGPoint pos2 = [[points objectAtIndex:i - 1] CGPointValue];
        CGPoint pos3 = [[points objectAtIndex:i] CGPointValue];
        CGPoint pos4 = [[points objectAtIndex:i + 1] CGPointValue];
        CGPoint pos5 = [[points objectAtIndex:i + 2] CGPointValue];
        CGFloat xpos = (pos1.x + pos2.x + 2 * pos3.x + pos4.x + pos5.x)/6;

        ...
        (now calcuclate ypos similarly and store the point into an array)
    }
}
分类: cocos2d, stackoverflow精选 标签:

新游戏《真·方块无双》发布-穿越混世过险境,运筹方块化无双

2013年7月26日 没有评论

发布新游戏:真·方块无双(Shin Block Musou)

新游戏《真&#183;方块无双》发布-穿越混世过险境,运筹方块化无双

一,关于游戏


1,介绍

这是一款益智类小游戏,通过点击屏幕使方块跳起从而躲过迎面而来的障碍物。游戏中设置了保存最高纪录的功能,看看自己能否超越自我,挑战极限。

至于游戏名称为什么叫《真方块无双》,我想大概是因为玩了半个月《真三国无双》的原因吧,一时灵感一现就想到了这个名称。哈哈(也不知道Koei会不会因为模仿他的品牌而罚我的款)

2,游戏引擎

本游戏是利用lufylegend 1.7.7制作而成的。lufylegend是一个开源的html5游戏引擎,它模仿了ActionScript 3.0的语法,利用它可以非常方便地进行游戏开发。具体介绍可以去官方网站了解一下。

引擎官方网站:

http://lufylegend.com/lufylegend

API文档:

http://lufylegend.com/lufylegend/api

3,作者的话

创作本游戏的灵感来源于Scratch网站上的一个项目,作者是trueGamez。素材也取自本项目,在此对trueGamez表示感谢,另外,在下也对所有支持我的人表示感谢。以后游戏更新会加入道具之类的功能,敬请期待。

二,怎样才能玩


1,网页版

http://www.lufylegend.com/lufylegend_developers/yorhom_Block_Jumper/index.html

2,智能手机android版

http://files.cnblogs.com/yorhom/ShinBlockMusou.apk

3,PC版(含源代码和素材)

http://files.cnblogs.com/yorhom/Block_Jumper.rar

三,游戏截图

新游戏《真&#183;方块无双》发布-穿越混世过险境,运筹方块化无双

新游戏《真&#183;方块无双》发布-穿越混世过险境,运筹方块化无双

新游戏《真&#183;方块无双》发布-穿越混世过险境,运筹方块化无双

新游戏《真&#183;方块无双》发布-穿越混世过险境,运筹方块化无双

新游戏《真&#183;方块无双》发布-穿越混世过险境,运筹方块化无双

如果游戏有bug,欢迎大家将问题发到本文下方,或者通过邮箱告诉我,邮箱地址:wangyuehao1999@gmail.com


最后,在下为本游戏赋诗一首,文辞稍有不适之处,请多加包涵:

玄机星罗暗魂,陷阱棋布骇人神。

穿越混世过险境,运筹方块化无双。

—————————————————————-

欢迎大家转载我的文章。

转载请注明:转自Yorhom’s Game Box

http://blog.csdn.net/yorhomwang

欢迎继续关注我的博客

分类: 未分类 标签:

Cocos2d blur with shaders

2013年7月25日 没有评论

Currently I am toying with Cocos2D. I want to be able to blur the entire scene when there is a notification overlay displaying.

I thought I could do this with shaders (I am quite an OpenGL noob). From what I found is that there are “fsh” files which contain an algoritm for the shader. I found one for “gausian blurring” but how can I add such a shader to an CCScene of Cocos2D?

I can’t seem to figure this out.

I have just started to play a little bit with shaders myself. There’s a lot of material on the web to read and try out. I’ll point you in the direction of some urls I found useful to get to understand how/what they do.. that might get you started.

Simple tutorial to achieve a greyscale effect with shaders (Cocos2D)

http://www.shaderdev.com/2013/09/16/full-scene-shader-effects-how-to-create-a-grayscale-pause-screen-using-ccrendertexture/

Coding experiments blogpost: great looking shader effect. This is the shader I share for cocos2D below…

http://coding-experiments.blogspot.com/2010/06/frosted-glass.html

With those you are surely on your way. Feel free to use the shaders below too if you find them useful, these were taken from the second url.

vertex shader

attribute vec4 a_position;
attirbute vec4 a_color;
attribute vec2 a_texCoord;

uniform mat4 u_MVPMatrix;
varying lowp vec2 v_fragmentColor;
varying lowp vec2 v_texCoord;

void main()
{
    gl_Position = CC_MVPMatrix * a_position;
    v_fragmentColor = a_color;
    v_texCoord = a_texCoord;
}

fragment shader

varying lowp vec4 v_fragmentColor;
varying lowp vec2 v_texCoord;
uniform sampler2D u_texture;

float rand(vec2 co)
{
    return fract(sin(dot(co.xy ,vec2(92.,80.))) +
                 cos(dot(co.xy ,vec2(41.,62.))) * 5.1);
}

void main()
{
    vec2 rnd = vec2(0.0);
    rnd = vec2(rand(v_texCoord),rand(v_texCoord));
    glFragColor = texture2D(u_texture, v_texCoord+rnd*0.05);
}
分类: stackoverflow精选, unity3d 标签:

子类化CCNode,扩展一个多功能的对象

2013年7月24日 没有评论

1、起因

   学过了面向对象的编程,就不可避免的以对象的角度来思考程序结构。

  牛皮少吹,说点实际的。

2.基类

  首先,先来说一下cocos2d-x的程序类结构。

  基本所有的元素都是CCNode的子类。比如CCSprite、CCMenu、CCLayer等。只是相应关注的功能点不一样。

  我们通常需要的是一个复合的对象。

  比如:塔防游戏。怪物头上都要有血条。这个东西是跟着怪物走的。显然应该在一个对象中。血条显示的是血量,这个数值自然是一个成员变量会比较好。但是如果我写成

Class MySprite : public CCSprite
{
    ......
}

会有问题。首先,血条与怪物明显是逻辑上的两个东西,另外,如果需要对其操作或向其中加入其它效果元素,事情将变得更难以管理。所以倒不妨直接采用基类CCNode:

Class MySprite : public CCNode
{
    ......
}

3、初始化

   确定了基类,就可以开始着手写了。我可以添加一个CCSprite作怪物,一个CCControlSlider作它的血槽显示。

这两个东西都用addChild加到MySprite中,此时可以把MySprite理解为一个CCLayer。所以这个类看起来应该是这样的:

Class MySprite:public CCNode
{
  public:
    CREATE_FUNC(MySprite);
    virtual bool init();


}

然后在init中添加相应的功能就行了。

bool MySprite::init()
{
    //add Sprite
    .......
    //add BloodBar
    ......
}

    使用时 MySprite* sp = MySprite::create(); 这样的操作就可以创建一个新的复合对象了。

4、参数

    一切都非常好,但是有点小瑕疵。现在想创建不同的怪兽,它们的血值是不一样的。能不能通过参数来进行配置呢?当然可以,这是我们自己的类,我们能控制一切。
    在初始化时传入参数,是一个不错的选择。所以初始化函数调用应该是这个样子:
MySprite* sp = MySprite::create(100);

     这样我就把怪物的血量100传进去了。好,就按这个思路写一个构造函数,写法就参照create好了。

   先在.h文件中加入一个构造函数声明:
Class MySprite:public CCNode
{
  public:
    CREATE_FUNC(MySprite); 
    virtual bool init();
    static MySprite* create(int hp);
  protect:
    int m_hp;
}

    无参数的构造函数留不留看你需要了。如果你希望安全一些就彻底按照cocos2d-x的create方式来做,这也是推荐的写法。如果你觉得没必要的话只需在这个create中添加处理代码就行了。

    更好的做法是在create中调用init,在init中添加处理:

Class MySprite:public CCNode
{
  public:
    CREATE_FUNC(MySprite);
    virtual bool init();

    static MySprite* create(int hp);
    virtual bool initMySprite(int hp);
  protect:
    int m_hp;
}

   其实现与CREATE_FUNC宏类似:

MySprite* MySprite::create( int hp )
{
	MySprite*pRet = new MySprite(); 
	if (pRet && pRet->initMySprite(hp)) 
	{ 
		pRet->autorelease(); 
		return pRet; 
	} 
	else 
	{ 
		delete pRet; 
		pRet = NULL; 
		return NULL; 
	}
}

bool MySprite::initMySprite(int hp)
{
    //save hp
    ......
    //add sprite
    ......
    //add BloodBar
    ......
}

    经过这些步骤,我们就可以通过参数来控制这个类的行为了。

5、总结

    总结一下,如果想自己定制一个元素集合体,大体分以下步骤:
    1、挑选基类。选择合适功能的基类,如果选择起来有难度,就选择CCNode。
    2、编写默认初始化:create()。尽量使用create作为初始化函数,使编码风格保持一致。
    3、编写特例初始化:create(…)。通过参数来控制类的行为。


本篇博客出自阿修罗道,转载请注明出处:http://blog.csdn.net/fansongy/article/details/9455307


分类: 未分类 标签:

cocos2d-x 实现clash of clans多点聚焦缩放场景

2013年7月18日 没有评论

猴子原创,欢迎转载。转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢!
原文地址: http://www.cocos2dev.com/?p=434

都是以前写的一些效果,整理了下,传到了git上面。博客里面都有过讲解。

cocos2d-x 实现clash of clans多点聚焦缩放场景

cocos2d-x 实现clash of clans多点聚焦缩放场景


https://github.com/sunny-liu/cocos2dx-extensions.git

分类: 未分类 标签:

2D Cross-Platform Game Development Engines [closed]

2013年7月11日 没有评论

I’ve worked for some time with Corona SDK and love how fast and easy I can create powerful apps using Lua. But it can only compile for iOS and Android, which feels like too little now.

My main interest is for it to be able to compile to Desktop AND Mobile. At least for the following:

  • Windows + Mac for desktop, as standalone applications.
  • iOS + Android for mobile.

I’d prefer it to lean more towards Lua type scripting instead of ActionScript, but please feel free to post anything that you have worked with and love.

I’ve found the following engines so far:

  • Marmalade Quick – After further looking into it, Marmalade Quick can only build for Mobile!
  • IwGame – Works on top of marmalade and says it can deploy to
    desktop and mobile with Lua. Any info is greatly appreciated on this
  • sio2 – Says “SIO2 is an OpenGLES based cross-platform 2D and 3D
    game engine for iOS, Android, MacOS and Windows” and “The engine also
    allows you to port your game on the Mac Store and on Windows.”, but
    their forum and web title is “Game Engine for Mobile Devices”. Can’t
    find any info on if it can deploy to desktop platforms, any info is
    greatly appreciated again.
  • Loom Engine – Loom is similar to Haxe + OpenFL (attempts to attract Flash developers) in that it uses AS3-like of ECMAScript, but it doesn’t build native code from it. However it uses Cocos2D for rendering so it should in theory be as fast as Cocos2D. — Thanks to Bojan.
  • SDL – I’ve read in multiple places that SDL can deploy to nearly any platform or device and has a Lua binding. But i can’t find how this works as it’s not an engine. Any one who can explain how it works and if it’s possible is once again, very much appreciated.
  • SFML – “Windows, Linux, Mac OS X and soon Android & iOS. ” doesn’t use Lua but can use other languages like Java and Python etc. Anyone have any information on this?
  • Torgue2D – “Torque 2D was developed with OS X, Windows, and iOS devices in mind and works equally well on all the platforms.” uses TorgueScript and no Android =(
  • Sencha – Seems to compile to all platforms, uses Javascript too which I know. But even with V8 JS would this work well performance wise compared to other options?
  • GameMaker – own scripting language GML and I actually remember this one as a tool for non-programmers. Has it actually grown into a real engine, I mean for serious development?
  • Construct2 – Same question as gamemaker
  • Corona – Lua but mobile only (Android and iOS only as well)
  • Cocos2D – Seems like it has lots of options but not sure with the same language? Seems like you’d have to re-write your entire code. Any info if cocos2D can deploy to desktop + mobile with almost the same code would be greatly appreciated.
  • Angel2D – Says it can deploy to everything except Android and uses Lua, anyone ever used this one before?
  • libgdx — I’ve only seen good things about this. Here is a benchmark test for libgdx and is where I saw it reaching 40k sprites at 60fps. http://www.sparkrift.com/2012/1/love2d-vs-allegro-vs-clanlib-vs-libgdx-vs-cocos2d-x-vs-monogame-vs-xna-vs-sfml . It seems libgdx barely goes over 30k actually. But still seems amazing. This is on the same level as Qt for me, almost perfect, except I’m not really worried about performance on it. libgdx can build for everything pretty much.
  • XNA + MonoGame — MonoGame’s performance seems only slightly lower than libgdx, can build to most platforms. However I don’t know much about XNA and I heard it won’t be receiving future updates, but is quite stable? More information is welcome.
  • Citrus — Don’t have much information on Citrus either. AS3 game engine that can build for iOS, Android, Windows, Mac and more.
  • Haxe + OpenFL — OpenFL (Haxe) builds to native on many platforms, not just to Flash. Windows, Mac, Linux and Android all get optional native deployment or OpenFL runtime called Neko which is in theory faster than Flash, and SDL 2.0 will enable iOS deployment soon(ish). — Thanks to Bojan.
  • Qt-Project — Just linking Qt project here, can build for everything and has a pretty big community with lots of third party libraries to help you even further.
  • Moai —The only Lua engine that I know that can build for Desktop and Mobile. Only downside is the community isn’t that big and documentation isn’t the best. But if you can get passed those this is a great solution and the one I’m currently using.
  • Adobe — Can’t forget to add adobe here since it can build to everything that supports flash.
  • Unity3D — Recently announced 2D integration looks very promising, should be released Q3-Q4 of 2013.
  • Cocos2d-x — An open source engine. Supports JS, Lua, C++ and multiple platforms.
  • Html5 — There seem to be a lot of emphasise on html5 mobile apps, here are just a few tools I found that can help port your html5 project to a platform:

    1. Chromium embedded

    2. Sencha

    3. Phonegap

    4. Appcelerator/Titanium

    5. Icenium

So, I’d be happy if you could comment from your experiences with any engines and suggest which one you would recommend.
Thank you for your help!

EDIT: Since this topic is getting popular I’ll be adding other options I’ve found over time. I suggest you choose what is most familiar to you and best for your project needs.

I would recommend V-Play (v-play.net) – it’s a cross-platform game engine based on Qt for iOS, Android, Symbian, MeeGo, Blackberry10 and also can export for native desktop applications for Windows, Mac and Linux.

It’s based on C++ but has a neat scripting support for QML & JavaScript. QML is a no-brainer to learn and can boost your productivity as less code is needed – just see the comparison with cocos2d-x(60% less Loc) or Corona(15% less LoC) for a comparison of the same games.

(Disclaimer: I’m one of the guys behind V-Play)

No mention of App Game Kit (AGK) here so let me fill in the gap. It’s a mainly 2D cross platform SDK allowing you to code once in either C++ or it’s own “Basic” language. Version 2 just got over 400% funding on Kickstarter and will have full 3D support, Spine support (for 2D animated characters), bullet physics and whole bunch of other new features.

It already has Facebook, Twitter, a bunch of Ultrabook sensor commands, Box2D and more. I’ve been using it from the start and love it (can you tell?). No, I don’t work for The Game Creators (the company that created it) although I admit I did do for a while making some apps.

One of the best features from my point of view is you can develop on Windows and broadcast from the IDE over Wi-Fi to any supported device, so while I’m coding I can (within seconds) test my code on iPad, Android, Windows, Mac or Blackberry Playbook.

If you have C# background. Have a look at Duality.

Duality is a flexible 2D game framework written entirely in C# –
and it’s here to make things a little easier for you. It provides both
an extensible game engine and a visual editor to match. There will be
no need for a level editor, testing environment or content manager
because Duality is all that by itself. And best of all: It’s free.

Here is my game framework Oxygine.
It is open source modern hardware accelerated 2D C++ framework for mobile and PC platforms.
Features: OpenGL(ES) 2, compressed textures, atlases, complex animations/tweens/sprites, scene graph, fonts, event handling, build tools, and others.
Can be built on top of SDL2 or Marmalade SDK.

In the basis of the engine there is a scene graph, that is similar to Flash one. To be short, You can call this as Flash for C++, but more comfortable and way faster. Initially it was developed for mobile platforms (iOS, Android), but can be also used for PC games.

2D Cross-Platform Game Development Engines [closed]

I’m just answering to give you some insights on how the SDL is used. As you said before it’s not a game engine (it’s just a library actually). Furthermore, it is not object oriented at all and you don’t have some easy animation facilities (you have to code them by yourself).

How it works (I used the C version but I guess the Lua binding should be similar):

Include the headers needed to build the project on the platform you want.

Design your own game loop in which you will set up (at least) a whole event processing system, frame rate manager and a “screen cleaner (or updater)” (I’m insisting on the fact that you have to manually refresh your screen using the SDL_flip_screen routine which is something that is not one of your concerns at all with Corona).

Then, code your game using all the “mechanics” you made before.

The SDL is a low level library (don’t expect to have an easy to use GUI framework or the storyboard framework of Corona for instance).

Finally, this library was used to port Civilization III to Linux, so yes it works but it will ask you a lot of energy to have something like you had with Corona ;)

PS: I am not a native English speaker, so please let me know if I wasn’t clear :)

How about HaxeFlixel? We have a great selection of demos, and of course support cross platform development via Haxe + OpenFL. This is an open source project hosted on github. We support all major platforms (including iOS).

If you are into using Python, Kivy is a great solution these days. It compiles to all the platforms you ask for:

Kivy is running on Linux, Windows, MacOSX, Android and IOS. You can
run the same code on all supported platforms. It can use natively most
inputs protocols and devices like WM_Touch, WM_Pen, Mac OS X Trackpad
and Magic Mouse, Mtdev, Linux Kernel HID, TUIO. A multi-touch mouse
simulator is included.

Kivy uses lots of optimized code for graphics rendering (via Cython) so it is fast too.

Here is a speakerdeck that gives you some background and an overview (android specific).

You also have ShiVa3D, a serious competitor of Unity3D.
It uses Lua and supports many platforms from mobile to game consoles and web browsers.

Very intuitive to use and very nice UI to work with.

Gideros is a great Lua based 2d cross platforms engine, currently supporting both Android and IOS platforms, but more to come.
And it also has some great features as instant on device testing, auto scaling and auto image resolution to easily target various of screen sizes, as well as the option to extend each platform through native plugins.

分类: cocos2d, stackoverflow精选 标签:

不再依赖A*,利用C++编写全新寻路算法

2013年7月2日 没有评论

一,说在前面的话

大概在半年前,看见一到信息竞赛题:在任意方格阵中设置障碍物,确定起始点后,求这两点之间路径。当时觉得蛮有意思的,但是没有时间去做,今天花了两个小时来实现它。据说有一个更高级的寻路算法叫做a*, 那我就把我的算法叫做W*。

这个算法主要用于解迷宫和实现战棋游戏(SLG)的寻路。

首先讲一讲我的算法的思路:
我们先确定起始点,然后从起点出发,按一定顺序判断这个位置上下左右是否有可走的位置,如果发现有可走的位置,则递归进入该位置的判断。在递归的同时记录所走的路线。当发现某个位置无路可走,则删除路线的最后一个位置并返回上级位置进行判断。如此反复尝试最终找到路线。

说了这么多,就来讲解一下代码吧。

二,讲解部分

包含头文件(全部都是stl中的):

#include <map>
#include <vector>
#include <iostream>

为几个冗长的类型重命名,用来使后来的代码更明了。

typedef		unsigned int				uint;
typedef		std::vector<int>			CRow;
//相当于把CLabyrinth定义成一个整型的二维数组
typedef		std::vector<CRow>			CLabyrinth;

定义一个类类型表示二维数组中的位置:

class CPoint
{

public:

	int	col;			//列
	int	row;			//行

public:

	//构造函数,接受行和列的初始化
	CPoint(int c = 0, int r = 0)
		: col(c)
		, row(r)
	{
		return;
	}

	//赋值操作
	CPoint& operator=(const CPoint& pt)
	{
		col = pt.col;
		row = pt.row;
		return *this;
	}

	//比较操作
	bool operator==(const CPoint& pt)
	{
		return col == pt.col && row == pt.row;
	}

	//判断该位置是否合法
	bool allRight()
	{
		return col >= 0 && row >= 0;
	}

};

typedef		std::vector<CPoint>			CRoute;

然后到了核心类类型CLabyrinthAI

{

protected:

	//装有迷宫数据的二维数组
	CLabyrinth		m_xLabyrinth;
	//起点位置
	CPoint			m_ptBeginning;
	//终点位置
	CPoint			m_ptEnding;
	//记录路线的数组
	CRoute			m_vRoute;

public:

	//枚举表示起点、终点的值
	enum{Beginning = -1, Ending = -2};
	//枚举表示障碍物与可走区的值
	enum{CanntGo = 0, CanGo = 1};
	//枚举是否找到终点
	enum{FoundEnding = 0, NotFoundEnding = 1};

protected:

	//判断某个位置是否已在路线数组中,用于别走重复的路
	bool isRepeat(const CPoint& pt)
	{
		bool bRes = false;
		CRoute::iterator it = m_vRoute.begin();
		for(; it != m_vRoute.end(); it++){
			CPoint pt0 = *it;
			if(pt0 == pt){
				bRes = true;
				break;
			}
		}
		return bRes;
	}

	//将某一位置加入路线数组
	void advance(const CPoint& ptTo)
	{
		m_vRoute.push_back(ptTo);
	}

	//将路线数组最后一个位置弹出
	void back()
	{
		m_vRoute.pop_back();
	}

	//判断某一位置是否是起点
	bool isBeginning(const CPoint& pt)
	{
		return m_ptBeginning == pt;
	}

	//判断某一位置是否是终点
	bool isEnding(const CPoint& pt)
	{
		return m_ptEnding == pt;
	}

/*-----------------核心算法------------------------*/
	//判断某一位置是否可以向上移动
	CPoint canUp(const CPoint& ptCurrent)	//接受当前位置
	{
		CPoint ptRes = CPoint(-1, -1);
		int col = ptCurrent.col;
		int row = ptCurrent.row;
		if(row > 0){
			CPoint ptNext = CPoint(col, row - 1);	//上移后位置
			//检查上移后位置是否已经走过,以免寻路过程中绕圈子进入死循环
			if(!isRepeat(ptNext)){
				//获得迷宫二维数组中上移后位置的属性(起点、终点、可走、障碍)
				int nAttr = m_xLabyrinth[ptNext.row][ptNext.col];
				//如果上移后位置为可走或到达终点,则设定返回值为上移后的位置
				if(nAttr == CanGo || nAttr == Ending){
					ptRes = ptNext;
				}
			}
		}
		return ptRes;	//如果上移后位置不可走则返回非法的位置
	}

	//以下判断某一位置可否移动的原理大致与上相同,就不多说了

	//判断某一位置是否可以向下移动
	CPoint canDown(const CPoint& ptCurrent)
	{
		CPoint ptRes = CPoint(-1, -1);
		int col = ptCurrent.col;
		int row = ptCurrent.row;
		if(row < m_xLabyrinth.size() - 1){
			CPoint ptNext = CPoint(col, row + 1);
			if(!isRepeat(ptNext)){
				int nAttr = m_xLabyrinth[ptNext.row][ptNext.col];
				if(nAttr == CanGo || nAttr == Ending){
					ptRes = ptNext;
				}
			}
		}
		return ptRes;
	}

	//判断某一位置是否可以向左移动
	CPoint canLeft(const CPoint& ptCurrent)
	{
		CPoint ptRes = CPoint(-1, -1);
		int col = ptCurrent.col;
		int row = ptCurrent.row;
		if(col > 0){
			CPoint ptNext = CPoint(col - 1, row);
			if(!isRepeat(ptNext)){
				int nAttr = m_xLabyrinth[ptNext.row][ptNext.col];
				if(nAttr == CanGo || nAttr == Ending){
					ptRes = ptNext;
				}
			}
		}
		return ptRes;
	}

	//判断某一位置是否可以向右移动
	CPoint canRight(const CPoint& ptCurrent)
	{
		CPoint ptRes = CPoint(-1, -1);
		int col = ptCurrent.col;
		int row = ptCurrent.row;
		if(col < m_xLabyrinth[0].size() - 1){
			CPoint ptNext = CPoint(col + 1, row);
			if(!isRepeat(ptNext)){
				int nAttr = m_xLabyrinth[ptNext.row][ptNext.col];
				if(nAttr == CanGo || nAttr == Ending){
					ptRes = ptNext;
				}
			}
		}
		return ptRes;
	}

/*
*判断某一位置是否可以向四周移动,如果判断到某一位置可以移动,则递归进入该位置判断。
*如果该位置没有任何位置可移动,则返会上级位置并且调用back函数。如果走到终点,
*则立刻返回枚举值FoundEnding,上级位置检查到返回值为FoundEnding,也直接返回。
*/
	int findRoute(const CPoint& ptCurrent)
	{
		int nRes = NotFoundEnding;		//默认返回值为没有找到终点
		CPoint ptNext = CPoint(-1, -1);

		advance(ptCurrent);			//将当前位置加入路线数组

		//判断当前位置是否是终点,如果是终点则不进行下面的判断,将返回值设置为找到终点
		if(isEnding(ptCurrent)){
			nRes = FoundEnding;
		}else{					//按上左下右的顺序判断有无可走路径
			//尝试向上
			ptNext = canUp(ptCurrent);	//获取向上走后的位置
			//判断向上走后的位置是否是合法位置,若不合法,则表明上走到了迷宫的边缘,或者上面没有可走路径
			if(ptNext.allRight()){
				//上述判断成功,则将向上移动后的位置传入给自己,进行递归。当该函数退出,查看返回值是否为找到终点。若找到终点则立刻返回FoundEnding
				if(findRoute(ptNext) == FoundEnding){
					nRes = FoundEnding;
					return nRes;
				}
			}
//下列尝试四周位置是否可走的代码与上述大体相同,就不多说了
			//尝试向左
			ptNext = canLeft(ptCurrent);
			if(ptNext.allRight()){
				if(findRoute(ptNext) == FoundEnding){
					nRes = FoundEnding;
					return nRes;
				}
			}
			//尝试向下
			ptNext = canDown(ptCurrent);
			if(ptNext.allRight()){
				if(findRoute(ptNext) == FoundEnding){
					nRes = FoundEnding;
					return nRes;
				}
			}
			//尝试向右
			ptNext = canRight(ptCurrent);
			if(ptNext.allRight()){
				if(findRoute(ptNext) == FoundEnding){
					nRes = FoundEnding;
					return nRes;
				}
			}
		}

		//检测是否到达终点,若没有到达终点,则立刻从路线表中删除该位置
		if(nRes != FoundEnding){
			back();
		}

		return nRes;
	}
/*-----------------核心算法------------------------*/

public:

	//构造函数
	CLabyrinthAI()
	{
		return;
	}

	//带有初始化迷宫数组构造函数
	CLabyrinthAI(const CLabyrinth& vLabyrinth)
	{
		m_xLabyrinth = vLabyrinth;
		getBeginning();
		getEnding();
	}

	//初始化迷宫数组
	void setLabyrinth(const CLabyrinth& vLabyrinth)
	{
		m_xLabyrinth = vLabyrinth;
	}

	//查找起点
	void getBeginning()
	{
		uint nRow = 0;
		for(; nRow < m_xLabyrinth.size(); nRow++){
			CRow xRow = m_xLabyrinth[nRow];
			uint nCol = 0;
			for(; nCol < xRow.size(); nCol++){
				int n = xRow[nCol];
				if(n == Beginning){
					m_ptBeginning = CPoint(nCol, nRow);
					break;
				}
			}
		}
	}

	//查找终点
	void getEnding()
	{
		uint nRow = 0;
		for(; nRow < m_xLabyrinth.size(); nRow++){
			CRow xRow = m_xLabyrinth[nRow];
			uint nCol = 0;
			for(; nCol < xRow.size(); nCol++){
				int n = xRow[nCol];
				if(n == Ending){
					m_ptEnding = CPoint(nCol, nRow);
					break;
				}
			}
		}
	}

	//调用核心算法函数,输出获得的路线
	void AI()
	{
		findRoute(m_ptBeginning);
		if(!m_vRoute.empty()){
			CRoute::iterator it = m_vRoute.begin();
			for(; it != m_vRoute.end(); it++){
				CPoint pt = *it;
				std::cout << "(" << pt.row << ", " << pt.col << ")";
				if(it != m_vRoute.end() - 1){
					std::cout << "->";
				}else{
					std::cout << std::endl;
				}
			}
		}else{
			//如果没有找到路线到达终点
			std::cout << "Sorry cannot file any ways to get ending." << std::endl;
		}
	}

};

代码都加上了注释,大家可以慢慢看。
如果上述过程把你搅晕了,那就用图来为你解答吧。

不再依赖A*,利用C++编写全新寻路算法

然后来到main函数

//用VC 6.0貌似不需要给main传参数,那我就偷一下懒
int main()
{
	//定义迷宫数组,定义成C风格的二维数组方便查看
	int vLabyrinthArray[][4] = {
		{1,0,-1,1}
		, {1,0,0,1}
		, {0,0,1,1}
		, {0,1,1,0}
		, {0,1,1,1}
		, {-2,1,0,0}
	};

	//以下代码为将C风格的二维数组导入成C++风格的二维数组
	int nRowNum = sizeof(vLabyrinthArray) / sizeof(vLabyrinthArray[0]);
	int nColNum = sizeof(vLabyrinthArray[0]) / sizeof(int);

	CLabyrinth vLabyrinth;
	for(int row = 0; row < nRowNum; row++){
		CRow xRow;
		for(int col = 0; col < nColNum; col++){
			int n = vLabyrinthArray[row][col];
			xRow.push_back(n);
		}
		vLabyrinth.push_back(xRow);
	}

	//实例化CLabyrinthAI
	CLabyrinthAI xAI(vLabyrinth);
	//打出路线
	xAI.AI();

	//使程序暂停,方便查看数据
	system("Pause");

	return 0;
}

以上代码同样加了注释,相信了解C++的同学都能看懂。

运行截图:

不再依赖A*,利用C++编写全新寻路算法

(Dos的,有点丑……不再依赖A*,利用C++编写全新寻路算法

三,Javascript版

顺便我也把C++版的移植到了Javascript上,代码如下:

function CLabyrinthAI(){
	var s = this;
	s.m_xLabyrinth = new Array(new Array());
	s.m_ptBeginning = {};
	s.m_ptEnding = {};
	s.m_vRoute = new Array();
	s.Beginning = -1;
	s.Ending = -2;
	s.CannotGo = 0;
	s.CanGo = 1;
	s.FoundEnding = 0;
	s.NotFoundEnding = 1;
}
CLabyrinthAI.prototype.initAI = function(){
	var s = this;
	s.getBeginning();
	s.getEnding();
}
CLabyrinthAI.prototype.isRepeat = function(pt){
	var s = this;
	var bRes = false;
	for(var n = 0; n < s.m_vRoute.length; n++){
		var pt0 = s.m_vRoute[n];
		if(pt0.col == pt.col && pt0.row == pt.row){
			bRes = true;
			break;
		}
	}
	return bRes;
};
CLabyrinthAI.prototype.advance = function(ptTo){
	this.m_vRoute.push(ptTo);
};
CLabyrinthAI.prototype.back = function(){
	this.m_vRoute.splice(this.m_vRoute.length-1,1);
};
CLabyrinthAI.prototype.isBeginning = function(pt){
	if(this.m_ptBeginning.col == pt.col && this.m_ptBeginning.row == pt.row){
		return true;
	}else{
		return false;
	}
};
CLabyrinthAI.prototype.isEnding = function(pt){
	if(this.m_ptEnding.col == pt.col && this.m_ptEnding.row == pt.row){
		return true;
	}else{
		return false;
	}
};
CLabyrinthAI.prototype.canUp = function(ptCurrent){
	var s = this;
	var ptRes = {col:-1,row:-1};
	var col = ptCurrent.col;
	var row = ptCurrent.row;
	if(row > 0){
		var ptNext = {col:col,row:row - 1};
		if(!s.isRepeat(ptNext)){
			var nAttr = s.m_xLabyrinth[ptNext.row][ptNext.col];
			if(nAttr == s.CanGo || nAttr == s.Ending){
				ptRes = ptNext;
			}
		}
	}
	return ptRes;
};
CLabyrinthAI.prototype.canDown = function(ptCurrent){
	var s = this;
	var ptRes = {col:-1,row:-1};
	var col = ptCurrent.col;
	var row = ptCurrent.row;
	if(row < s.m_xLabyrinth.length - 1){
		var ptNext = {col:col,row:row + 1};
		if(!s.isRepeat(ptNext)){
			var nAttr = s.m_xLabyrinth[ptNext.row][ptNext.col];
			if(nAttr == s.CanGo || nAttr == s.Ending){
				ptRes = ptNext;
			}
		}
	}
	return ptRes;
};
CLabyrinthAI.prototype.canLeft = function(ptCurrent){
	var s = this;
	var ptRes = {col:-1,row:-1};
	var col = ptCurrent.col;
	var row = ptCurrent.row;
	if(col > 0){
		var ptNext = {col:col-1,row:row};
		if(!s.isRepeat(ptNext)){
			var nAttr = s.m_xLabyrinth[ptNext.row][ptNext.col];
			if(nAttr == s.CanGo || nAttr == s.Ending){
				ptRes = ptNext;
			}
		}
	}
	return ptRes;
};
CLabyrinthAI.prototype.canRight = function(ptCurrent){
	var s = this;
	var ptRes = {col:-1,row:-1};
	var col = ptCurrent.col;
	var row = ptCurrent.row;
	if(col < s.m_xLabyrinth[0].length - 1){
		var ptNext = {col:col+1,row:row};
		if(!s.isRepeat(ptNext)){
			var nAttr = s.m_xLabyrinth[ptNext.row][ptNext.col];
			if(nAttr == s.CanGo || nAttr == s.Ending){
				ptRes = ptNext;
			}
		}
	}
	return ptRes;
};
CLabyrinthAI.prototype.allRight = function(p){
	if(p.col >= 0 && p.row >= 0){
		return true;
	}else{
		return false;
	}
};
CLabyrinthAI.prototype.findRoute = function(ptCurrent){
	var s = this;
	var nRes = s.NotFoundEnding;
	var ptNext = {col:-1,row:-1};

	s.advance(ptCurrent);
	
	if(s.isEnding(ptCurrent)){
		nRes = s.FoundEnding;
	}else{
		ptNext = s.canUp(ptCurrent);
		if(s.allRight(ptNext)){
			if(s.findRoute(ptNext) == s.FoundEnding){
				nRes = s.FoundEnding;
				return nRes;
			}
		}
		
		ptNext = s.canLeft(ptCurrent);
		if(s.allRight(ptNext)){
			if(s.findRoute(ptNext) == s.FoundEnding){
				nRes = s.FoundEnding;
				return nRes;
			}
		}
		
		ptNext = s.canDown(ptCurrent);
		if(s.allRight(ptNext)){
			if(s.findRoute(ptNext) == s.FoundEnding){
				nRes = s.FoundEnding;
				return nRes;
			}
		}
		
		ptNext = s.canRight(ptCurrent);
		if(s.allRight(ptNext)){
			if(s.findRoute(ptNext) == s.FoundEnding){
				nRes = s.FoundEnding;
				return nRes;
			}
		}
	}
	if(nRes != s.FoundEnding){
		s.back();
	}
	
	return nRes;
};
CLabyrinthAI.prototype.getBeginning = function(){
	var s = this;
	for(var nRow = 0; nRow < s.m_xLabyrinth.length; nRow++){
		var xRow = s.m_xLabyrinth[nRow];
		for(var nCol = 0; nCol < xRow.length; nCol++){
			var n = xRow[nCol];
			if(n == s.Beginning){
				s.m_ptBeginning = {col:nCol,row:nRow};
				break;
			}
		}
	}
};
CLabyrinthAI.prototype.getEnding = function(){
	var s = this;
	for(var nRow = 0; nRow < s.m_xLabyrinth.length; nRow++){
		var xRow = s.m_xLabyrinth[nRow];
		for(var nCol = 0; nCol < xRow.length; nCol++){
			var n = xRow[nCol];
			if(n == s.Ending){
				s.m_ptEnding = {col:nCol,row:nRow};
				break;
			}
		}
	}
};
CLabyrinthAI.prototype.AI = function(data){
	var s = this;
	s.m_xLabyrinth = data;
	s.initAI();
	s.findRoute(s.m_ptBeginning);
	return s.m_vRoute;
};

设计原理和C++版差不多,只是没有CPoint类而已。

虽然这套算法是研究出来了,但是还不能判断是否为最近路线,因此有待更新。不过以现在的算法,开发一个SLG应该不是问题了。

※感谢我的哥哥与我一起讨论其中的原理。

源代码下载:

http://files.cnblogs.com/yorhom/findRoute.rar

谢谢大家阅读本文,支持就是最大的鼓励。

—————————————————————-

欢迎大家转载我的文章。

转载请注明:转自Yorhom’s Game Box

http://blog.csdn.net/yorhomwang

欢迎继续关注我的博客

分类: 未分类 标签: