Pixi.js学习

记录学习pixi时候遇到的难一点的地方,我个人觉得我还是学得比较快的。

1.官方文档解释toLocal函数的时候,解释的不是很清楚,这里引文一篇博客加以解释:here

  个人理解:按照anysprite.toLocal(sprite_x,sprite_y)的参数形式来解释会——整个所用到的都是全局坐标,比较 anysprite与以sprite_x为基础偏移sprite_y坐标,返回坐标差值

  另外anySprite.toGlobal(postion)函数,是将anySprite的顶层容器的全局坐标计算的初始坐标原点放在postion,返回此时的anySprite的坐标。

  还有很重要一件事,如果对anySprite的大小有设置,那么会对toLocal和toGlobal函数都会造成影响,具体影响值是设定大小与原图像比例进行等比变化——比如使用toGlobal(pos),如果设定为width=100,那么偏移量放大100倍pos.x,但是原图像又是按照100的数值来进行绘制,属实迷惑了。。。

 

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
    </style>
    <script src="https://cdn.bootcss.com/pixi.js/5.2.1/pixi.min.js"></script>
    <script src="../../js/vue.min.js"></script>
</head>

<body>
    <script>
        //判断浏览器渲染引擎
        //Aliases 别名
        let Application = PIXI.Application,
            loader = PIXI.loader,
            TextureCache = PIXI.TextureCache,
            resources = PIXI.loader.resources,
            Sprite = PIXI.Sprite;
        let Rectangle = PIXI.Rectangle;

        const resolution = window.devicePixelRatio;
        let app = new Application({
            width: 600,
            height: 600,
            resolution: 1, // default: 1 分辨率
            forceCanvas: true, //强制使用canvas引擎绘制
            backgroundColor: 0x1099bb, //背景颜色
        });

        document.body.appendChild(app.view);

        let t1 = PIXI.Texture.from("./resources/三人.png")
        // tolocal演示
        let sp1 = new PIXI.Sprite(t1);
        sp1.position.set(100, 100);
        console.log(sp1.width);
        console.log(sp1.height);
        // sp1.width=503;//这里是我是用的文件原像素大小
        // sp1.height=752;

        // sp1.width=100;//设置比例,
        // sp1.height=100;
        let pt1 = new PIXI.Point(40, 40);
        // 这里多搞几层容器
        let c1 = new PIXI.Container()
        c1.addChild(sp1);
        c1.position.set(100, 100)
        app.stage.addChild(c1);

        let r1 = sp1.toGlobal(pt1) // 第二个第三个参数可以省略
        console.log(r1) // Point2 {x: 240, y: 240} 
        // 正常值应该是240,但是设定过高宽后,变为了100+width*40,100+height*40
    </script>
</body>

</html>
示例代码
复制代码

 

 

 

2.在游戏状态部分,对于角色的移动官方样例做了点优化,允许同时x,y轴移动且不冲突,同时,对代码也进行了封装优化:

 

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
    </style>
    <script src="https://cdn.bootcss.com/pixi.js/5.2.1/pixi.min.js"></script>
    <script src="../../js/vue.min.js"></script>
</head>

<body>
    <script>
        //判断浏览器渲染引擎
        //Aliases 别名
        let Application = PIXI.Application,
            loader = PIXI.loader,
            TextureCache = PIXI.TextureCache,
            resources = PIXI.loader.resources,
            Sprite = PIXI.Sprite;
        let Rectangle = PIXI.Rectangle;

        const resolution = window.devicePixelRatio;
        let app = new Application({
            width: 400,
            height: 400,
            resolution: resolution, // default: 1 分辨率
            forceCanvas: true, //强制使用canvas引擎绘制
            backgroundColor: 0x1099bb, //背景颜色
        });

        document.body.appendChild(app.view);

        //加载图像方式
        loader
            .add("./resources/三人.json")
            .on("progress", loadProgressHandler)
            .load(setup);
        // 监控加载进度
        function loadProgressHandler(loader, resource) {
            console.log("loading: " + resource.url);
            console.log("progress: " + loader.progress + "%");
        }

        var sprite, state;
        state = stop;

        let left = keyboard("ArrowLeft"),
            up = keyboard("ArrowUp"),
            right = keyboard("ArrowRight"),
            down = keyboard("ArrowDown");

        function setup() {
            //单一创建
            console.log("All files loaded");
            // 异步处理
            //读取纹理创建精灵
            let texture = resources["./resources/三人.json"].textures["角色3.png"];
            sprite = new Sprite(texture);
            sprite.position.set(300, 50);
            sprite.width = 50;
            sprite.height = 50;
            sprite.movex = 0;
            sprite.movey = 0;
            app.stage.addChild(sprite);

            setkeyboard();
            app.ticker.add(delta => gameLoop(delta));
        }

        function gameLoop(delta) {
            // sprite.x += 1;
            state(delta);
        }

        function stop() {
            //
        }

        function move() {
            sprite.x += sprite.movex;
            sprite.y += sprite.movey;
        }

        function keyboard(value) {
            let key = {};
            key.value = value;
            key.isDown = false;
            key.isUp = true;
            key.press = undefined;
            key.release = undefined;

            //按下
            key.downHandler = event => {
                if (event.key === key.value) {
                    if (key.isUp && key.press) key.press();
                    key.isDown = true;
                    key.isUp = false;
                    event.preventDefault();
                }
            }

            //按后
            key.upHandler = event => {
                if (event.key === key.value) {
                    if (key.isDown && key.value) key.release();
                    key.isDown = false;
                    key.isUp = true;
                    event.preventDefault();
                }
            }

            const downListener = key.downHandler.bind(key);
            const upListener = key.upHandler.bind(key);

            window.addEventListener(
                "keydown", downListener, false
            );

            window.addEventListener(
                "keyup", upListener, false
            );

            key.unsubscribe = () => {
                window.removeEventListener("keydown", downListener);
                window.removeEventListener("keyup", upListener);
            };
            return key;
        }

        function setkeyboard() {
            setkey(left, right, -1, 0);
            setkey(right, left, 1, 0);
            setkey(up, down, 0, -1);
            setkey(down, up, 0, 1);
        }

        function setkey(key, rkey, x, y) {
            key.press = () => {
                sprite.movex = x ? x : sprite.movex;
                sprite.movey = y ? y : sprite.movey;
                state = move;
            }
            key.release = () => {
                if (x != 0 && sprite.movex == x) sprite.movex = 0;
                if (y != 0 && sprite.movey == y) sprite.movey = 0;
                if (sprite.movex == 0 && sprite.movey == 0) state = stop;
            }
        }
    </script>
</body>

</html>
全部代码 
复制代码

  解释:

  1.初始将state定义为stop空函数

  2.在按键后将sprite的movex,movey改变,同时切换到move函数

  3.封装了setkey,对按键设置进行优化

    按键后,对当前非0指定方向变量进行赋值,同时切换move

    按起,对当前非0指定方向进行考虑,如果当前实际move值与当前按键指向相同,那么初始化move方向,同时,如果全部为0,那么切换到stop。

 

记录一份官网的寻宝猎人demo(自己的优化版本:1.碰撞时停1s;2.xy双轴同时移动)

 

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
    </style>
    <script src="https://cdn.bootcss.com/pixi.js/5.2.1/pixi.min.js"></script>
    <script src="https://www.kkkk1000.com/js/dust.js"></script>
    <script src="../js/vue.min.js"></script>
</head>

<body>
    <script>
        //判断浏览器渲染引擎
        const type = PIXI.utils.isWebGLSupported() ? "WebGL" : "canvas";
        //console.log(type);//WebGL
        // type
        console.log("🚀 ~ file: demo.html ~ line 15 ~ type", type)
        PIXI.utils.sayHello(type);

        let d = new Dust(PIXI);
        const width = window.innerWidth;
        const height = window.innerHeight;
        const resolution = window.devicePixelRatio;
        let app = new PIXI.Application({
            width: width, // default: 800 宽度
            height: height, // default: 600 高度
            resolution: resolution, // default: 1 分辨率
            forceCanvas: true, //强制使用canvas引擎绘制
            backgroundColor: 0x1099bb, //背景颜色
            antialias: true, // default: false 反锯齿
        });
        //获取舞台
        let stage = app.stage;
        //获取渲染器
        let renderer = app.renderer;

        document.body.appendChild(app.view);

        // 所有形状的绘制,都先从创建Pixi的Graphics类(Pixi.Graphics)的实例开始。
        let Graphics = PIXI.Graphics;
        let Text = PIXI.Text;
        let TextStyle = PIXI.TextStyle;

        // 矩形
        let rectangle = new Graphics();
        rectangle.beginFill(0x66CCFF); //填入颜色
        rectangle.lineStyle(4, 0xFF3300, 1); //外边框(像素宽度,颜色,透明度)
        rectangle.drawRect(0, 0, 100, 100); //进行矩形绘制
        rectangle.endFill(); // 结束绘制

        rectangle.x = 170;
        rectangle.y = 170;
        // app.stage.addChild(rectangle);


        // 文本
        let message = new Text("");
        message.position.set(0, 0);
        // app.stage.addChild(message);

        //主角
        let p1 = PIXI.Texture.from("../pixi/sprites(精灵)/imgs/角色3.png");
        let sprite = new PIXI.Sprite(p1);
        sprite.position.set(100, 100);
        sprite.width = 50;
        sprite.height = 50;
        sprite.movex = 0;
        sprite.movey = 0;
        // app.stage.addChild(sprite);

        //目标点
        let p2 = PIXI.Texture.from("../pixi/sprites(精灵)/imgs/角色2.png");
        let sprite2 = new PIXI.Sprite(p2);
        sprite2.position.set(300, 300);
        sprite2.width = 50;
        sprite2.height = 50;
        // app.stage.addChild(sprite2);

        var gamesence = new PIXI.Container();
        var gameover = new PIXI.Container();


        let message2 = new Text("GameOver , You Win");
        message2.position.set(200, 200);


        gamesence.addChild(rectangle, message, sprite2, sprite);
        gameover.addChild(message2);
        gameover.visible = false;

        app.stage.addChild(gamesence);
        app.stage.addChild(gameover);

        var state, flag;
        var int;
        state = stop;
        flag = true;

        let left = keyboard("ArrowLeft"),
            up = keyboard("ArrowUp"),
            right = keyboard("ArrowRight"),
            down = keyboard("ArrowDown");

        setkeyboard();
        startgame();

        function startgame() {
            int = setInterval(() => {
                gameLoop();
            }, 1000 / 60);
        }

        async function gameLoop() {
            // sprite.x += 1;
            console.log("gameloop");
            state();
            if (hitTestRectangle(sprite, rectangle)) {

                rectangle.tint = 0xff3300;
                // state = stop; //停止移动,关闭按键
                message.text = "碰撞! 一秒后返回原点";
                flag = false;
                console.log("碰撞了");
                clearInterval(int);
                setTimeout(() => {
                    //恢复
                    flag = true;
                    console.log("恢复");
                    sprite.position.set(100, 100);
                    startgame();
                }, 1000);
            } else if (hitTestRectangle(sprite, sprite2)) {
                message.text = "win!";
                clearInterval(int);
                setTimeout(() => {
                    gamesence.visible = false;
                    gameover.visible = true;
                }, 1000);
            } else {
                message.text = "正常移动";
                rectangle.tint = 0xccff99;
            }
        }

        function stop() {
            //
        }

        function move() {
            if (!flag)
                return;
            sprite.x += sprite.movex;
            sprite.y += sprite.movey;
        }

        function keyboard(value) {
            let key = {};
            key.value = value;
            key.isDown = false;
            key.isUp = true;
            key.press = undefined;
            key.release = undefined;

            //按下
            key.downHandler = event => {
                if (event.key === key.value) {
                    if (key.isUp && key.press) key.press();
                    key.isDown = true;
                    key.isUp = false;
                    event.preventDefault();
                }
            }

            //按后
            key.upHandler = event => {
                if (event.key === key.value) {
                    if (key.isDown && key.value) key.release();
                    key.isDown = false;
                    key.isUp = true;
                    event.preventDefault();
                }
            }

            const downListener = key.downHandler.bind(key);
            const upListener = key.upHandler.bind(key);

            window.addEventListener(
                "keydown", downListener, false
            );

            window.addEventListener(
                "keyup", upListener, false
            );

            key.unsubscribe = () => {
                window.removeEventListener("keydown", downListener);
                window.removeEventListener("keyup", upListener);
            };
            return key;
        }

        function setkeyboard() {
            setkey(left, right, -1, 0);
            setkey(right, left, 1, 0);
            setkey(up, down, 0, -1);
            setkey(down, up, 0, 1);
        }

        function setkey(key, rkey, x, y) {
            key.press = () => {
                sprite.movex = x ? x : sprite.movex;
                sprite.movey = y ? y : sprite.movey;
                state = move;
            }
            key.release = () => {
                if (x != 0 && sprite.movex == x) sprite.movex = 0;
                if (y != 0 && sprite.movey == y) sprite.movey = 0;
                if (sprite.movex == 0 && sprite.movey == 0) state = stop;
            }
        }

        function hitTestRectangle(r1, r2) {

            //Define the variables we'll need to calculate
            let hit, combinedHalfWidths, combinedHalfHeights, vx, vy;

            //hit will determine whether there's a collision
            hit = false;

            //Find the center points of each sprite
            r1.centerX = r1.x + r1.width / 2;
            r1.centerY = r1.y + r1.height / 2;
            r2.centerX = r2.x + r2.width / 2;
            r2.centerY = r2.y + r2.height / 2;

            //Find the half-widths and half-heights of each sprite
            r1.halfWidth = r1.width / 2;
            r1.halfHeight = r1.height / 2;
            r2.halfWidth = r2.width / 2;
            r2.halfHeight = r2.height / 2;

            //Calculate the distance vector between the sprites
            vx = r1.centerX - r2.centerX;
            vy = r1.centerY - r2.centerY;

            //Figure out the combined half-widths and half-heights
            combinedHalfWidths = r1.halfWidth + r2.halfWidth;
            combinedHalfHeights = r1.halfHeight + r2.halfHeight;

            //Check for a collision on the x axis
            if (Math.abs(vx) < combinedHalfWidths) {

                //A collision might be occurring. Check for a collision on the y axis
                if (Math.abs(vy) < combinedHalfHeights) {

                    //There's definitely a collision happening
                    hit = true;
                } else {

                    //There's no collision on the y axis
                    hit = false;
                }
            } else {

                //There's no collision on the x axis
                hit = false;
            }

            //`hit` will be either `true` or `false`
            return hit;
        };
    </script>
</body>

</html>
精简但陋
复制代码

 

 

 

【Over】

posted @   Renhr  阅读(314)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示