11RIA 闪客社区 - 最赞 Animate Flash 论坛

搜索
查看: 2374|回复: 0
上一主题 下一主题

[2D 物理引擎] 【9RIA—ladeng6666】—【Box2D系列教程 14】信手绘制线条刚体

[复制链接] TA的其它主题
发表于 2018-2-6 13:57:54 | 显示全部楼层 |阅读模式

【游客模式】——注册会员,加入11RIA 闪客社区吧!一起见证Flash的再次辉煌……

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
转载:9RIA游戏开发者社区(天地会)
作者:ladeng6666(拉登大叔)
作者博客:http://www.ladeng6666.com/blog/


【Box2D系列教程-导航帖】—拉登大叔出品(总贴)



来自天地会的wkyjoey同学问道如何做一个重力大师游戏(如下图)。这里要特意表示一下歉意,最近一直忙于工作,没有及时更新教程。

对于重力大师游戏,试玩之后,不难发现,我们在运行时可以创建的刚体有两种,线条刚体和多边形刚体。今天我们来一起研究一下线条刚体的创建。多边形刚体会在下次教程中讨论。

4399_11544912937.jpg
这里我们要绘制的线条不是直线而是曲线,所以简单的矩形刚体无法实现这个效果。在圆形边界教程中,我们同样接触到了曲线。解决方法是用多个线段组合起来模拟一个圆圈。庆幸的是这个方法同样适用于本例中的曲线。下面我们详细讨论一下。

线条是又无数个点组成的,把点放大一些就成了线段,所以一个线条可以变成多个线段的组合。

segment.png
如上图,我们假设每个先断掉长度为segmentLength,线段的长度越短,segmentLength越小,线条模拟就越逼真。

在线条绘制过程中,持续检测鼠标坐标curPoint与前一个点prePoint之间的距离distance,当distance大于线段长度时,创建一个新的线段,并将curPoint赋值给prePoint。

好吧,下面我介绍一下具体的步骤:
    1. 定义线段的长度segmentLength
    2. 在鼠标点下后,卡是绘制线条,并记录之前的鼠标坐标位置为prePoint
    3. 在绘制过程中。如果鼠标坐标与prePoint之间的距离distance大于segmentLength,则将鼠标坐标赋值给prePoint,创建新的线段,并添加到segmentList中
    4. 鼠标弹起后,遍历所有的线段,并利用多边形组合法,创建对于的线段刚体,然后组合成一个完整的线条。
效果如下,点击并拖动鼠标开始绘制,其中的红点是线段的坐标位置。另外这里我没有限制线段的交叉,所以在绘制时尽量避免交叉,防止意外的错误,后续我们再讨论如何防止绘制线段时交叉。



源码中用到了LDEasyBox2D来简化代码。完整的代码及注释如下:
[Actionscript3] 纯文本查看 复制代码
package
{
	import Box2D.Collision.b2AABB;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2FixtureDef;
	import Box2D.Dynamics.b2World;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;

	/**
	 * [url]http://www.ladeng6666.com[/url]
	 * @author ladeng6666
	 */
	public class Main extends Sprite
	{
		private var world:b2World;

		private var spriteCanvas:Sprite;
		private var tipCanvas:Sprite;

		//前一个point
		private var prePoint:Point = new Point();
		//当前的point
		private var curPoint:Point = new Point();
		//1.设置线段长度segmentLength
		private var segmentLength:Number = 20;
		private var segmentsList:Array=new Array();

		private var isDrawing:Boolean = false;
		public function Main()
		{
			//创建box2D世界
			world = LDEasyBox2D.createWorld();
			//创建box2D调试图
			addChild(LDEasyBox2D.createDebug(world));
			//创建地面
			LDEasyBox2D.createWrapWall(world,stage);

			spriteCanvas = new Sprite();
			addChild(spriteCanvas);
			tipCanvas = new Sprite();
			addChild(tipCanvas);

			//侦听事件
			addEventListener(Event.ENTER_FRAME, loop);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove);
		}
		private function onStageMouseDown(e:MouseEvent):void
		{
			//2.开始绘制线条,并定义prePoint
			isDrawing = true;
			spriteCanvas.graphics.lineStyle(2);
			spriteCanvas.graphics.moveTo(mouseX, mouseY);

			curPoint = new Point(mouseX, mouseY);
			prePoint = curPoint.clone();
		}
		private function onStageMouseMove(e:MouseEvent):void
		{
			if(!isDrawing) return;
			spriteCanvas.graphics.lineTo(mouseX, mouseY);

			curPoint = new Point(mouseX, mouseY);
			var distance:Number = Point.distance(prePoint, curPoint);
			if (distance >= segmentLength) {
				//3.创建线段,并添加到segmentsList中
				segmentsList.push( new Segment(prePoint, curPoint));
				prePoint = curPoint.clone();
			}
		}

		private function onStageMouseUp(e:MouseEvent):void
		{
			isDrawing = false;
			spriteCanvas.graphics.clear();
			//在鼠标位置随机创建一个圆形或矩形刚体
			createSegment(segmentsList);
			//清楚segmengsList里的内容
			segmentsList = new Array();
		}

		private function loop(e:Event):void
		{
			world.Step(1 / 30, 10, 10);
			world.ClearForces();
			world.DrawDebugData();

			drawTip(segmentsList);
		}

		private function createSegment(segmentsArray:Array):void
		{
			//1.创建刚体需求b2BodyDef
			var bodyRequest:b2BodyDef = new b2BodyDef();
			bodyRequest.type = b2Body.b2_dynamicBody;
			bodyRequest.position.Set(0 ,0);//记得米和像素的转换关系
			//2.Box2D世界工厂更具需求创建createBody()生产刚体
			var body:b2Body=world.CreateBody(bodyRequest);
			//3.创建敢提形状需求b2ShapeDef的子类
				//创建矩形刚体形状需求
			var fixtureRequest:b2FixtureDef = new b2FixtureDef();
			fixtureRequest.density = 3;
			fixtureRequest.friction = 0.3;
			fixtureRequest.restitution = 0.2;

			for each(var segment:Segment in segmentsArray) {
				var shapeBoxRequest:b2PolygonShape = new b2PolygonShape();
				shapeBoxRequest.SetAsOrientedBox(segment.length /2/ 30, 2 / 30, new b2Vec2(segment.centerX/30, segment.centerY/30), segment.rotation);
				fixtureRequest.shape = shapeBoxRequest;
				body.CreateFixture(fixtureRequest);
			}
		}
		private function drawTip(segmengtsArray:Array):void {
			tipCanvas.graphics.clear();
			for each( var segment:Segment in segmengtsArray) {
				tipCanvas.graphics.beginFill(0xFF0000, 0.5);
				tipCanvas.graphics.drawCircle(segment.centerX, segment.centerY,3);
			}

		}
	}

}



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条

感谢所有支持论坛的朋友:下面展示最新的5位赞助和充值的朋友……更多赞助和充值朋友的信息,请查看:永远的感谢名单

SGlW(66139)、 anghuo(841)、 whdsyes(255)、 longxia(60904)、 囫囵吞澡(58054)

下面展示总排行榜的前3名(T1-T3)和今年排行榜的前3名的朋友(C1-C3)……更多信息,请查看:总排行榜今年排行榜

T1. fhqu1462(969)、 T2. lwlpluto(14232)、 T3. 1367926921(962)  |  C1. anghuo(147)、 C2. fdisker(27945)、 C3. 囫囵吞澡(58054)



快速回复 返回顶部 返回列表