当前位置:   article > 正文

桌面宠物 ② 通过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中的代码设置

<img>标签即为展示网页宠物的内容,设置他的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. <template>
  2. <div>
  3. <img class="pet" id="pet" src="/image/pet/Idle.gif" />
  4. </div>
  5. </template>
  6. <script>
  7. import { start } from "../util/pet.js";
  8. export default {
  9. // 某些父子组件交互的值
  10. data() {
  11. return {
  12. };
  13. },
  14. mounted() {
  15. start();
  16. },
  17. methods: {},
  18. };
  19. </script>
  20. <style scoped lang="less">
  21. .pet {
  22. width: 50px;
  23. height: 65px;
  24. position: absolute;
  25. background-size: cover;
  26. }
  27. </style>

四、总结

4.1 项目百度网盘

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

提取码: hia9

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

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

4.2 总结

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/198450?site
推荐阅读
相关标签