• 桌面宠物 ② 通过js制作属于自己的web网页宠物


    一、网页宠物素材

    1.1 需要准备什么素材

    桌面宠物 ① 通过python制作属于自己的桌面宠物_林林zonzon的博客-CSDN博客_python桌面宠物同前一篇文章一样,web网页宠物的动画效果的实现,也是由一个个GIF图拼接而成,我们需要准备多组GIF动图来实现网页宠物的动作切换。

    1.2 素材的获取方法

    ① 素材网站:爱给网、素材巷等。

    ② 通过ps、pr自己制作 :pr制作选择视频输出为GIF图即可,ps则需要一帧一帧的找静态图拼接到一起,具体操作流程看上篇。

    ③ 通过淘宝购买:【淘宝某些商家的资源挺坑的】

    二、js实现代码

    2.1 目录结构

    项目的目录结构如下,其中index.html为可以打开的网页。

     img下的GIF图片是网页宠物对应的可切换动作,这里就放了4个,分别为Attack攻击动画、Hit受击动画、Idle待机动画、Walk行走动画。

     class下的pet.js就是网页宠物的行为逻辑设置。

    2.2 实现代码

    2.2.1 index.html中的代码设置

    标签即为展示网页宠物的内容,设置他的class和id名都为pet,src为其读取的资源路径,默认读取idle(待机)的GIF图片

    1. <div>
    2. <img class="pet" id="pet" src="./img/Idle.gif" />
    3. div>

     script下引入对应的JS文件

    <script src="./class/pet.js" type="text/javascript">script>

     style下设置网页宠物的展示样式

    1. .pet {
    2. width: 50px;
    3. height: 65px;
    4. position: absolute;
    5. background-size: cover;
    6. }

    2.2.2 实现功能

    这次的网页宠物实现的功能为:平常处于待机动画状态,在点击宠物后,宠物播放受击动画,然后开始追逐鼠标,追逐到后执行攻击动画,攻击动画执行完毕后恢复待机状态。

    ① 宠物元素设置

    首先通过getElementById,根据id获取对应image的相关属性

    1. // 获取宠物元素
    2. let pet = document.getElementById('pet');

    定义旋转角度,宠物位置、鼠标位置、移动次数来实现宠物追逐鼠标时候位置方向的旋转移动。

    1. // 旋转角度
    2. let deg = 0;
    3. // 旋转角度Y
    4. let deg_y = 0;
    5. // 记录宠物位置
    6. let position = {
    7. x: 0,
    8. y: 0,
    9. }
    10. // 记录宠物距离鼠标需要移动的距离
    11. let mousePosition = {
    12. x: 0,
    13. y: 0,
    14. }
    15. // 记录当前移动次数
    16. let count = 0;
    17. // 宠物移动到鼠标位置,所需要的次数
    18. let speed = 50;

    定义相关状态,与动画切换时间,实现状态切换和动画播放

    1. // 是否处于追逐状态
    2. let isCatchUp = false;
    3. // 是否处于点击状态
    4. let isClick = false;
    5. // 是否处于待机状态
    6. let isIdle = true;
    7. // 攻击动画状态记录
    8. let attack = {
    9. // 当前帧
    10. current: 0,
    11. // 持续时间
    12. max: 340,
    13. }
    14. // 点击动画状态记录
    15. let click = {
    16. current: 0,
    17. max: 40
    18. }
    19. // 行走动画状态记录
    20. let walk = {
    21. current: 0,
    22. max: 130
    23. }

    ② 鼠标点击的监听事件,将其设置为点击状态

    1. // 点击事件监听
    2. document.getElementById("pet").onclick = function () {
    3. isClick = true;
    4. };

    ③ 监听鼠标移动事件

            首先通过当前鼠标位置-当前宠物距离浏览器左边的距离-宠物宽度的中心位置的方式算出需要移动的距离mousePosition;

            通过相关公式算出需要翻转的角度deg;

            判断鼠标当时的落点与宠物离浏览器左边距离的关系,根据你GIF图的朝向调整是大于还是小于;

            最后将count计数清零,因为每一次鼠标移动都需要重新计算鼠标距离。

    1. // 鼠标移动事件处理
    2. window.addEventListener('mousemove', function (event) {
    3. // 需要移动的x轴距离 = 当前鼠标位置-距离浏览器左边的距离-宠物相对于浏览器页面宽度/2(宽的中心位置)
    4. mousePosition.x = event.x - pet.offsetLeft - pet.clientWidth / 2;
    5. mousePosition.y = event.y - pet.offsetTop - pet.clientHeight / 2;
    6. // 需要的旋转角度计算
    7. deg = 360 * Math.atan(mousePosition.y / mousePosition.x) / (2 * Math.PI);
    8. // 这里的event.clientX 返回当事件被触发时鼠标指针相对于浏览器页面(或客户区)的水平坐标。
    9. // 这里有关于图片位置的设置,注意你的gif图的方向,原图方向向左,那么这里就是小于,原图方向向右,这里就是大于。
    10. // 翻转图片
    11. if (pet.offsetLeft > event.clientX) {
    12. deg_y = - 180;
    13. } else {
    14. deg_y = 0;
    15. }
    16. //这里每一次移动鼠标都要重新计算距离,所以这里的count需要清零
    17. count = 0;
    18. })

    ④ 宠物更新状态事件,网页宠物的动作切换流程,主体由setInterval完成,setInterval为一个不断执行的定时函数,每过10毫秒循环执行。

    1. // 每过10毫秒,循环执行
    2. setInterval(() => {
    3. // 处于追逐鼠标状态
    4. if (isCatchUp == false && isIdle == false) {
    5. catchUpState();
    6. }
    7. // 处于攻击状态
    8. else if (isCatchUp == true && isIdle == false) {
    9. attackState();
    10. }
    11. // 处于点击状态
    12. else if (isClick == true) {
    13. clickState();
    14. }
    15. }
    16. , 10)

    ⑤ 鼠标追逐状态 catchUpState()

    用walk.current模拟GIF播放的当前帧,walk.max模拟GIF图的一次播放时间。  walk.current = 1 就相当于GIF播放到第1帧。

    1. function catchUpState() {
    2. // 准备播放追逐状态动画
    3. if (walk.current == 0) {
    4. (1)......
    5. }
    6. // 开始播放追逐状态GIF
    7. else if (walk.current < walk.max) {
    8. (2)......
    9. }
    10. // 结束播放追逐状态GIF,同时开始重新播放追逐状态GIF图
    11. else if (walk.current >= walk.max) {
    12. (3)......
    13. }
    14. }

     (1)在current等于0时,切换成需要的GIF图,并根据你自己GIF图的大小决定调整情况,最后current++。

    1. // 此时宠物为追逐状态,gif图切换为walk.gif
    2. document.getElementById("pet").src = "./img/Walk.gif"
    3. // 因为不同的GIF图对应的宽高可能有差别,需要调整的可以在这里调整
    4. pet.style.width = 50 + "px"
    5. // 当前动画帧+1
    6. walk.current++

    (2)在current>0而小于设定的max时 ,就执行当前状态下的一些操作。

    walk状态下,首先根据我们在鼠标监听事件中获取的deg调整宠物旋转角度。

    1. // 调整宠物角度
    2. pet.style.transform = "rotateZ(" + deg + "deg) rotateY(" + deg_y + "deg)"

    然后再通过count和speed的大小判断宠物是否到达鼠标位置,没到达就改变宠物对应的位置,到达就调整宠物状态。【speed为我们设定的需要移动距离的份数,count为当前移动距离的份数】

    1. // 如果没追到鼠标
    2. if (count < speed) {
    3. // position.x和y分别记录当前宠物的横纵坐标位置
    4. // 此时的横纵坐标位置,通过+=的方式移过去,speed越大,移动速度越慢
    5. // 相当于将两点之间的位置分为speed份,每一次刷新移动一份的距离
    6. position.x += mousePosition.x / speed
    7. position.y += mousePosition.y / speed
    8. }
    9. // 追到鼠标
    10. else {
    11. // 改变状态
    12. isCatchUp = true
    13. }

     最后改变宠物实际的样式属性,实现宠物的移动。

    1. // 实际的画出当前的宠物位置
    2. pet.style.left = position.x + "px"
    3. pet.style.top = position.y + "px"
    4. count++
    5. walk.current++;

    (3)在current>=max时,即是行走动画播放完毕,在walk状态下,如果没有追逐到鼠标,将会继续循环播放walk.gif动画。

    1. //当前帧归零
    2. walk.current = 0;
    3. //继续播放walk.gif图片
    4. document.getElementById("pet").src = "./img/Walk.gif"

    ⑥ 宠物攻击状态 attackState(),这里的逻辑和上面的逻辑是一样的,就不过多讲述了。

    1. function attackState() {
    2. // 准备播放攻击状态动画
    3. if (attack.current == 0) {
    4. // 调整播放的动画
    5. document.getElementById("pet").src = "./img/Attack.gif"
    6. pet.style.width = 100 + "px"
    7. attack.current++
    8. }
    9. // 开始播放攻击状态动画,这里可以拓展在某些帧(current计数)的时候设置攻击范围和攻击处理函数之类的
    10. else if (attack.current < attack.max) {
    11. attack.current++;
    12. }
    13. // 结束播放攻击动画,改变对应状态,播放待机动画。
    14. else if (attack.current >= attack.max) {
    15. // 将动画设置复原
    16. isCatchUp = false;
    17. isIdle = true;
    18. attack.current = 0;
    19. document.getElementById("pet").src = "./img/Idle.gif"
    20. pet.style.width = 50 + "px"
    21. }
    22. }

     ⑦ 宠物点击状态 clickState()

    1. function clickState() {
    2. // 准备播放受击动画
    3. if (click.current == 0) {
    4. document.getElementById("pet").src = "./img/Hit.gif"
    5. pet.style.width = 60 + "px"
    6. click.current++
    7. }
    8. // 开始播放受击动画,可以在这里面处理对应受击动作函数
    9. else if (click.current < click.max) {
    10. click.current++;
    11. }
    12. // 结束播放受击动画,改变状态,播放行走动画
    13. else if (click.current >= click.max) {
    14. click.current = 0;
    15. document.getElementById("pet").src = "./img/Walk.gif"
    16. pet.style.width = 50 + "px"
    17. isClick = false;
    18. isIdle = false;
    19. }
    20. }

    2.3 完整源码

    2.3.1 index.html

    1. DOCTYPE html>
    2. <html lang="en">
    3. <body>
    4. <div>
    5. <img class="pet" id="pet" src="./img/Idle.gif" />
    6. div>
    7. body>
    8. <script src="./class/pet.js" type="text/javascript">script>
    9. <style>
    10. .pet {
    11. width: 50px;
    12. height: 65px;
    13. position: absolute;
    14. background-size: cover;
    15. }
    16. style>
    17. html>

    2.3.2 pet.js

    1. // 获取宠物元素
    2. let pet = document.getElementById('pet');
    3. // 旋转角度
    4. let deg = 0;
    5. // 旋转角度Y
    6. let deg_y = 0;
    7. // 记录宠物距离鼠标需要移动的距离
    8. let mousePosition = {
    9. x: 0,
    10. y: 0,
    11. }
    12. // 记录宠物位置
    13. let position = {
    14. x: 0,
    15. y: 0,
    16. }
    17. // 记录当前移动次数
    18. let count = 0;
    19. // 宠物移动到鼠标位置,所需要的次数
    20. let speed = 50;
    21. // 是否处于追逐状态
    22. let isCatchUp = false;
    23. // 是否处于点击状态
    24. let isClick = false;
    25. // 是否处于待机状态
    26. let isIdle = true;
    27. // 攻击动画状态记录
    28. let attack = {
    29. // 当前帧
    30. current: 0,
    31. // 持续时间
    32. max: 340,
    33. }
    34. // 点击动画状态记录
    35. let click = {
    36. current: 0,
    37. max: 40
    38. }
    39. // 行走动画状态记录
    40. let walk = {
    41. current: 0,
    42. max: 130
    43. }
    44. // 点击事件处理
    45. document.getElementById("pet").onclick = function () {
    46. isClick = true;
    47. };
    48. // 鼠标移动事件处理
    49. window.addEventListener('mousemove', function (event) {
    50. // 期望图片移动到的鼠标x轴位置 = 当前鼠标位置-距离浏览器左边的距离-宠物相对于浏览器页面宽度/2(宽的中心位置)
    51. mousePosition.x = event.x - pet.offsetLeft - pet.clientWidth / 2;
    52. mousePosition.y = event.y - pet.offsetTop - pet.clientHeight / 2;
    53. // 旋转角度
    54. deg = 360 * Math.atan(mousePosition.y / mousePosition.x) / (2 * Math.PI);
    55. // clientX 事件属性返回当事件被触发时鼠标指针相对于浏览器页面(或客户区)的水平坐标。
    56. // 这里有关于图片位置的设置,注意你的gif图的方向,原图方向向左,那么这里就是小于,原图方向向右,这里就是大于。
    57. // 翻转图片
    58. if (pet.offsetLeft > event.clientX) {
    59. deg_y = - 180;
    60. } else {
    61. deg_y = 0;
    62. }
    63. //这里每一次移动鼠标都要重新计算距离,所以这里的count需要清零
    64. count = 0;
    65. })
    66. // 每过10毫秒,循环执行
    67. setInterval(() => {
    68. // 处于追逐鼠标状态
    69. if (isCatchUp == false && isIdle == false) {
    70. catchUpState();
    71. }
    72. // 处于攻击状态
    73. else if (isCatchUp == true && isIdle == false) {
    74. attackState();
    75. }
    76. // 处于点击状态
    77. else if (isClick == true) {
    78. clickState();
    79. }
    80. }
    81. , 10)
    82. function catchUpState() {
    83. // 准备播放追逐状态动画
    84. if (walk.current == 0) {
    85. // 此时宠物为追逐状态,gif图切换为walk.gif
    86. document.getElementById("pet").src = "./img/Walk.gif"
    87. // 因为不同的GIF图对应的宽高可能有差别,需要调整的可以在这里调整
    88. pet.style.width = 50 + "px"
    89. // 当前动画帧+1
    90. walk.current++
    91. }
    92. // 开始播放追逐状态GIF
    93. else if (walk.current < walk.max) {
    94. // 调整宠物角度
    95. pet.style.transform = "rotateZ(" + deg + "deg) rotateY(" + deg_y + "deg)"
    96. // 如果没追到鼠标
    97. if (count < speed) {
    98. // position.x和y分别记录当前宠物的横纵坐标位置
    99. // 此时的横纵坐标位置,通过+=的方式移过去,speed越大,移动速度越慢
    100. // 相当于将两点之间的位置分为speed份,每一次刷新移动一份的距离
    101. position.x += mousePosition.x / speed
    102. position.y += mousePosition.y / speed
    103. }
    104. // 追到鼠标
    105. else {
    106. // 改变状态
    107. isCatchUp = true
    108. walk.current = 0
    109. }
    110. // 实际的画出当前的宠物位置
    111. pet.style.left = position.x + "px"
    112. pet.style.top = position.y + "px"
    113. count++
    114. walk.current++;
    115. }
    116. // 结束播放追逐状态GIF,同时开始重新播放追逐状态GIF图
    117. else if (walk.current >= walk.max) {
    118. walk.current = 0;
    119. document.getElementById("pet").src = "./img/Walk.gif"
    120. }
    121. }
    122. function attackState() {
    123. // 准备播放攻击状态动画
    124. if (attack.current == 0) {
    125. // 调整播放的动画
    126. document.getElementById("pet").src = "./img/Attack.gif"
    127. pet.style.width = 100 + "px"
    128. attack.current++
    129. }
    130. // 开始播放攻击状态动画,这里可以拓展在某些帧(current计数)的时候设置攻击范围和攻击处理函数之类的
    131. else if (attack.current < attack.max) {
    132. attack.current++;
    133. }
    134. // 结束播放攻击动画,改变对应状态,播放待机动画。
    135. else if (attack.current >= attack.max) {
    136. // 将动画设置复原
    137. isCatchUp = false;
    138. isIdle = true;
    139. attack.current = 0;
    140. document.getElementById("pet").src = "./img/Idle.gif"
    141. pet.style.width = 50 + "px"
    142. }
    143. }
    144. function clickState() {
    145. // 准备播放受击动画
    146. if (click.current == 0) {
    147. document.getElementById("pet").src = "./img/Hit.gif"
    148. pet.style.width = 60 + "px"
    149. click.current++
    150. }
    151. // 开始播放受击动画,可以在这里面处理对应受击动作函数
    152. else if (click.current < click.max) {
    153. click.current++;
    154. }
    155. // 结束播放受击动画,改变状态,播放行走动画
    156. else if (click.current >= click.max) {
    157. click.current = 0;
    158. document.getElementById("pet").src = "./img/Walk.gif"
    159. pet.style.width = 50 + "px"
    160. isClick = false;
    161. isIdle = false;
    162. }
    163. }

    三、在vue项目中展示网页宠物

    做这个东西主要还是想把他放在自己的个人网站上面,让网站内容不至于过于空虚。放在vue上面的话,大体没啥问题,主要是注意放的位置就欧克了,建议放在绝对路径里面。

    3.1 资源位置

    这里资源放置的路径,建议将宠物的GIF图片放在项目public下面的文件夹中,不然可能无法正常加载。

     .js文件和.vue文件同正常一样即可。

    3.2 pet.js代码

    将整个js代码用一个函数start包起来,然后每个涉及到图片地址的用public下的绝对路径代替即可。

    1. export function start() {
    2. let pet = document.getElementById('pet');
    3. ......
    4. function catchUpState() {
    5. if (walk.current == 0) {
    6. // document.getElementById("pet").src = "./img/Walk.gif"
    7. document.getElementById("pet").src = "/image/pet/Walk.gif"
    8. ......
    9. }
    10. ......
    11. }

    3.3 vue界面代码

    引入pet.js里面的start方法,这个需要在mounted里面初始化,不能放在created()里面进行初始化,不然会报错。

    1. <script>
    2. import { start } from "../util/pet.js";
    3. export default {
    4. // 某些父子组件交互的值
    5. data() {
    6. return {
    7. };
    8. },
    9. mounted() {
    10. start();
    11. },
    12. methods: {},
    13. };
    14. script>
    15. <style scoped lang="less">
    16. .pet {
    17. width: 50px;
    18. height: 65px;
    19. position: absolute;
    20. background-size: cover;
    21. }
    22. style>

    四、总结

    4.1 项目百度网盘

    百度网盘链接: https://pan.baidu.com/s/1585QjxSWWdX2eOXXECGpVg

    提取码: hia9

    vue为vue项目上更改过的文件

    webpet则是可以直接打开index.html的文件

    4.2 总结

    还有很多等待优化的地方,只是一个小小的demo,做着玩的,不过收获的确很多。可能有些地方会出现问题,有问题私信或者评论区留言,咱们共同探讨🐵

  • 相关阅读:
    项目管理之立项TG0
    单调队列 → 常用于动态规划问题的优化
    MACOS查看硬盘读写量
    redission
    数据结构与算法(一)线性结构篇
    电脑硬件——CPU散热器
    【CKA考试笔记】十九、master的负载均衡及高可用
    C++学习(2):分配器allocator
    13-ES5和ES6基础
    Pytest测试框架搭建的关键6个知识点(建议收藏)
  • 原文地址:https://blog.csdn.net/zujiasheng/article/details/126711017