Front end - native HTML cat cat max table pet (with source code)

I. Introduction

I saw a table pet made by the boss of Max and the boss of the Kobold, so it is like a simple realization with the web

2. Code package 

https://wwwf.lanzout.com/iWfER0ze0cqd
Password: fg88

 3. Simple effect

Simple use of random actions (weights can be set)


Fourth, the situation of stepping on the pit

If it is not in the main loop loop, this cannot be used here, which will cause multiple loop cycles to be opened

animationId = requestAnimationFrame(loop);  // 浏览器提供的 API,用于优化动画性能并在重绘之前在主线程上执行指定的函数

 When the timer is set in a function, it is best to mount it on a global variable! Convenient to destroy later!

1. Initialize variables

2. Create a timer (in a function) 

3. Clear the timer

 Both the ico icon and the cur icon can be applied in the web!

Note: their size cannot exceed 32x32 pixels! ! !

A click listener is set for the parent box - clicking on the child box will not trigger the listener! !

Solution: Set the child box to be unclickable! ! !

.cywl img {
    width: 90px;
    height: 90px;
    /* 无法选中 */
    pointer-events: none;
    user-select: none;
}

Five, the main page code

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <link rel="stylesheet" href="./index.css">
    <style>
        .cywl {
            position: fixed;
            width: 100px;
            height: 100px;
            z-index: 9999;
            left: 50px;
            bottom: 50px;
            cursor: url(./Maxwell_Who-CatCursor/alternate.ico),
                default;
            display: flex;

            /* background-color: #5ee7df; */
        }

        .cywl img {
            width: 90px;
            height: 90px;
            /* 无法选中 */
            pointer-events: none;
            user-select: none;
        }
    </style>
</head>

<body style="height: 5000px; background-image: linear-gradient(200deg, #5ee7df, #b490ca);">
    <!--宠物开始-->
    <div id="pet" class="cywl">
        <img id="pet-img" src="./max/stand1.png">
    </div>
    <!--宠物结束-->

    <script>
        // 创建 pet 对象
        const pet = {
            x: 50,   // 宠物初始位置的横坐标 (左下角开始)
            y: 50,
            vx: 1,   // 水平方向上宠物前进的速度
            vy: 0   // // 垂直方向上宠物前进的速度
        };

        // -------------------------------------------------------------动作
        // 动作权重
        // 权重问题:将所有权重相加,(得到一个大范围,那么就让随机数落到这个范围内,而对应的权重,就是落到的对应位置中)
        var actions = {
            // 普通
            walkleft: 1,
            walkright: 1,

            fish: 1,
            sleep: 1,
            kiss: 1,

            stand: 1,


        };

        // 存储宠物行走动画帧的数组
        const LeftwalkFrames = []; // 左走
        const RightwalkFrames = []; // 右走

        const DragFrames = [];  // 拖拽

        const fishFrames = [];
        const kissFrames = [];
        const sleepFrames = [];

        const standFrames = [];

        const fallingFrames = [];


        // 初始化 定时器
        var ttt = null;
        var dragTime = null;

        var action = 'stand';


        //1、将对象中的动作按照权重转换为数组。可以使用 Object.keys 方法获取对象的键,
        //2、再使用 Array.map 方法将每个键转换为对象 {name: key, weight: actions[key]}。
        //3、最后使用 Array.reduce 方法将多个对象合成一个数组
        var actionList = Object.keys(actions).map(function (key) {
            return {
                name: key,
                weight: actions[key]
            };
        }).reduce(function (prev, curr) {
            return prev.concat(curr);
        }, []);


        // 根据权重随机选择动作 
        // 权重问题:将所有权重相加,(得到一个大范围,那么就让随机数落到这个范围内,而对应的权重,就是落到的对应位置中)

        function randomAction() {
            var totalWeight = actionList.reduce(function (prev, curr) {
                return prev + curr.weight;
            }, 0);
            // console.log(totalWeight);

            var randomNum = Math.random() * totalWeight;

            for (var i = 0; i < actionList.length; i++) {
                if (randomNum <= actionList[i].weight) {
                    return actionList[i].name;
                }
                randomNum -= actionList[i].weight;
            }
        }
        // -------------------------------------------------------------动作




        const img111 = new Image();
        img111.src = `./max/falling1.png`;
        fallingFrames.push(img111);

        // 创建动画序列  
        for (let i = 1; i < 13; i++) {
            // 将行走动画帧添加到 walkFrames 数组中

            const img = new Image();
            img.src = `./max/walkright${i}.png`;
            RightwalkFrames.push(img);

            const img2 = new Image();
            img2.src = `./max/walkleft${i}.png`;
            LeftwalkFrames.push(img2);

            // 其他

            const img3 = new Image();
            img3.src = `./max/drag${i}.png`;
            DragFrames.push(img3);

            const img4 = new Image();
            img4.src = `./max/fish${i}.png`;
            fishFrames.push(img4);

            const img5 = new Image();
            img5.src = `./max/kiss${i}.png`;
            kissFrames.push(img5);

            const img6 = new Image();
            img6.src = `./max/sleep${i}.png`;
            sleepFrames.push(img6);

            const img7 = new Image();
            img7.src = `./max/stand${i}.png`;
            standFrames.push(img7);

        }

        // 绘制宠物
        function drawPet(anyFrames = RightwalkFrames) {
            const frameIndex = Math.floor(Date.now() / 100) % anyFrames.length;  // 计算当前应该绘制的动画帧的索引
            const img = anyFrames[frameIndex]; // 获取当前应该绘制的动画帧

            document.querySelector('.cywl img').src = img.src;  // 更新宠物的显示图像
        }



        // 更新宠物位置
        function updatePet() {


            pet.x += pet.vx;   // 更新宠物在水平方向的位置
            // pet.y += pet.vy;

            // 超出屏幕左边
            if (pet.x < 0) {
                action = 'walkright'
            }
            // 超出屏幕右边
            if (pet.x + petDiv.clientWidth > window.innerWidth) {
                action = 'walkleft'
            }



            petDiv.style.left = pet.x + 'px';   // 更新宠物所在 div 元素的横坐标位置
            petDiv.style.bottom = pet.y + 'px';
        }



        // ----------------------------------------------------------------------处理用户交互

        // 定位
        const petDiv = document.querySelector('#pet');
        petDiv.style.left = pet.x + 'px';   // 更新宠物所在 div 元素的横坐标位置
        petDiv.style.bottom = pet.y + 'px';

        // 禁用图片点击
        const petImg = document.querySelector('#pet-img');
        petImg.style.pointerEvents = 'none';


        var isDragging = false;   // 标记是否正在拖拽中
        var diffX = 0;    // 鼠标指针与盒子左上角的偏移量
        var diffY = 0;


        let animationId = null;


        // 鼠标按下
        petDiv.addEventListener('mousedown', function (event) {

            action = '';

            clearInterval(petTimer); // 暂停宠物行动的定时器

            // 判断鼠标是否在 div 元素内按下,并记录下偏移量
            if (event.target === petDiv) {
                isDragging = true;
                diffX = event.clientX - petDiv.offsetLeft;
                diffY = event.clientY - petDiv.offsetTop;

                // 拖拽定时器
                dragTime = setInterval(function drag() {
                    // 显示拖拽 图片
                    drawPet(DragFrames);

                    // 这里不能用这个,会导致开启多个loop
                    // animationId = requestAnimationFrame(loop);  // 浏览器提供的 API,用于优化动画性能并在重绘之前在主线程上执行指定的函数

                }, 100);

            }
        });



        // 鼠标拖动
        document.addEventListener('mousemove', function (event) {
            // 如果正在拖拽中,则更新盒子位置
            if (isDragging === true) {



                pet.x = event.clientX - diffX
                pet.y = event.clientY - diffY

                petDiv.style.left = pet.x + 'px';
                petDiv.style.top = pet.y + 'px';
            }

        });

        // 鼠标抬起
        document.addEventListener('mouseup', function (event) {
            if (isDragging === true) {

                // 清除旧的定时器
                clearInterval(ttt);
                clearInterval(dragTime);

                // 停止拖拽
                isDragging = false;

                action = 'stand';

                ttt = setInterval(function name() {
                    action = randomAction();
                }, 3000);


                // 超出屏幕 回到 指定位置 
                if (pet.y < 0 || pet.y + petDiv.clientHeight > window.innerHeight || pet.x + petDiv.clientWidth > window.innerWidth || pet.x < 0) {
                    pet.x = 500;
                    pet.y = 500;
                    const petDiv = document.querySelector('#pet');
                    petDiv.style.left = 500 + 'px';   // 更新宠物所在 div 元素的位置
                    petDiv.style.top = 500 + 'px';
                    // console.log(1111111)
                }


                // 显示下落 图片
                drawPet(fallingFrames);
                // animationId = requestAnimationFrame(loop);  // 浏览器提供的 API,用于优化动画性能并在重绘之前在主线程上执行指定的函数

                // loop();
            }

        });

        // 宠物行动的定时器,每 3 秒执行一次 doAction 函数
        var petTimer = setInterval(function name() {
            action = randomAction();
        }, 3000);




        // ----------------------------------------------------------------------
        // 主循环
        function loop() {


            console.log(action);
            if (action == 'walkleft') {
                // 执行 leftwalk 动作
                pet.vx = -0.5;
                updatePet();
                drawPet(LeftwalkFrames);

            }

            if (action == 'walkright') {
                pet.vx = 0.5;
                updatePet();
                drawPet(RightwalkFrames);

            }

            if (action == 'fish') {
                // updatePet();
                drawPet(fishFrames);

            }

            if (action == 'kiss') {
                // updatePet();
                drawPet(kissFrames);

            }

            if (action == 'sleep') {
                // updatePet();
                drawPet(sleepFrames);

            }

            if (action == 'stand') {
                // updatePet();
                drawPet(standFrames);

            }
            requestAnimationFrame(loop);  // 浏览器提供的 API,用于优化动画性能并在重绘之前在主线程上执行指定的函数
        }

        // 启动循环
        loop();
    </script>
</body>

</html>

Guess you like

Origin blog.csdn.net/Pan_peter/article/details/131264676