之前完成了flash版本的“反向动力学应用-可拖动的圆规”,用flash cc改成了html5版的。
还是先看效果。
源码如下(flash cc中帧上代码):
this.stop(); var stage = this.getStage(); var divider = this.divider; var legL = divider.legL; var legR = divider.legR; var lp = divider.lp; var mp = divider.mp; var rp = divider.rp; var 移动末端; var 移动端点; var 关节; var 固定端点; var 固定杆; var 活动杆; var 可活动长度; var 活动杆长度; var 固定杆长度; var targetX; var targetY; var dragType=0; legL.addEventListener("mousedown", dragLhandler); lp.addEventListener("mousedown", dragLhandler); legR.addEventListener("mousedown", dragRhandler); rp.addEventListener("mousedown", dragRhandler); divider.addEventListener("mousedown", draghandler); stage.addEventListener("mouseup", mouseUpHandler); stage.addEventListener("pressmove", pressMoveHandler); function mouseUpHandler(e){ dragType=0; } /** * 整体拖动 */ function draghandler(e){ console.log("整体拖动"); dragType=2; } /** * 拖动左边 * @param e */ function dragLhandler(e) { console.log("拖动左边"); e.stopPropagation(); var p=divider.globalToLocal(stage.mouseX, stage.mouseY); targetX = p.x; targetY = p.y; 移动端点 = p; 移动末端 = lp;关节 = mp; 固定端点 = rp; 固定杆 = legR; 活动杆 = legL; 活动杆长度 = distance(移动末端, 关节); 固定杆长度 = distance(固定端点, 关节); 可活动长度 = distance(移动端点, 关节); dragType=1; } /** * 拖动右边 * @param e */ function dragRhandler(e) { console.log("拖动右边"); e.stopPropagation(); var p=divider.globalToLocal(stage.mouseX, stage.mouseY); targetX = p.x; targetY = p.y; 移动端点 =p; 移动末端 = rp; 关节 = mp; 固定端点 = lp; 固定杆 = legL; 活动杆 = legR; 活动杆长度 = distance(移动末端, 关节); 固定杆长度 = distance(固定端点, 关节); 可活动长度 = distance(移动端点, 关节); dragType=1; } /** * 几何距离 */ function distance(obj1, obj2) { return Math.sqrt((obj1.y - obj2.y) * (obj1.y - obj2.y) + (obj1.x - obj2.x) * (obj1.x - obj2.x)); } /** * 鼠标按下拖动 */ function pressMoveHandler(e) { //move(); if(dragType==1){ move(); } else if(dragType==2){ divider.x=stage.mouseX; divider.y=stage.mouseY; } } /** * 碰撞检测 * @return {[type]} [description] */ function hitTest(){ var r1=固定端点.nominalBounds.width/2; var r2=移动末端.nominalBounds.width/2; return distance(固定端点,移动末端)<=(r1+r2); } /** * */ function move() { var p=divider.globalToLocal(stage.mouseX, stage.mouseY); if(segmentsIntr(移动末端,p,关节,固定端点)){ return; } if (hitTest()) { //trace("撞到了"); var p1 = new createjs.Point(p.x - targetX, p.y - targetY); var p2 = new createjs.Point(移动末端.x - 固定端点.x, 移动末端.y - 固定端点.y); if (p1.x * p2.x + p1.y * p2.y < 0) { //trace("不能移动"); return; } } // var flag = true; var count = 0; targetX = p.x; targetY = p.y; while (flag) { move2target(targetX, targetY); var angle01 = Math.atan2(targetY - 关节.y, targetX - 关节.x); var angle02 = Math.atan2(移动末端.y - 关节.y, 移动末端.x - 关节.x); flag = Math.abs((angle02 - angle01) * 180 / Math.PI) > 1.0; count++; if (count > 10) break; } 固定杆.x = 关节.x; 固定杆.y = 关节.y; 固定杆.rotation = Math.atan2(固定端点.y - 关节.y, 固定端点.x - 关节.x) * 180 / Math.PI; 活动杆.x = 关节.x; 活动杆.y = 关节.y; 活动杆.rotation = Math.atan2(移动末端.y - 关节.y, 移动末端.x - 关节.x) * 180 / Math.PI; //trace("循环了" + count + "次"); //关节位于元件的(0,0)点 var offsetX = 关节.x; var offsetY = 关节.y; var numchildren=divider.getNumChildren(); for (var i = 0; i < numchildren; i++) { var dis = divider.getChildAt(i); dis.x -= offsetX; dis.y -= offsetY; } divider.x += offsetX; divider.y += offsetY; } function move2target(targetX, targetY) { var angle01 = Math.atan2(targetY - 关节.y, targetX - 关节.x); //var 活动杆rotation:Number = angle01 * 180 / Math.PI; 移动端点.x = 关节.x + 可活动长度 * Math.cos(angle01); 移动端点.y = 关节.y + 可活动长度 * Math.sin(angle01); var tx = targetX - 移动端点.x; var ty = targetY - 移动端点.y; 关节.x += tx; 关节.y += ty; var targetX2 = 关节.x; var targetY2 = 关节.y; var angle02 = Math.atan2(targetY2 - 固定端点.y, targetX2 - 固定端点.x); //var 固定杆rotation:Number = angle02 * 180 / Math.PI; 关节.x = 固定端点.x + 固定杆长度 * Math.cos(angle02); 关节.y = 固定端点.y + 固定杆长度 * Math.sin(angle02); 移动末端.x = 关节.x + 活动杆长度 * Math.cos(angle01); 移动末端.y = 关节.y + 活动杆长度 * Math.sin(angle01); } /** * 計算线段ab和线段cd是否相交 * 复制于:http://www.cnblogs.com/i-gps/archive/2012/06/19/2554992.html * @param {[type]} a [description] * @param {[type]} b [description] * @param {[type]} c [description] * @param {[type]} d [description] * @return {[type]} [description] */ function segmentsIntr(a, b, c, d){ /** 1 解线性方程组, 求线段交点. **/ // 如果分母为0 则平行或共线, 不相交 var denominator = (b.y - a.y)*(d.x - c.x) - (a.x - b.x)*(c.y - d.y); if (denominator==0) { return false; } // 线段所在直线的交点坐标 (x , y) var x = ( (b.x - a.x) * (d.x - c.x) * (c.y - a.y) + (b.y - a.y) * (d.x - c.x) * a.x - (d.y - c.y) * (b.x - a.x) * c.x ) / denominator ; var y = -( (b.y - a.y) * (d.y - c.y) * (c.x - a.x) + (b.x - a.x) * (d.y - c.y) * a.y - (d.x - c.x) * (b.y - a.y) * c.y ) / denominator; /** 2 判断交点是否在两条线段上 **/ if ( // 交点在线段1上 (x - a.x) * (x - b.x) <= 0 && (y - a.y) * (y - b.y) <= 0 // 且交点也在线段2上 && (x - c.x) * (x - d.x) <= 0 && (y - c.y) * (y - d.y) <= 0 ){ //相交 //console.log("相交"); return true; // 返回交点p return { x : x, y : y } } //否则不相交 //console.log("不相交"); return false }
遇到问题:
-
createjs中没有“mousemove”事件,但是有“pressmove”事件,用起来更方便,目前还没发现bug;
-
flash cc中变量用中文名,格式化之后会出错,var和中文变量名会连在一起;
-
createjs中碰撞检测只有一个hitTest(x,y),还是用的本地坐标,碰撞检测还是自己写算了;
-
虽然加了碰撞检测,但是拖动太快的话,会直接穿过去,所以加了一个线段相交的检测;
-
注册点的问题,元件是直接从flash as版本中复制过来的,发布之后发现,元件的注册点不是舞台上元件的坐标原点,而是元件的变形中心点,修改变形中心点,和左边远点重合之后恢复正常。
flash cc(最新版的animate cc)还是很好用的,直接用createjs库的话,有很大一部分时间实在创建元件,写布局。用flash cc就可以专注于逻辑的实现了。
可以看看flash cc导出的js文件,有好多实现思路是可以借鉴的,还有好多方法和属性是没有在api中公开的,都可以参考。
如果能针对单个项目自定义修改html模板就好了,因为有时候我们需要写一些css样式(比如背景色,margin属性等),加一些二外的js库(比如屏幕自适应);如果能实现像as一样,有文档类、链接类就更方便了,写在帧上不太适合做大一点的项目。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。