cocos2d-js帅炸了之text学习【一 spinetext骨骼动画】


好炫酷哇!


1.什么是骨骼动画

当前有两种模型动画的方式:顶点动画和骨骼动画。顶点动画中,每帧动画其实就是模型特定姿态的一个“快照”。通过在帧之间插值的方法,引擎可以得到平滑的动画效果。在骨骼动画中,模型具有互相连接的“骨骼”组成的骨架结构,通过改变骨骼的朝向和位置来为模型生成动画。

骨骼动画比顶点动画要求更高的处理器性能,但同时它也具有更多的优点,骨骼动画可以更容易、更快捷地创建。不同的骨骼动画可以被结合到一起——比如,模型可以转动头部、射击并且同时也在走路。一些引擎可以实时操纵单个骨骼,这样就可以和环境更加准确地进行交互——模型可以俯身并向某个方向观察或射击,或者从地上的某个地方捡起一个东西。多数引擎支持顶点动画,但不是所有的引擎都支持骨骼动画。

2.关于帧动画和骨骼动画的加载与调用

对比一下示例代码:
// *********************帧动画加载与调用************************
 
// 动作的加载
initAction:function(){
    // 站立动作
    var sa = cc.Animation.create();
    for (var si = 1; si < 4; si++){
        var frameName1 = "res/Hero" + si + ".png";
        sa.addSpriteFrameWithFile(frameName1);
    }
    sa.setDelayPerUnit(5.8 / 14);
    sa.setRestoreOriginalFrame(true);
    this._actionStand = cc.RepeatForever.create(cc.Animate.create(sa));
 
    // 跑动动作
    var animation = cc.Animation.create();
    for (var i = 1; i < 12; i++){
        var frameName = "res/HeroRun" + i + ".png";
        animation.addSpriteFrameWithFile(frameName);
    }
    animation.setDelayPerUnit(2.8 / 14);
    animation.setRestoreOriginalFrame(true);
    this._actionRunning = cc.RepeatForever.create(cc.Animate.create(animation));
 
    // 普通攻击
    var anAttack = cc.Animation.create();
    for (var attackIndex = 1; attackIndex < 6; attackIndex ++){
        var attackFrame = "res/HeroAttack" + attackIndex + ".png";
        anAttack.addSpriteFrameWithFile(attackFrame);
    }
    anAttack.setDelayPerUnit(1.8 / 14);
    // anAttack.setRestoreOriginalFrame(false);
    this._actionAttack = cc.Animate.create(anAttack);
 
    // 跳跃攻击 ...
 
    // 突刺攻击 ...
 
    // 其它动作,如果有 ~
 
}
 
// 动作的调用
this._sprite.runAction(this._actionStand);      // 站立
this._sprite.runAction(this._actionRunning);    // 跑动
// ...
 
// *********************<a href='http://cn.cocos2d-x.org/article/index?type=cocos2d-x&url=/doc/cocos-docs-master/manual/framework/native/v3/spine/zh.md' target='_blank' title=骨骼动画>骨骼动画</a>加载与调用************************
 
// 加载骨骼资源
var s_Robot_png = "res/armature/Robot.png";
var s_Robot_plist = "res/armature/Robot.plist";
var s_Robot_json = "res/armature/Robot.json";
 
cc.ArmatureDataManager.getInstance().addArmatureFileInfo(
    s_Robot_png,
    s_Robot_plist,
    s_Robot_json);
 
this._armature = cc.Armature.create("Robot");
 
// 使用方法
this._armature.getAnimation().play("stand");    // 站立
this._armature.getAnimation().play("run");  // 跑动
// ...


3.动作组织

游戏中,对于英雄和怪物来说,有一些通用的方法或者代码结构。

var ActionSprite = cc.Node.extend({
    // 初始化方法
    init:function(obj){...},
    // 攻击
    acceptAttack:function(obj){...},
    // 是否翻转,图片“左右”走动
    isFlip:function(){...},
    // 设置精灵
    setSprite:function(image, pos){...},
    // 开始跑动 附带方向,方向是一个小于 360 的角度
    runWithDegrees:function(degrees){...},
    // 跑动,改变方向
    moveWithDegrees:function(degrees){...},
    // 停止跑动
    idle:function(){...},
    // 每帧更新
    update:function(dt){...},
    // 简单 ai 实现
    ai:function(){...},
    // 屏幕检测,人物不能走出屏幕之外 并且只能在下方
    checkLocation:function(){...},
    // 站立
    hStand:function(){...},
    // 跑动
    hRunning:function(){...},
 
    // ...
});

若为帧动画,具体实现如下:

hAttack:function(at){
    var aa = null;
    if (at == AT.ATTACK){
        aa = this._actionAttack;
        this._attackRangt = 150;            
    }else if (at == AT.ATTACK_A){
        aa = this._actionAttackJump;
        // 当前位置跳跃
        var jump = cc.JumpTo.create(
            0.6, cc.pSub(this.getPosition(), cc.p(this._flipX ? 200: -200)), 120, 1);
        this.runAction(jump);
        this._attackRangt = 300;
    }else if (at == AT.ATTACK_B){
        aa = this._actionAttackT;
        // 当前位置移动
        var move = cc.MoveTo.create(0.3, cc.pSub(this.getPosition(), cc.p(
                this._flipX ? 200:-200, 0)));
        this.runAction(move);
        this._attackRangt = 300;            
    }
 
    if (aa){
        this._sprite.stopAllActions();
        var action = cc.Sequence.create(
            aa,
            cc.CallFunc.create(this.callBackEndAttack, this));
        this._sprite.runAction(action);
        this._state = AC.STATE_HERO_ATTACK;
        this.postAttack();
    }
},
attack:function(at){
    this.hAttack(at);
},
callBackEndAttack:function(){
    if (this._isRun){
        this.hRunning();
    }else{
        this.hStand();
    }
}

若为骨骼动画,具体实现如下:

var Robot = ActionSprite.extend({
    _armture:null,
 
    init:function(){
        var bRet = false;
        if (this._super()){
 
            cc.ArmatureDataManager.getInstance().addArmatureFileInfo(
                s_Robot_png,
                s_Robot_plist,
                s_Robot_json);
 
            this._armature = cc.Armature.create("NewProject");
            this.setSprite(this._armature, cc.p(500, 300));
            this.setZLocatoin(-90);
            this.hStand();
 
            this.runWithDegrees(180);
 
            this.setRoleType(AC.ROLE_ROBOT);
            this._imageflipX = true;
            bRet = true;
            this._speed = 150;
        }       
        return bRet;
    },
    setSprite:function(armature, pos){
        this._sprite = armature;
        this.addChild(this._sprite);
        this.setPosition(pos);      
    },  
    hAttack:function(at){
        this._attackRangt = 150;                    
        this._sprite.stopAllActions();
        this._sprite.getAnimation().play("attack");
        this._sprite.getAnimation().setMovementEventCallFunc(this.callBackEndAttack,this);
        this._state = AC.STATE_HERO_ATTACK;
        this.postAttack();
    },
    hStand:function(){
        this._sprite.getAnimation().play("stand");
        this._state = AC.STATE_HERO_STAND;
    },
    hRunning:function(){
        this._sprite.getAnimation().play("run");
        this._state = AC.STATE_HERO_RUNNING;        
    },
    attack:function(button){
        this.hAttack(button);
    },
    callBackEndAttack:function(armature, movementType, movementID){
        if (movementType == CC_MovementEventType_LOOP_COMPLETE) {
            if (this._isRun){
                this.hRunning();
            }else{
                this.hStand();
            }
        }
    },
    _timestamp: (new Date()).valueOf(),
    _attackIndex: 0,
    _moveIndex: 0,
    ai:function(){
        var newTs = (new Date()).valueOf();
        var value = newTs - this._timestamp;
 
        if (this._moveIndex < value / 3000){
            this._moveIndex += 1;
            var r = Math.random() * 360;
            this.moveWithDegrees(r);
        }
        if (this._attackIndex < value / 6000){
            this._attackIndex += 1;
            this.attack();
        }
 
    }
});

4.读官方示例代码

var sp = sp || {};   开一个命名空间

var ANIMATION_TYPE = {             宏定义小人的动作类型,为状态机做准备。
    ANIMATION_START:      0,		
    ANIMATION_END:        1,		
    ANIMATION_COMPLETE:   2,
    ANIMATION_EVENT:      3
};

SpineTestScene = TestScene.extend({     里面封装了prototype函数。将对象实例化。这是一个场景类

    runThisTest:function () {
        var layer = new SpineTest();    
        this.addChild(layer);           运行layer层

        director.runScene(this);        调用 导演,运行此场景类
    }
});

touchcount = 0;

var SpineTest = BaseTestLayer.extend({        骨骼动画层  
    _spineboy:null,
    _debugMode: 0,
    _flipped: false,
    ctor:function () {                          构造函数
        this._super(cc.color(0,0,0,255), cc.color(98,99,117,255));     背景颜色

        cc.eventManager.addListener({                                添加响应事件
            event: cc.EventListener.TOUCH_ALL_AT_ONCE,          关于cc.eventlistener,一会总结吧
            onTouchesBegan: function(touches, event){
                var target = event.getCurrentTarget();
                target._debugMode ++;
                target._debugMode = target._debugMode % 3;
                if (target._debugMode == 0) {
                    target._spineboy.setDebugBones(false);
                    target._spineboy.setDebugSolots(false);
                    return;
                }

                if (target._debugMode == 1) {
                    target._spineboy.setDebugBones(true);
                    target._spineboy.setDebugSolots(false);
                    return;
                }

                if (target._debugMode == 2) {
                    target._spineboy.setDebugBones(false);
                    target._spineboy.setDebugSolots(true);
                }
            }
        }, this);
        var size = director.getWinSize();

        /
        // Make Spine's Animated skeleton Node
        // You need 'json + atlas + image' resource files to make it.
        // No JS binding for spine-c in this version. So, only file loading is supported.
        var SpineBoyAnimation = sp.SkeletonAnimation.extend({        
            ctor: function() {
                this._super('res/skeletons/spineboy.json', 'res/skeletons/spineboy.atlas');
                cc.log("Extended SkeletonAnimation");
            }
        });
        
        var spineBoy = new SpineBoyAnimation();
        spineBoy.setPosition(cc.p(size.width / 2, size.height / 2 - 150));
        spineBoy.setAnimation(0, 'walk', true);
        spineBoy.setMix('walk', 'jump', 0.2);
        spineBoy.setMix('jump', 'walk', 0.4);
        spineBoy.setAnimationListener(this, this.animationStateEvent);
        spineBoy.setScale(0.5);
        this.addChild(spineBoy, 4);
        this._spineboy = spineBoy;
    },
    onBackCallback:function (sender) {
    },
    onRestartCallback:function (sender) {
    },
    onNextCallback:function (sender) {
        touchcount++;
        this._spineboy.setAnimation(0, ['walk', 'jump','run', 'shoot'][touchcount % 4], true);
    },
    subtitle:function () {
        return "Spine test";
    },
    title:function () {
        return "Spine test";
    },

    animationStateEvent: function(obj, trackIndex, type, event, loopCount) {
        var entry = this._spineboy.getCurrent();
        var animationName = (entry && entry.animation) ? entry.animation.name : 0;

        switch(type)
        {
            case ANIMATION_TYPE.ANIMATION_START:
                cc.log(trackIndex + " start: " + animationName);
                break;
            case ANIMATION_TYPE.ANIMATION_END:
                cc.log(trackIndex + " end:" + animationName);
                break;
            case ANIMATION_TYPE.ANIMATION_EVENT:
                cc.log(trackIndex + " event: " + animationName);
                break;
            case ANIMATION_TYPE.ANIMATION_COMPLETE:
                cc.log(trackIndex + " complete: " + animationName + "," + loopCount);
                if(this._flipped){
                    this._flipped = false;
                    this._spineboy.setScaleX(0.5);
                }else{
                    this._flipped = true;
                    this._spineboy.setScaleX(-0.5);
                }
                break;
            default :
                break;
        }
    },
    
    // automation
    numberOfPendingTests:function() {
        return 1;
    },
    getTestNumber:function() {
        return 0;
    }

});

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值