当前位置: 首页 > article >正文

spine 动画层 动态权重

 前奏.业务背景

这边想实现一个功能,项目中有 一只猫 猫的头会盯着逗猫棒移动。因为素材还没到所以这里使用了 spine 自带的猫头鹰。他的动画 刚好挺有针对性:(关联上篇)icon-default.png?t=O83Ahttps://blog.csdn.net/nicepainkiller/article/details/144113214

一共有六组动画:

        idel  空闲动画全身都会动 多帧动画

        blink 眨眼睛动画 头不动 多帧动画

        其余几个动画只有有头会动 单帧动画 只有一帧

  •     blink  眼睛在中间的动画 会眨眼睛
  •     down 眼睛朝下看 单帧
  •     left     眼睛朝左看 单帧
  •     right   眼睛朝右看 单帧
  •     up      眼睛朝上看 单帧
  •     idel    空闲动画 全身动

 猫头鹰眼睛可以盯着 屏幕物体移动,实现效果如下 :

最初想的实现方式是:类似 Unity3D 有一个二位动画权重的东西。但是找遍 cocos creator  API 发现没找到,

那么只能纯手撸了:

        思路就是动态控制 动画层的权重来显示不同动画头上,头右,头下,头左)的播放权重。

实操1.逗猫棒位置计算

首先就确定一个屏幕可以拖动的元素,并且计算出一个区域,用来确定 向量 Vec2:

  1. 屏幕触点 转 屏幕坐标
  2. 根据屏幕坐标计算出 用来表示范围的  一个 向量
核心代码:
//获取 触点坐标位置
touchMove(event: EventTouch) {
    //更新 拖拽元素位置
    console.log('touchMove');
    this.potion.x = event.getLocationX();
    this.potion.y = event.getLocationY();
    //触点坐标转 屏幕坐标
    this.worldPostion = this.camera.screenToWorld(this.potion);
    //屏幕坐标转 局部坐标
    this.node.position = this.nodeParent.getComponent(UITransform).convertToNodeSpaceAR(this.worldPostion);
    //console.log("this.node.position:", this.node.position);
    //计算向量
    this.localPostion.x = clamp(this.node.position.x, -this.range, this.range) / this.range;
    this.localPostion.y = clamp(this.node.position.y, -this.range, this.range) / this.range;
    //console.log("this.localPostion:", this.localPostion);
    this.spinMerge1.updateAnimation(this.localPostion);
}
功能完整代码:
import { _decorator, Component, Node, EventTouch, Camera, Vec3, UITransform, Vec2, clamp, director, view } from 'cc';
import { SpinMerge1 } from './SpinMerge1';
const { ccclass, property } = _decorator;

@ccclass('TouchMove')
export class TouchMove extends Component {

    @property({ type: Node })
    private nodeParent: Node;

    @property({ type: Camera })
    private camera: Camera;

    //控制 Spine 动画的脚步
    @property({ type: SpinMerge1 })
    private spinMerge1: SpinMerge1;

    private potion: Vec3 = new Vec3();
    private worldPostion: Vec3 = new Vec3();
    private localPostion: Vec2 = new Vec2();
    private range: number;

    onLoad() {
        this.node.on(Node.EventType.TOUCH_START, this.touchStart, this);
        this.node.on(Node.EventType.TOUCH_MOVE, this.touchMove, this);
        this.node.on(Node.EventType.TOUCH_END, this.touchEnd, this)
        this.node.on(Node.EventType.TOUCH_CANCEL, this.touchCancel, this)
    }

    start() {
        this.range = view.getVisibleSize().width / 2;
    }

    //展示只有 在拖拽情况下才显示的 元素 equipmentFly
    touchStart(event: EventTouch) {
        //Log.trace('touchStart');
        console.log('touchStart');
    }

    //获取 触点坐标位置
    touchMove(event: EventTouch) {
        //更新 拖拽元素位置
        console.log('touchMove');
        this.potion.x = event.getLocationX();
        this.potion.y = event.getLocationY();
        //触点坐标转 屏幕坐标
        this.worldPostion = this.camera.screenToWorld(this.potion);
        //屏幕坐标转 局部坐标
        this.node.position = this.nodeParent.getComponent(UITransform).convertToNodeSpaceAR(this.worldPostion);
        //console.log("this.node.position:", this.node.position);
        //计算向量
        this.localPostion.x = clamp(this.node.position.x, -this.range, this.range) / this.range;
        this.localPostion.y = clamp(this.node.position.y, -this.range, this.range) / this.range;
        //console.log("this.localPostion:", this.localPostion);
        this.spinMerge1.updateAnimation(this.localPostion);
    }

    //结束拖拽 隐藏拖拽元素
    touchCancel(event: EventTouch) {
        console.log('touchCancel');
        this.node.position = new Vec3();
        this.spinMerge1.resetAnimation();

    }
    //结束拖拽
    touchEnd(event: EventTouch) {
        console.log('touchEnd');
        this.node.position = new Vec3();
        this.spinMerge1.resetAnimation();
    }

}


实操2.猫头鹰盯着逗猫棒

猫头随着物体移动的核心就是

      通过动画层混合 分别控制 头上,头右,头下,头左 动画权重,做到动态控制展示的权重。

 

核心代码:
public updateAnimation(vec2: Vec2) {
    //console.log('updateAnimation:', vec2);
    this.ver2Normal.x = Math.abs(vec2.x);
    this.ver2Normal.y = Math.abs(vec2.y);
    //右上
    if (vec2.x > 0 && vec2.y > 0) {
        this.trackleft.alpha = 0.0;
        this.trackdown.alpha = 0.0;

        this.trackright.alpha = this.ver2Normal.x;
        this.trackUp.alpha = clamp(this.ver2Normal.y, 0, 1 - this.ver2Normal.x);
        //右下
    } else if (vec2.x > 0 && vec2.y < 0) {
        this.trackUp.alpha = 0;
        this.trackleft.alpha = 0;

        this.trackright.alpha = this.ver2Normal.x;
        this.trackdown.alpha = clamp(this.ver2Normal.y, 0, 1 - this.ver2Normal.x);

        //左下
    } else if (vec2.x < 0 && vec2.y < 0) {
        this.trackUp.alpha = 0;
        this.trackright.alpha = 0;

        this.trackleft.alpha = this.ver2Normal.x;
        this.trackdown.alpha = clamp(this.ver2Normal.y, 0, 1 - this.ver2Normal.x);


        //左上
    } else if (vec2.x < 0 && vec2.y > 0) {
        this.trackright.alpha = 0;
        this.trackdown.alpha = 0;

        this.trackleft.alpha = this.ver2Normal.x;
        this.trackUp.alpha = clamp(this.ver2Normal.y, 0, 1 - this.ver2Normal.x);
    } else {
        this.trackUp.alpha = 0;
        this.trackright.alpha = 0;
        this.trackdown.alpha = 0;
        this.trackleft.alpha = 0;
    }

}
完整代码:
import { _decorator, Component, Node, sp, Button, Vec2, clamp } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('SpinMerge1')
export class SpinMerge1 extends Component {

    @property({ type: sp.Skeleton })
    private spinAnimation: sp.Skeleton;
    private trackUp: sp.spine.TrackEntry;
    private trackright: sp.spine.TrackEntry;
    private trackdown: sp.spine.TrackEntry;
    private trackleft: sp.spine.TrackEntry;

    private ver2Normal: Vec2 = new Vec2();

    start() {
        this.spinAnimation.setAnimation(0, 'idle', true);

        //猫头鹰的动画名 left right 反了
        //所以我们这里的顺序是: 上 -> 右 -> 下 -> 左 
        this.trackUp = this.spinAnimation.setAnimation(1, 'up', true);
        this.trackright = this.spinAnimation.setAnimation(4, 'left', true);
        this.trackdown = this.spinAnimation.setAnimation(3, 'down', true);
        this.trackleft = this.spinAnimation.setAnimation(2, 'right', true);
        //眨眼睛动画
        this.spinAnimation.addAnimation(5, 'blink', true, 2);

        this.trackUp.alpha = 0;
        this.trackright.alpha = 0;
        this.trackdown.alpha = 0;
        this.trackleft.alpha = 0;
    }

    onBtnTop() {
        this.trackUp.alpha = 1;
        this.trackright.alpha = 0;
        this.trackdown.alpha = 0;
        this.trackleft.alpha = 0;
    }
    onBtnRight() {
        this.trackUp.alpha = 0;
        this.trackright.alpha = 1;
        this.trackdown.alpha = 0;
        this.trackleft.alpha = 0;
    }
    onBtnBottom() {
        this.trackUp.alpha = 0;
        this.trackright.alpha = 0;
        this.trackdown.alpha = 1;
        this.trackleft.alpha = 0;
    }
    onBtnleft() {
        this.trackUp.alpha = 0;
        this.trackright.alpha = 0;
        this.trackdown.alpha = 0;
        this.trackleft.alpha = 1;
    }

    onBtnRightTop() {
        this.trackleft.alpha = 0.0;
        this.trackdown.alpha = 0.0;

        this.trackright.alpha = 0.5;
        this.trackUp.alpha = 0.5;
    }

    onBtnRightBottom() {
        this.trackUp.alpha = 0;
        this.trackleft.alpha = 0;

        this.trackright.alpha = 0.5;
        this.trackdown.alpha = 0.5;
    }

    onBtnleftBottom() {
        this.trackUp.alpha = 0;
        this.trackright.alpha = 0;

        this.trackleft.alpha = 0.5;
        this.trackdown.alpha = 0.5;
    }

    onBtnleftTop() {
        this.trackdown.alpha = 0;
        this.trackright.alpha = 0;

        this.trackleft.alpha = 0.5;
        this.trackUp.alpha = 0.5;
    }


    public updateAnimation(vec2: Vec2) {
        //console.log('updateAnimation:', vec2);
        this.ver2Normal.x = Math.abs(vec2.x);
        this.ver2Normal.y = Math.abs(vec2.y);
        //右上
        if (vec2.x > 0 && vec2.y > 0) {
            this.trackleft.alpha = 0.0;
            this.trackdown.alpha = 0.0;

            this.trackright.alpha = this.ver2Normal.x;
            this.trackUp.alpha = clamp(this.ver2Normal.y, 0, 1 - this.ver2Normal.x);
            //右下
        } else if (vec2.x > 0 && vec2.y < 0) {
            this.trackUp.alpha = 0;
            this.trackleft.alpha = 0;

            this.trackright.alpha = this.ver2Normal.x;
            this.trackdown.alpha = clamp(this.ver2Normal.y, 0, 1 - this.ver2Normal.x);

            //左下
        } else if (vec2.x < 0 && vec2.y < 0) {
            this.trackUp.alpha = 0;
            this.trackright.alpha = 0;

            this.trackleft.alpha = this.ver2Normal.x;
            this.trackdown.alpha = clamp(this.ver2Normal.y, 0, 1 - this.ver2Normal.x);


            //左上
        } else if (vec2.x < 0 && vec2.y > 0) {
            this.trackright.alpha = 0;
            this.trackdown.alpha = 0;

            this.trackleft.alpha = this.ver2Normal.x;
            this.trackUp.alpha = clamp(this.ver2Normal.y, 0, 1 - this.ver2Normal.x);
        } else {
            this.trackUp.alpha = 0;
            this.trackright.alpha = 0;
            this.trackdown.alpha = 0;
            this.trackleft.alpha = 0;
        }

    }

    public resetAnimation() {
        this.trackUp.alpha = 0;
        this.trackright.alpha = 0;
        this.trackdown.alpha = 0;
        this.trackleft.alpha = 0;

    }

}


工程下载


http://www.kler.cn/a/415601.html

相关文章:

  • Elasticsearch与NLP的深度融合:文本嵌入与向量搜索实战指南
  • React 前端框架深度剖析
  • RabbitMQ7:消息转换器
  • 28.UE5实现对话系统
  • FBX福币交易所创业板指放量大涨2.73% 谷子经济概念持续爆发
  • TCP/IP协议攻击与防范
  • brew安装mongodb和php-mongodb扩展新手教程
  • 智启未来 扬帆5G:江苏移动打造“5G + 智慧教育”典范,引领教育新风尚
  • 个人博客接入github issue风格的评论,utteranc,gitment
  • Nuxt.js 应用中的 render:response 事件钩子
  • 【Java面试题】消息队列中,如何保证消息的顺序性?
  • SQL进阶——子查询与视图
  • Prophet时间序列算法总结及python实现案例
  • 关于Spring @Transactional事务传播机制详解
  • 前端面试题-1(详解事件循环)
  • Cesium CZML绘制Entity
  • 深入理解 MongoDB:一款灵活高效的 NoSQL 数据库
  • 2020 NHOI小学(C++)
  • C# yield 关键字
  • github通过修改hosts访问
  • RiceChem——用于评估大语言模型在教育领域自动长答卷评分 (ALAG) 的数据集
  • Elasticsearch集群如何实现高可用和一致性
  • IP与“谷子”齐飞,阅文“乘势而上”?
  • 手机镜头组如此突出,考虑恢复以前设计
  • IDEA连接Apifox客户端
  • 【Docker项目实战】使用Docker部署Paint Board在线创意画板工具