思路 1、利用动画编辑器,设置一个路径,多个路径就编辑多个动画 2、用特定的代码对动画进行处理,获取到路径坐标,大佬已经写好代码,不用自己重复造轮子了(微元法求曲线长度
思路
1、利用动画编辑器,设置一个路径,多个路径就编辑多个动画
2、用特定的代码对动画进行处理,获取到路径坐标,大佬已经写好代码,不用自己重复造轮子了(微元法求曲线长度)
获得动画路径的贝塞尔曲线方程
求得每一段贝塞尔曲线的长度
每隔一小段打一个点
最终生成一个路径
3、编写寻路脚本,挂载到物体上,让沿着路径移动
动画编辑
脚本挂载
// gen_map_path.js 动画路径转换坐标的代码 已经升级到2.x cc.Class({ extends: cc.Component, properties: { // foo: { // default: null, // The default value will be used only when the component attaching // to a node for the first time // url: cc.Texture2D, // optional, default is typeof default // serializable: true, // optional, default is true // visible: true, // optional, default is true // displayName: ‘Foo‘, // optional // readonly: false, // optional, default is false // }, // ... is_debug: false, }, // use this for initialization onLoad: function() { this.anim_com = this.node.getComponent(cc.Animation); var clips = this.anim_com.getClips(); var clip = clips[0]; var newNode = new cc.Node(); this.new_draw_node = newNode.getComponent(cc.Graphics); if (!this.new_draw_node) { this.new_draw_node = this.node.addComponent(cc.Graphics); } this.node.addChild(newNode); // this.draw_node = new cc.DrawNode(); // this.node._sgNode.addChild(this.draw_node); var paths = clip.curveData.paths; // console.log(paths); this.road_data_set = []; var k; for (k in paths) { var road_data = paths[k].props.position; this.gen_path_data(road_data); } }, start: function() { /* // test() var actor = cc.find("UI_ROOT/map_root/ememy_gorilla").getComponent("actor"); // actor.gen_at_road(this.road_data_set[0]); actor = cc.find("UI_ROOT/map_root/ememy_small2").getComponent("actor"); // actor.gen_at_road(this.road_data_set[1]); actor = cc.find("UI_ROOT/map_root/ememy_small3").getComponent("actor"); actor.gen_at_road(this.road_data_set[2]); */ // end }, get_road_set: function() { return this.road_data_set; }, gen_path_data: function(road_data) { var ctrl1 = null; var start_point = null; var end_point = null; var ctrl2 = null; var road_curve_path = []; // [start_point, ctrl1, ctrl2, end_point], for (var i = 0; i < road_data.length; i++) { var key_frame = road_data[i]; if (ctrl1 !== null) { road_curve_path.push([start_point, ctrl1, ctrl1, cc.p(key_frame.value[0], key_frame.value[1])]); } start_point = cc.p(key_frame.value[0], key_frame.value[1]); for (var j = 0; j < key_frame.motionPath.length; j++) { var end_point = cc.p(key_frame.motionPath[j][0], key_frame.motionPath[j][1]); ctrl2 = cc.p(key_frame.motionPath[j][2], key_frame.motionPath[j][3]); if (ctrl1 === null) { ctrl1 = ctrl2; } // 贝塞尔曲线 start_point, ctrl1, ctrl2, end_point, road_curve_path.push([start_point, ctrl1, ctrl2, end_point]); ctrl1 = cc.p(key_frame.motionPath[j][4], key_frame.motionPath[j][5]); start_point = end_point; } } console.log(road_curve_path); var one_road = [road_curve_path[0][0]]; for (var index = 0; index < road_curve_path.length; index++) { start_point = road_curve_path[index][0]; ctrl1 = road_curve_path[index][1]; ctrl2 = road_curve_path[index][2]; end_point = road_curve_path[index][3]; var len = this.bezier_length(start_point, ctrl1, ctrl2, end_point); var OFFSET = 16; var count = len / OFFSET; count = Math.floor(count); var t_delta = 1 / count; var t = t_delta; for (var i = 0; i < count; i++) { var x = start_point.x * (1 - t) * (1 - t) * (1 - t) + 3 * ctrl1.x * t * (1 - t) * (1 - t) + 3 * ctrl2.x * t * t * (1 - t) + end_point.x * t * t * t; var y = start_point.y * (1 - t) * (1 - t) * (1 - t) + 3 * ctrl1.y * t * (1 - t) * (1 - t) + 3 * ctrl2.y * t * t * (1 - t) + end_point.y * t * t * t; one_road.push(cc.p(x, y)); t += t_delta; } } console.log(one_road); if (this.is_debug) { this.new_draw_node.clear(); // 清除以前的 for (var i = 0; i < one_road.length; i++) { this.new_draw_node.moveTo(one_road[i].x, one_road[i].y); this.new_draw_node.lineTo(one_road[i].x + 1, one_road[i].y + 1); this.new_draw_node.stroke(); // this.draw_node.drawSegment(one_road[i], // cc.p(one_road[i].x + 1, one_road[i].y + 1), // 1, cc.color(255, 0, 0, 255)); } } this.road_data_set.push(one_road); }, bezier_length: function(start_point, ctrl1, ctrl2, end_point) { // t [0, 1] t 分成20等分 1 / 20 = 0.05 var prev_point = start_point; var length = 0; var t = 0.05; for (var i = 0; i < 20; i++) { var x = start_point.x * (1 - t) * (1 - t) * (1 - t) + 3 * ctrl1.x * t * (1 - t) * (1 - t) + 3 * ctrl2.x * t * t * (1 - t) + end_point.x * t * t * t; var y = start_point.y * (1 - t) * (1 - t) * (1 - t) + 3 * ctrl1.y * t * (1 - t) * (1 - t) + 3 * ctrl2.y * t * t * (1 - t) + end_point.y * t * t * t; var now_point = cc.p(x, y); var dir = now_point.sub(prev_point); prev_point = now_point; length += dir.mag(); t += 0.05; } return length; } // called every frame, uncomment this function to activate update callback // update: function (dt) { // }, });
// actor.js 角色沿路径行走代码 var gen_map_path = require("gen_map_path"); var State = { Idle: 0, Walk: 1, Attack: 2, Dead: 3, }; cc.Class({ extends: cc.Component, properties: { // foo: { // default: null, // The default value will be used only when the component attaching // to a node for the first time // url: cc.Texture2D, // optional, default is typeof default // serializable: true, // optional, default is true // visible: true, // optional, default is true // displayName: ‘Foo‘, // optional // readonly: false, // optional, default is false // }, // ... map: { type: gen_map_path, default: null, }, speed: 100, }, // use this for initialization onLoad: function() { }, start: function() { var road_set = this.map.get_road_set(); this.cur_road = road_set[0]; if (this.cur_road < 2) { return; } this.state = State.Idle; var pos = this.cur_road[0]; this.node.setPosition(pos); this.walk_to_next = 1; this.start_walk(); }, start_walk: function() { if (this.walk_to_next >= this.cur_road.length) { // 攻击逻辑 this.state = State.Attack; // return; } var src = this.node.getPosition(); var dst = this.cur_road[this.walk_to_next]; var dir = dst.sub(src); var len = dir.mag(); this.vx = this.speed * dir.x / len; this.vy = this.speed * dir.y / len; this.walk_total_time = len / this.speed; this.walked_time = 0; this.state = State.Walk; }, walk_update: function(dt) { if (this.state != State.Walk) { return; } this.walked_time += dt; if (this.walked_time > this.walk_total_time) { dt -= (this.walked_time - this.walk_total_time); } var sx = this.vx * dt; var sy = this.vy * dt; this.node.x += sx; this.node.y += sy; if (this.walked_time >= this.walk_total_time) { this.walk_to_next++; this.start_walk(); } }, // called every frame, uncomment this function to activate update callback update: function(dt) { if (this.state == State.Walk) { this.walk_update(dt); } }, });