cocos creator基础-(二十九)动画编辑器编辑地图路径

思路

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);
        }
    },
});

原文地址:https://www.cnblogs.com/orxx/p/10560390.html

时间: 2024-07-30 01:42:23

cocos creator基础-(二十九)动画编辑器编辑地图路径的相关文章

cocos creator基础-(二十四)cc.Director与资源加载策略

1: 了解creator场景切换; 2: 了解director基本的一些接口; 3: 理解资源加载的策略; cc.Director对象 1:游戏里面控制管理整个游戏全局对象,包括了场景切换等,为cc.Director对象; 2:导演对象全局只有一个cc.director,大写的为类, 小写的cc.director为全局的导演对象; 3: cc.director来获取导演对象实例; 4: 游戏中各种管理对象都可以通过cc.director获取,比如物理引擎管理,Action管理, 碰撞检测管理等;

cocos creator基础-(二十)物理引擎碰撞检测

1: 理解物体类型和分类,配置碰撞矩阵;2: 编写碰撞响应函数,监听碰撞事件;3: 学会了解Sensor来做触发器,只触发碰撞不改变运动; 物体类型与碰撞矩阵 1: 添加物体类型: Add Layer, 每个类型对应一个名字group与groupIndex2: 创建物体的时候要选择一个类型;3: 配置碰撞矩阵,决定哪些物体类型碰撞; 碰撞事件监听 1: 刚体组件开启碰撞监听;2: 当有碰撞发生的时候,遍历刚体所在的节点所挂的所有的组件,看组件是否实现了碰撞检测函数,如果是,那么调用;3: 在需要

cocos creator基础-(二十五)FileUtils本地文件读写

1: 掌握jsb.fileUtils的基本使用; FileUtils API   CCFileUtils.h 1:jsb是javascript bind的代表,整个C/C++ 导出的绑定都在这个jsb里面,jsb 支持native,不支持h5(浏览器上无法运行jsb is not defined ); 2: FileUtils是本地文件读写的一个工具类,全局只有一个实例; 3: jsb.fileUtils来获取文件读写工具类的实例; 4: jsb.fileUtils.isDirectoryExi

cocos creator基础-(二十三)android环境搭建、h5/android 打包发布

1: 了解h5打包发布,要注意的事项; 2: 完成android环境配置与creator 项目android打包; 3: 使用 eclips打开项目或android-studio; h5打包发布 1:引擎模块裁剪,减少引擎体积; 2: resources目录的特性,减少setting.js体积; 3: 订制启动的logo,与样式; 4: resources特性 a:creator里面会根据场景的依赖来打包的我们的资源, 资源没有用的,将不会被打包进来; b:有时候我们需要代码加载我们的资源, c

Bootstrap &lt;基础二十六&gt;进度条

Bootstrap 进度条.在本教程中,你将看到如何使用 Bootstrap 创建加载.重定向或动作状态的进度条. Bootstrap 进度条使用 CSS3 过渡和动画来获得该效果.Internet Explorer 9 及之前的版本和旧版的 Firefox 不支持该特性,Opera 12 不支持动画. 默认的进度条 创建一个基本的进度条的步骤如下: 添加一个带有 class .progress 的 <div>. 接着,在上面的 <div> 内,添加一个带有 class .prog

Bootstrap&lt;基础二十四&gt; 缩略图

Bootstrap 缩略图.大多数站点都需要在网格中布局图像.视频.文本等.Bootstrap 通过缩略图为此提供了一种简便的方式.使用 Bootstrap 创建缩略图的步骤如下: 在图像周围添加带有 class .thumbnail 的 <a> 标签. 这会添加四个像素的内边距(padding)和一个灰色的边框. 当鼠标悬停在图像上时,会动画显示出图像的轮廓. 下面的实例演示了默认的缩略图: <!DOCTYPE html> <html> <head> &l

Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView

Android学习笔记二十九之SwipeRefreshLayout.RecyclerView和CardView 前面我们介绍了AlertDialog和几个常用的Dialog,ProgressDialog进度条提示框.DatePickerDialog日期选择对话框和TimePickerDialog时间选择对话框.这一节我们介绍几个新的API控件SwipeRefreshLayout.RecyclerView和CardView,这几个API控件都是google在Android5.0推出的.下面我们来学

Bootstrap &lt;基础二十五&gt;警告(Alerts)

警告(Alerts)以及 Bootstrap 所提供的用于警告的 class.警告(Alerts)向用户提供了一种定义消息样式的方式.它们为典型的用户操作提供了上下文信息反馈. 您可以为警告框添加一个可选的关闭按钮.为了创建一个内联的可取消的警告框,请使用 警告(Alerts) jQuery 插件. 您可以通过创建一个 <div>,并向其添加一个 .alert class 和四个上下文 class(即 .alert-success..alert-info..alert-warning..ale

二十九、linux常用命令(一)

vim是打开vim编辑器,别的编辑器还有vi(功能没有vim 强大),nano,emacs等等,感觉还是vim最强大,其次是vi,别的就要差一些了. 我听我们老师说,用图形界面本身已经会被高手笑了,如果打开一个gpedit或者kwrite那就废了......常用的命令 ls,列出当前目录下的文件,ls -l是列出详细信息,ls -a列出隐藏文件. cd,更改目录.clear,清屏命令.reset,重置终端. startx,启动图形界面.fdisk -l,查看硬盘分区. ps aux,列出系统进程