【实例学习视觉动效开发】零基础PIXI, GSAP制作刹车视觉动效| 猿创营

1,113 阅读2分钟

背景

加入猿创营(大帅老猿)有一段时间了,群内创业、兼职、学习氛围很浓,感谢大帅及群友的很多学习案例分享。为了加强学习,同时也想跟大家学习如何多输出。借助本次'第一届猿创营摸金群全员实训'机会,经过1、2天的学习,把学习到的做一个小结,希望可以帮到还未入门的同学。

本次视觉动效最终效果图

动图.gif

点击这里查看demo

所用框架(知识)

1. Pixi (资源加载及构建,渲染)

2. Gsap (动效)

本例包含元素

1. 车

2. 按钮

3. 路

4. 运动线条

所用素材

1. 主车架图

2. 操纵杆图

3. 刹车把手图

4. 按钮图

5. 圆圈图

构建开始

1.创建一个html文件,引入pixi及gsap的js文件,如下:

<script src="https://pixijs.download/release/pixi.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>

2.创建一个dom容器,如下:

<div id="brakebanner"></div>

设置宽度及居中背景css:    
<style>
    #brakebanner {
        width: 1000px;
        margin: 0 auto;
        background-color: #f8f8f8;
    }
</style>

3.写js脚本, 全部js逻辑及注释

<script>
    /**
     * 1.>创建Pixi应用和stage(舞台: 特殊Pixi容器对象, 该舞台对象将根容器来保存您希望Pixi显示的东西。)
     *
     *  如果您需要修改Pixi的默认配置,请参阅Pixi.application文档。
     *
     *  要更改画布的大小,请使用renderer的resize方法,并提供任何新的width和height值。
     *  但是,为了确保画布的大小调整到与分辨率匹配,请将autoResize设置为true。
     *
     *  本例使用固定高度 宽度. (可以参考官方文档实现自适应控制)
     *
     *  详细介绍: 请参阅[官方文档](https://pixijs.io):  https://pixijs.io
     *
     * @type {PIXI.Application}
     */
    let app = new PIXI.Application({
        width: 1000,
        height: 1000
    })

    /**
     * 设置应用背景色(格式: 0x标识的16进制颜色值, 区别css使用#开头的颜色值)
     * @type {number}
     */
    app.renderer.backgroundColor = 0xf2f2f2

    /**
     * 将Pixi自动为您创建的画布添加到HTML文档中
     */
    document.getElementById("brakebanner").appendChild(app.view)


    /**
     *  使用Pixi的Sprite类来创建精灵
     *
     *  创建方法有三种:
     *     通过单个图像文件。(本文使用该种方法创建)
     *     通过雪碧图。
     *     通过纹理贴图。
     *
     *  sprite(精灵)是一种的特殊图像对象。您可以控制它们的位置、大小和其他属性。
     *  学习制作和控制sprite(精灵)非常重要。
     */
    //按钮图片精灵
    let spriteBtn = PIXI.Sprite.from('./images/btn.png');
    //圆圈精灵
    let spriteBtnCircle = PIXI.Sprite.from('./images/btn_circle.png');
    //自行车精灵
    let spriteBrakeBike = PIXI.Sprite.from('./images/brake_bike.png');
    //控制杆精灵
    let spriteBrakeHandlerbar = PIXI.Sprite.from('./images/brake_handlerbar.png');
    //刹车把精灵
    let spriteBrakeLever = PIXI.Sprite.from('./images/brake_lever.png');

    //由于图片太大, 这里进行了缩放
    spriteBtn.scale.x               =   spriteBtn.scale.y               = 0.5;
    spriteBtnCircle.scale.x         =   spriteBtnCircle.scale.y         = 0.5;
    spriteBrakeBike.scale.x         =  spriteBrakeBike.scale.y          = 0.2;
    spriteBrakeHandlerbar.scale.x   =  spriteBrakeHandlerbar.scale.y    = 0.2;
    spriteBrakeLever.scale.x        =   spriteBrakeLever.scale.y        = 0.2;

    //调整刹车把的位置, (这里设置了固定位置)
    spriteBrakeLever.x = 170;
    spriteBrakeLever.y = 190;

    /**
     * 自行车容器 - 将车, 控制杆, 刹车把放在该容器
     * @type {PIXI.Container}
     */
    let bikeContainer = new PIXI.Container();
    bikeContainer.addChild(spriteBrakeBike);
    bikeContainer.addChild(spriteBrakeLever);
    bikeContainer.addChild(spriteBrakeHandlerbar);

    //设置该容器的位置
    bikeContainer.x = bikeContainer.y =   300;

    /**
     * 按钮容器 - 将按钮, 圆圈放在该容器
     * @type {PIXI.Container}
     */
    const btnContainer = new PIXI.Container();
    btnContainer.addChild(spriteBtn);
    btnContainer.addChild(spriteBtnCircle);

    //设置该容器位置
    btnContainer.x = -50 + app.screen.width / 2;
    btnContainer.y = -120 + app.screen.width / 2;

    //设置按钮位置
    spriteBtn.x = 9 ;
    spriteBtn.y = 9 ;

    //设置圆圈位置
    spriteBtnCircle.x = 0;
    spriteBtnCircle.y = 0;

    //创建一个红点
    let circleRed = new PIXI.Graphics();
    circleRed.beginFill(0xFF0000);
    circleRed.drawCircle(0, 0, 4);
    circleRed.endFill();
    circleRed.x = 150;
    circleRed.y = 0;

    //创建一个绿点
    let circleGreen = new PIXI.Graphics();
    circleGreen.beginFill(0x008000);
    circleGreen.drawCircle(0, 0, 4);
    circleGreen.endFill();
    circleGreen.x = 250;
    circleGreen.y = 0;

    //创建一个橘色点
    let circleOrange = new PIXI.Graphics();
    circleOrange.beginFill(0xFFA500);
    circleOrange.drawCircle(0, 0, 4);
    circleOrange.endFill();
    circleOrange.x = 350;
    circleOrange.y = 0;


    /**
     * 绘制一个矩形图形作为路
     * 作为路容器 - 将创建的三个点(用来实现运动路线效果)放在该容器
     * @type {PIXI.Container}
     */
    let rectangleRoad = new PIXI.Graphics();
    rectangleRoad.lineStyle(4, 0x008000, 1);
    rectangleRoad.beginFill(0xcccccc);
    rectangleRoad.drawRect(0, 0, 500, 2000);
    rectangleRoad.endFill();

    //将路移到中心
    rectangleRoad.x = app.screen.width / 2;
    rectangleRoad.y = app.screen.height / 2;

    //设置路的旋转中心
    rectangleRoad.pivot.x = rectangleRoad.width / 2;
    rectangleRoad.pivot.y = rectangleRoad.height / 2;

    //旋转路
    rectangleRoad.rotation = (35 * Math.PI) / 180;

    //加入三个点到路
    rectangleRoad.addChild(circleRed);
    rectangleRoad.addChild(circleGreen);
    rectangleRoad.addChild(circleOrange);


    //加入舞台
    app.stage.addChild(rectangleRoad);        //公路
    app.stage.addChild(bikeContainer);        //车容器
    app.stage.addChild(btnContainer);        //按钮容器

    /**
     *  锚点设置刹车把精灵的原点。
     *
     *  默认值是(0,0),这意味着精灵的原点是左上角。
     *  将锚点设置为(0.5,0.5)意味着精灵的原点在中间。
     *  将锚点设置为(1,1)意味着精灵的原点将是右下角。(本例设置右下角作为旋转的原点)
     * @type {number}
     */
    spriteBrakeLever.anchor.x = 1
    spriteBrakeLever.anchor.y = 1

    /**
     * 为按钮精灵启用交互事件。
     * 除非interactive设置为true,否则不会发出触摸、指针和鼠标事件。
     * @type {boolean}
     */
    spriteBtn.interactive = true;
    spriteBtn.buttonMode = true;

    /**
     * 为按钮绑定, 按下鼠标, 放开鼠标事件
     */
    spriteBtn.on('mousedown', onMusedown)
    spriteBtn.on('mouseup', onMuseup)


    /**
     * 在按钮上按下鼠标时 - 事件处理逻辑
     * @param e
     */
    function onMusedown(e) {
        //刹车把的动作动画
        gsap.to(spriteBrakeLever, {
            duration: 0.6,
            rotation: (Math.PI / 180) * -30,
        });

        //停止运动轨迹函数
        gsap.ticker.remove(gameLoop)

        //停止后, 点恢复成初始圆点
        circleRed.scale.y = 1
        circleRed.scale.x = 1
        circleGreen.scale.y = 1
        circleGreen.scale.x = 1
        circleOrange.scale.y = 1
        circleOrange.scale.x = 1
    }

    /**
     * 在按钮上松开鼠标时 - 事件处理逻辑
     * @param e
     */
    function onMuseup(e) {
        //刹车把的动作动画
        gsap.to(spriteBrakeLever, {
            duration: 0.6,
            rotation: 0,
        });
        
        //初始速度0
        speed = 0;
        
        //开始运动轨迹函数
        gsap.ticker.add(gameLoop)
    }

    //运行速度初始值
    let speed = 0.0;


    /**
     * 运动效果处理函数
     */
    function gameLoop(){
        speed += 0.5;
         
        speed = Math.min(speed, 80);

        //速度达到80时, 修改点的x,y 显示为线条样式的运动轨迹
        if(speed == 80) {
            circleRed.scale.y = 10
            circleRed.scale.x = 0.1
            circleGreen.scale.y = 10
            circleGreen.scale.x = 0.1
            circleOrange.scale.y = 10
            circleOrange.scale.x = 0.1
        }

        console.log("es=", speed)

        //增加y坐标值, 模拟运动轨迹
        if(circleRed)  circleRed.y  += speed
        if(circleGreen)  circleGreen.y  += speed
        if(circleOrange)  circleOrange.y  += speed

        //点运动到,y轴2000后, 重置y坐标值
        if(circleRed.y > 2000 ) {
            circleRed.y  = 0
            circleGreen.y  = 0
            circleOrange.y  = 0
        }
    }

    /**
     * 初始运行, 运动效果
     */
    gsap.ticker.add(gameLoop)
</script>

<<完整代码>>

资源

1. PIXI官网:pixijs.com/

2. PIXI中文:pixijs.huashengweilai.com/

3. GSAP:greensock.com/docs/v3/GSA…

4. 案例地址:www.vanmoof.com/en-NL/s3?co…

5. 代码地址: github.com/freewl/YCY-TrainingCamp-S1

不足

1. 本文为零基础入门系列, 流水账式代码结构, 仅供学习参考与模仿

2. 动画处理不够细腻, 但是作为入门学习足够, 如果您感兴趣,可以添加更多逻辑及高级功能.

作业

1. 详细阅读Pixi及Gsap文档, sample及api文档. 深入了解每个对象及方法等的用法

2. 增加按钮动画效果

3. 增加车的动画效果(运动后停止的那刻,给车加个动画效果)

4. 封装代码, 将部分代码封装共用及提高代码结构与逻辑

号外

公众号里搜 大帅老猿,在他这里可以学到很多东西