前端——原生HTML猫猫max桌宠(附源码)

news2024/11/16 11:52:54

一、前言

看见了max大佬和狗头人大佬做的一个桌宠,于是就像用web简单实现一下

二、代码包 

https://wwwf.lanzout.com/iWfER0ze0cqd
密码:fg88

 三、简单效果

简单用了随机动作(可以进行权重设置)


四、踩坑情况

如果不是主循环loop里,这里不能用这个,会导致开启多个loop循环

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

 定时器在函数里面设置时,最好挂载到全局变量上!方便后面销毁!

1、初始化变量

2、创建定时器(在函数中) 

3、清除定时器

 ico图标和cur图标都可以在web中应用!

注意:他们的大小不能超过32x32像素 !!!

给父盒子设置了点击监听器——点击子盒子就无法触发监听器!!

解决方法:把子盒子设置为不可点击即可!!!

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

五、主页面代码

<!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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/689982.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记录--巧用 overflow-scroll 实现丝滑轮播图

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 前言: 近期我在项目中就接到了一个完成轮播图组件的需求。最开始我也像大家一样&#xff0c;直接选择使用了知名的开源项目 "Swiper"&#xff0c;但是后来发现它在移动端项目中某些测试环境…

Go的性能优化建议

前言&#xff1a; \textcolor{Green}{前言&#xff1a;} 前言&#xff1a; &#x1f49e;这个专栏就专门来记录一下寒假参加的第五期字节跳动训练营 &#x1f49e;从这个专栏里面可以迅速获得Go的知识 Go的性能优化建议 3 性能优化建议3.1 性能优化建议 - Benchmark3.2 性能优化…

一文解答危废行业信息化平台的必要性——哲讯智能科技

危险废物物联网监管系统可以通过物联网技术实现对危险废物的精准管理&#xff0c;不仅有利于提高危险废物管理水平&#xff0c;而且能够有效防范和减少重特大事故的发生&#xff0c;保障人民群众生命财产安全。利用物联网技术&#xff0c;通过传感器、无线网络、移动终端等设备…

linux CentOS 7下载步骤

1、官网地址&#xff1a;https://www.centos.org/download/ 2、 3、下载阿里云 4、下载 或minimal - 2009

08-购物车效果

先做数据&#xff0c;再做功能&#xff0c;最后界面 var goods [{pic: ./assets/g1.png,title: 椰云拿铁,desc: 1人份【年度重磅&#xff0c;一口吞云】√原创椰云topping&#xff0c;绵密轻盈到飞起&#xff01;原创瑞幸椰云™工艺&#xff0c;使用椰浆代替常规奶盖打造丰盈…

【SAS】【01】【scsi协议族】SCSI standards family

下图显示了SAM协议与SCSI协议族中其他协议标准和相关项目的关系。 SCSI Architecture Model: 定义SCSI系统模型、SCSI标准集的功能划分以及适用于所有SCSI实现和要求。Device-Type Specific Command Sets: 定义特定设备类型的实现标准&#xff0c;包括每种设备类型的设备模型。…

leetcode1884. 鸡蛋掉落-两枚鸡蛋.动态规划-java

鸡蛋掉落-两枚鸡蛋 leetcode1884. 鸡蛋掉落-两枚鸡蛋题目描述解题思路代码演示 动态规划代码演示 动态规划专题 leetcode1884. 鸡蛋掉落-两枚鸡蛋 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/egg-drop-with-2-eggs-a…

基于Python和Spacy的命名实体识别

命名实体识别&#xff08;Named Entity Recognition&#xff0c;简称NER&#xff09;是一种自然语言处理&#xff08;NLP&#xff09;方法&#xff0c;用于检测和分类文本中的命名实体&#xff0c;包括人物、组织、地点、日期、数量和其他可识别的现实世界实体。 Spacy是一个基…

STM32之HAL库微妙延迟(借助Systick)

代码 void bsp_us_delay(uint32_t us) {uint32_t start, now, delta, reload, us_tick;start SysTick->VAL;reload SysTick->LOAD;us_tick SystemCoreClock / 1000000UL;do {now SysTick->VAL;delta start > now ? start - now : reload start - now;} whi…

Element el-dropdown 事件

我这里是结合el-table一起使用 设置trigger"click" 就可以加点击事件 这里我需要点击下拉选择值后&#xff0c;既要得到下拉里面的值 也要得到这一行数据的值 重要的代码 <el-dropdowntrigger"click"command"handleCommand($event,scope.row,sc…

7 拓展中断_事件控制器(EXTI)

目录 EXTI-扩展中断和事件控制器 事件的概念 EXTI-扩展中断和事件控制器 EXTI外设框图 F1/F4/F7&#xff08;看懂与或门&#xff09; H7 STM32CubeMX中的EXTI配置 EXTI-扩展中断和事件控制器 事件的概念 STM32上许许多多的外设&#xff0c;是通过内部信号来协同工作的。…

VMware麒麟Kylin系统安装Linux

麒麟系统常用链接 https://www.jianshu.com/p/f58e2435b650 ios下载链接 https://eco.kylinos.cn/partners/mirror.html 其实基本上只有两个区别&#xff0c;一个是桌面操作系统和服务器操作系统的区别&#xff0c;一个是x86_64和arm内核的区别&#xff0c;我下的是这个海光版…

Splashtop 荣获2023年教育科技突破奖

2023年6月8日 加利福尼亚州库比蒂诺 Splashtop 在简化随处办公远程解决方案领域处于领先地位&#xff0c;该公司自豪地宣布其在教育科技突破奖评选活动中荣获“年度远程学习解决方案供应商奖”。这项在教育行业久负盛名的奖项特别关注创新性解决方案和创意公司&#xff0c;这些…

BlendOS 3 正在开发:承诺支持九个 Linux 发行版,无存储库更新

导读blendOS 发行版承诺混合 Arch Linux、Fedora Linux 和 Ubuntu&#xff0c;今年 4 月发布的 blendOS 2 使用 WayDroid&#xff0c;承诺运行 Android 应用程序。 开发商 Rudra Saraswat 表示&#xff0c;不可变发行版 blendOS 3 系统正在开发中&#xff0c;并承诺为不可变发行…

Nginx优化及防盗链

目录 一、隐藏版本号 1.查看版本号 2.修改配置文件 3.重启服务及查看版本号 二、修改用户 与组 1.修改配置文件 2.重启服务 三、缓存时间 1.修改配置文件 2.重启服务 3.测试访问 四、日志分割 1.写脚本 2.赋予执行权限并执行 3.验证 4.设置定时任务 五、连接超时 2…

ctfshow文件包含web87-117

1.web87 绕过死亡待可以使用rot13编码,还可以用base64编码,url两次编码&#xff0c;浏览器自动进行解码一次&#xff0c;代码解码一次&#xff0c;如果之编码一次&#xff0c;代码会被浏览器解码一次&#xff0c;这时候特殊字符还是url编码&#xff0c;而如php字符串则被还原&a…

扩增子高通量测序

扩增子测序是指利用合适的通用引物扩增环境中微生物的16S rDNA/18S rDNA /ITS高变区或功能基因&#xff0c;通过高通量测序技术检测PCR产物的序列变异和丰度信息&#xff0c;分析该环境下的微生物群落的多样性和分布规律&#xff0c;以揭示环境样品中微生物的种类、相对丰度、进…

人工智能数据集处理——数据清理2

目录 异常值的检测与处理 一、异常值的检测 1、使用3σ准则检测异常值 定义一个基于3σ准则检测的函数&#xff0c;使用该函数检测文件中的数据&#xff0c;并返回异常值 2、使用箱形图检测异常值 根据data.xlsx文件中的数据&#xff0c;使用boxplot()方法绘制一个箱型图 …

headscale专有网络及其ACL控制

如何使用 Headscale ( Tailscale 开源版 ) 快速搭建一个私有专属的 P2P 内网穿透网络 内网穿透简述 由于国内网络环境问题, 普遍家庭用户宽带都没有分配到公网 IP(我有固定公网 IP, 嘿嘿); 这时候一般我们需要从外部访问家庭网络时就需要通过一些魔法手段, 比如 VPN、远程软…

未来的编程语言「GitHub 热点速览」

作者&#xff1a;HelloGitHub-小鱼干 又一个编程语言火了&#xff0c;不算新&#xff0c;因为它已经开发了一段时间。不过在本周 Hacker News 上风头十足&#xff0c;DreamBerd 除了有点意思的改 ; 分隔符为 !&#xff0c;之外&#xff0c;它还能让你用问号来标注一段你也不确定…