用Java写的一个 Box2D b2PolygonShape描点工具

为满足项目需求,我用java写了一个生成Box2D b2PolygonShape多边形顶点的工具。

也是一步一步完成的,首先是为1个不规则的sprite图片生成多边形shape轮廓,后来发现如果用Box2D里面的compound概念的话

可以生成比较完美的不规则图片 shape 轮廓,因此,工具升级到1.1,从此支持对不规则的sprite图片进行描点

1.1版完成的时候逛了逛子龙山人的博客,发现ray的教程里面有介绍1个多边形描点工具

是源自 Johannes Fahrenkrug 的 VertexHelper,下下来在xcode里面跑了下,

发现还不错,

不过让我比较不解的是:生成的竟然是 box2d 以及 chipmunk 引擎的程序代码片段

这个我感觉不是很好,灵活性不够!不过这都是后话了,其实我对自己写的描点工具还是算比较满意的~

下面给个VertexHelper的图:


下面是VertextHelper的用例图,相信还是很容易就能看出怎么使用这个工具的,如果你用过Box2D的话~

以下是我做的工具的几张截图:


这个工具的设计思路还是比较简单的:

①将复杂的图形分割成多个凸多边形(Box2D只支持凸多边形,而且最大8个顶点,如果要超过8个顶点,请修改b2Settings.h头文件)

②这张图片我进行了倒置变换,这样可以减少一些坐标变换的工作,不过也带来了一些不好的影响,用到了一个类结果导致打不成Jar包了

③鉴于对JFrame边框以及Javaswing空间尺寸打不准,因此程序界面尽量简洁免除不必要的工作量,功能输入由快捷键代劳

比如,可以动态更改所描点的尺寸([]),以及子多边形外围矩形包围框的宽度(<>)

④避免输入不合乎条件的点,我对整个图片加了一个矩形包围框,点在这个矩形包围框外部的点将无效

⑤输入难免会出现差错,而且一个复杂图形必定要点出很多个子凸多边形才能完全覆盖,这样的话,出现错误时的挽救就是个问题

我采用了这样的思路:动画sprite图片最多不超过512*512的尺寸,那么,对付这么一些小个子图片的话

适当的采用高清4倍版的图片进行描点必会带来很好的用户体验,这样的话,就不用因为图片实在是太小点不准而做重复的工作了~

其实在第1版仅仅为1整张图片描出一个多边形的时候,我加入了撤销的操作,但是1.1版因为加入了复合多边形的概念

一张图片将会由多个子凸多边形来覆盖,撤销操作难免要考虑到不少的情形,我直接屏蔽之了,其实我是个懒人~

对于bird1_animi0×0.5.png这张图片


下面是生成的数据文件格式:

bird1_animi=0-59,18-22,41-41*41-41,18-22,30-8,50-1,78-6,69-45*69-45,78-6,93-24,99-44,100-57,86-59*86-59,100-57,95-84,81-81
bird2_animi=1-57,13-19,30-6,53-0,75-2,35-46*35-46,75-2,102-11,112-28,114-48,111-64,69-74*69-74,111-64,139-86,87-132,75-128,65-99
lighttower_animi=4-2,247-5,161-537,81-536*81-536,161-537,169-612,73-610*73-610,169-612,183-622,124-709,60-618

数据格式很简单,也很容易进行解析:

①采用了键值对的方式,可以通过以=分割成字符串数组,很容易的将一个个的sprite的形状数据添加到NSMutableDictionary里面去;

②多个形状图片之间以\n换行符进行分隔(windows用\r\n换行,linux,mac,java仅以\n换行),多个子凸多边形之间以星号进行分隔,

单个子凸多边形的各个顶点之间以逗号进行分隔,单个顶点的横纵坐标之间以横线进行分隔~

接下来是解析和使用该数据格式的相关代码:

①初步解析数据以字典的形式保存起来(该字典对象是一个单例,初步解析后保存的数据可以在整个程序的范围内被访问到)~

// 加载sprite动画的顶点信息~
-(void) loadAnimationData {
	_animVerticesDic = [[NSMutableDictionary alloc] initWithCapacity:20];
	NSString *absPath = [[NSBundle mainBundle] pathForResource:@"animVerticesSummary" ofType:@"txt"];
	
	NSFileManager *fm = [NSFileManager defaultManager];
	if([fm fileExistsAtPath:absPath] == NO) {
		NSLog(@"File not exists!");
		return;
	}
	
	NSString *fileContent = [NSString stringWithContentsOfFile:absPath
						encoding:NSUTF8StringEncoding 
						error:nil];
	NSArray *verticesSummaryArray = [fileContent componentsSeparatedByString:@"\n"];
	int len = [verticesSummaryArray count];
	for(int i = 0; i < len; i ++) {
		NSString *unit = [verticesSummaryArray objectAtIndex:i];
		NSRange range = [unit rangeOfString:@"="];

		NSString *keyStr = [unit substringToIndex:range.location];

		NSString *valueStr = [unit substringFromIndex:range.location+1];
		[_animVerticesDic setObject:valueStr forKey:keyStr];
	}
}

②具体的数据解析代码:

// 解析包含sprite动画帧的顶点数据的字符串
- (void) createSpriteShapes:(NSString*)animName sz:(CGSize)size {
	NSString *verticesStr = [[BYSingle getInstance].animVerticesDic objectForKey:animName];
	NSArray *childShapes = [verticesStr componentsSeparatedByString:@"*"];
	_childShapeCount = [childShapes count];
	NSLog(@"有多少个子形状: %d", _childShapeCount);
	
	_b2Shapes = new b2PolygonShape[_childShapeCount];
	_b2FixtureDefs = new b2FixtureDef[_childShapeCount];
	
	for(int i = 0; i < _childShapeCount; i ++) {
		NSString *verticesStr =  [childShapes objectAtIndex:i];
		NSArray *verticesArray = [verticesStr componentsSeparatedByString:@","];
		int verticesLen = [verticesArray count];
		NSLog(@"第%d个子形状有多少个顶点: %d", i, verticesLen);
		
		b2Vec2 vertices[verticesLen];
		for(int j = 0; j < verticesLen; j ++) {
			NSString *vStr = [verticesArray objectAtIndex:j];
			NSArray *array = [vStr componentsSeparatedByString:@"-"];
			
			float x = (float)[[array objectAtIndex:0] intValue];
			float y = (float)[[array objectAtIndex:1] intValue];
			
			vertices[j] = b2Vec2(x/PTM_RATIO, y/PTM_RATIO);
		}
		for(int j = 0; j < verticesLen; j ++) {
			vertices[j]+=b2Vec2(-size.width/2/PTM_RATIO, -size.height/2/PTM_RATIO);	// 平移使图片与polygon重合~
		}
		
		_b2Shapes[i].Set(vertices, verticesLen);
		_b2FixtureDefs[i].shape = &_b2Shapes[i];
		
		_b2FixtureDefs[i].density = BOX_DENSITY;
		_b2FixtureDefs[i].friction = BOX_FRICTION;
		_b2FixtureDefs[i].restitution = BOX_RESTITUTION;	
	}
}
抹了,贴几张游戏的图片

①单个凸多边形版的:


②多个子凸多边形版的:



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值