赞
踩
桌面宠物 ① 通过python制作属于自己的桌面宠物_林林zonzon的博客-CSDN博客_python桌面宠物同前一篇文章一样,web网页宠物的动画效果的实现,也是由一个个GIF图拼接而成,我们需要准备多组GIF动图来实现网页宠物的动作切换。
① 素材网站:爱给网、素材巷等。
② 通过ps、pr自己制作 :pr制作选择视频输出为GIF图即可,ps则需要一帧一帧的找静态图拼接到一起,具体操作流程看上篇。
③ 通过淘宝购买:【淘宝某些商家的资源挺坑的】
项目的目录结构如下,其中index.html为可以打开的网页。
img下的GIF图片是网页宠物对应的可切换动作,这里就放了4个,分别为Attack攻击动画、Hit受击动画、Idle待机动画、Walk行走动画。
class下的pet.js就是网页宠物的行为逻辑设置。
<img>标签即为展示网页宠物的内容,设置他的class和id名都为pet,src为其读取的资源路径,默认读取idle(待机)的GIF图片
- <div>
- <img class="pet" id="pet" src="./img/Idle.gif" />
- </div>
script下引入对应的JS文件
<script src="./class/pet.js" type="text/javascript"></script>
style下设置网页宠物的展示样式
- .pet {
- width: 50px;
- height: 65px;
- position: absolute;
- background-size: cover;
- }
这次的网页宠物实现的功能为:平常处于待机动画状态,在点击宠物后,宠物播放受击动画,然后开始追逐鼠标,追逐到后执行攻击动画,攻击动画执行完毕后恢复待机状态。
① 宠物元素设置
首先通过getElementById,根据id获取对应image的相关属性
- // 获取宠物元素
- let pet = document.getElementById('pet');
定义旋转角度,宠物位置、鼠标位置、移动次数来实现宠物追逐鼠标时候位置方向的旋转移动。
- // 旋转角度
- let deg = 0;
- // 旋转角度Y
- let deg_y = 0;
- // 记录宠物位置
- let position = {
- x: 0,
- y: 0,
- }
- // 记录宠物距离鼠标需要移动的距离
- let mousePosition = {
- x: 0,
- y: 0,
- }
- // 记录当前移动次数
- let count = 0;
- // 宠物移动到鼠标位置,所需要的次数
- let speed = 50;
定义相关状态,与动画切换时间,实现状态切换和动画播放
- // 是否处于追逐状态
- let isCatchUp = false;
- // 是否处于点击状态
- let isClick = false;
- // 是否处于待机状态
- let isIdle = true;
-
- // 攻击动画状态记录
- let attack = {
- // 当前帧
- current: 0,
- // 持续时间
- max: 340,
- }
- // 点击动画状态记录
- let click = {
- current: 0,
- max: 40
- }
- // 行走动画状态记录
- let walk = {
- current: 0,
- max: 130
- }
② 鼠标点击的监听事件,将其设置为点击状态
- // 点击事件监听
- document.getElementById("pet").onclick = function () {
- isClick = true;
- };
③ 监听鼠标移动事件
首先通过当前鼠标位置-当前宠物距离浏览器左边的距离-宠物宽度的中心位置的方式算出需要移动的距离mousePosition;
通过相关公式算出需要翻转的角度deg;
判断鼠标当时的落点与宠物离浏览器左边距离的关系,根据你GIF图的朝向调整是大于还是小于;
最后将count计数清零,因为每一次鼠标移动都需要重新计算鼠标距离。
- // 鼠标移动事件处理
- window.addEventListener('mousemove', function (event) {
- // 需要移动的x轴距离 = 当前鼠标位置-距离浏览器左边的距离-宠物相对于浏览器页面宽度/2(宽的中心位置)
- mousePosition.x = event.x - pet.offsetLeft - pet.clientWidth / 2;
- mousePosition.y = event.y - pet.offsetTop - pet.clientHeight / 2;
- // 需要的旋转角度计算
- deg = 360 * Math.atan(mousePosition.y / mousePosition.x) / (2 * Math.PI);
- // 这里的event.clientX 返回当事件被触发时鼠标指针相对于浏览器页面(或客户区)的水平坐标。
- // 这里有关于图片位置的设置,注意你的gif图的方向,原图方向向左,那么这里就是小于,原图方向向右,这里就是大于。
- // 翻转图片
- if (pet.offsetLeft > event.clientX) {
- deg_y = - 180;
- } else {
- deg_y = 0;
- }
- //这里每一次移动鼠标都要重新计算距离,所以这里的count需要清零
- count = 0;
- })
④ 宠物更新状态事件,网页宠物的动作切换流程,主体由setInterval完成,setInterval为一个不断执行的定时函数,每过10毫秒循环执行。
- // 每过10毫秒,循环执行
- setInterval(() => {
- // 处于追逐鼠标状态
- if (isCatchUp == false && isIdle == false) {
- catchUpState();
- }
- // 处于攻击状态
- else if (isCatchUp == true && isIdle == false) {
- attackState();
- }
- // 处于点击状态
- else if (isClick == true) {
- clickState();
- }
- }
- , 10)
⑤ 鼠标追逐状态 catchUpState()
用walk.current模拟GIF播放的当前帧,walk.max模拟GIF图的一次播放时间。 walk.current = 1 就相当于GIF播放到第1帧。
- function catchUpState() {
- // 准备播放追逐状态动画
- if (walk.current == 0) {
- (1)......
- }
- // 开始播放追逐状态GIF
- else if (walk.current < walk.max) {
- (2)......
- }
- // 结束播放追逐状态GIF,同时开始重新播放追逐状态GIF图
- else if (walk.current >= walk.max) {
- (3)......
- }
-
- }
(1)在current等于0时,切换成需要的GIF图,并根据你自己GIF图的大小决定调整情况,最后current++。
- // 此时宠物为追逐状态,gif图切换为walk.gif
- document.getElementById("pet").src = "./img/Walk.gif"
- // 因为不同的GIF图对应的宽高可能有差别,需要调整的可以在这里调整
- pet.style.width = 50 + "px"
- // 当前动画帧+1
- walk.current++
(2)在current>0而小于设定的max时 ,就执行当前状态下的一些操作。
walk状态下,首先根据我们在鼠标监听事件中获取的deg调整宠物旋转角度。
- // 调整宠物角度
- pet.style.transform = "rotateZ(" + deg + "deg) rotateY(" + deg_y + "deg)"
然后再通过count和speed的大小判断宠物是否到达鼠标位置,没到达就改变宠物对应的位置,到达就调整宠物状态。【speed为我们设定的需要移动距离的份数,count为当前移动距离的份数】
- // 如果没追到鼠标
- if (count < speed) {
- // position.x和y分别记录当前宠物的横纵坐标位置
- // 此时的横纵坐标位置,通过+=的方式移过去,speed越大,移动速度越慢
- // 相当于将两点之间的位置分为speed份,每一次刷新移动一份的距离
- position.x += mousePosition.x / speed
- position.y += mousePosition.y / speed
- }
- // 追到鼠标
- else {
- // 改变状态
- isCatchUp = true
- }
最后改变宠物实际的样式属性,实现宠物的移动。
- // 实际的画出当前的宠物位置
- pet.style.left = position.x + "px"
- pet.style.top = position.y + "px"
- count++
- walk.current++;
(3)在current>=max时,即是行走动画播放完毕,在walk状态下,如果没有追逐到鼠标,将会继续循环播放walk.gif动画。
- //当前帧归零
- walk.current = 0;
- //继续播放walk.gif图片
- document.getElementById("pet").src = "./img/Walk.gif"
⑥ 宠物攻击状态 attackState(),这里的逻辑和上面的逻辑是一样的,就不过多讲述了。
- function attackState() {
- // 准备播放攻击状态动画
- if (attack.current == 0) {
- // 调整播放的动画
- document.getElementById("pet").src = "./img/Attack.gif"
- pet.style.width = 100 + "px"
- attack.current++
- }
- // 开始播放攻击状态动画,这里可以拓展在某些帧(current计数)的时候设置攻击范围和攻击处理函数之类的
- else if (attack.current < attack.max) {
- attack.current++;
- }
- // 结束播放攻击动画,改变对应状态,播放待机动画。
- else if (attack.current >= attack.max) {
- // 将动画设置复原
- isCatchUp = false;
- isIdle = true;
- attack.current = 0;
- document.getElementById("pet").src = "./img/Idle.gif"
- pet.style.width = 50 + "px"
-
- }
-
- }
⑦ 宠物点击状态 clickState()
- function clickState() {
- // 准备播放受击动画
- if (click.current == 0) {
- document.getElementById("pet").src = "./img/Hit.gif"
- pet.style.width = 60 + "px"
- click.current++
- }
- // 开始播放受击动画,可以在这里面处理对应受击动作函数
- else if (click.current < click.max) {
- click.current++;
- }
- // 结束播放受击动画,改变状态,播放行走动画
- else if (click.current >= click.max) {
- click.current = 0;
- document.getElementById("pet").src = "./img/Walk.gif"
- pet.style.width = 50 + "px"
- isClick = false;
- isIdle = false;
- }
-
-
- }
- <!DOCTYPE html>
- <html lang="en">
- <body>
- <div>
- <img class="pet" id="pet" src="./img/Idle.gif" />
- </div>
- </body>
-
- <script src="./class/pet.js" type="text/javascript"></script>
- <style>
- .pet {
- width: 50px;
- height: 65px;
- position: absolute;
- background-size: cover;
- }
- </style>
- </html>
- // 获取宠物元素
- let pet = document.getElementById('pet');
- // 旋转角度
- let deg = 0;
- // 旋转角度Y
- let deg_y = 0;
- // 记录宠物距离鼠标需要移动的距离
- let mousePosition = {
- x: 0,
- y: 0,
- }
- // 记录宠物位置
- let position = {
- x: 0,
- y: 0,
- }
-
- // 记录当前移动次数
- let count = 0;
- // 宠物移动到鼠标位置,所需要的次数
- let speed = 50;
-
- // 是否处于追逐状态
- let isCatchUp = false;
- // 是否处于点击状态
- let isClick = false;
-
- // 是否处于待机状态
- let isIdle = true;
-
- // 攻击动画状态记录
- let attack = {
- // 当前帧
- current: 0,
- // 持续时间
- max: 340,
- }
- // 点击动画状态记录
- let click = {
- current: 0,
- max: 40
- }
-
- // 行走动画状态记录
- let walk = {
- current: 0,
- max: 130
- }
-
- // 点击事件处理
- document.getElementById("pet").onclick = function () {
- isClick = true;
- };
-
- // 鼠标移动事件处理
- window.addEventListener('mousemove', function (event) {
-
- // 期望图片移动到的鼠标x轴位置 = 当前鼠标位置-距离浏览器左边的距离-宠物相对于浏览器页面宽度/2(宽的中心位置)
- mousePosition.x = event.x - pet.offsetLeft - pet.clientWidth / 2;
- mousePosition.y = event.y - pet.offsetTop - pet.clientHeight / 2;
- // 旋转角度
- deg = 360 * Math.atan(mousePosition.y / mousePosition.x) / (2 * Math.PI);
- // clientX 事件属性返回当事件被触发时鼠标指针相对于浏览器页面(或客户区)的水平坐标。
- // 这里有关于图片位置的设置,注意你的gif图的方向,原图方向向左,那么这里就是小于,原图方向向右,这里就是大于。
- // 翻转图片
- if (pet.offsetLeft > event.clientX) {
- deg_y = - 180;
- } else {
- deg_y = 0;
- }
- //这里每一次移动鼠标都要重新计算距离,所以这里的count需要清零
- count = 0;
- })
-
-
- // 每过10毫秒,循环执行
- setInterval(() => {
- // 处于追逐鼠标状态
- if (isCatchUp == false && isIdle == false) {
- catchUpState();
- }
- // 处于攻击状态
- else if (isCatchUp == true && isIdle == false) {
- attackState();
- }
- // 处于点击状态
- else if (isClick == true) {
- clickState();
- }
- }
- , 10)
-
- function catchUpState() {
- // 准备播放追逐状态动画
- if (walk.current == 0) {
- // 此时宠物为追逐状态,gif图切换为walk.gif
- document.getElementById("pet").src = "./img/Walk.gif"
- // 因为不同的GIF图对应的宽高可能有差别,需要调整的可以在这里调整
- pet.style.width = 50 + "px"
- // 当前动画帧+1
- walk.current++
- }
- // 开始播放追逐状态GIF
- else if (walk.current < walk.max) {
- // 调整宠物角度
- pet.style.transform = "rotateZ(" + deg + "deg) rotateY(" + deg_y + "deg)"
- // 如果没追到鼠标
- if (count < speed) {
- // position.x和y分别记录当前宠物的横纵坐标位置
- // 此时的横纵坐标位置,通过+=的方式移过去,speed越大,移动速度越慢
- // 相当于将两点之间的位置分为speed份,每一次刷新移动一份的距离
- position.x += mousePosition.x / speed
- position.y += mousePosition.y / speed
- }
- // 追到鼠标
- else {
- // 改变状态
- isCatchUp = true
- walk.current = 0
- }
- // 实际的画出当前的宠物位置
- pet.style.left = position.x + "px"
- pet.style.top = position.y + "px"
- count++
- walk.current++;
- }
- // 结束播放追逐状态GIF,同时开始重新播放追逐状态GIF图
- else if (walk.current >= walk.max) {
- walk.current = 0;
- document.getElementById("pet").src = "./img/Walk.gif"
- }
-
- }
-
- function attackState() {
- // 准备播放攻击状态动画
- if (attack.current == 0) {
- // 调整播放的动画
- document.getElementById("pet").src = "./img/Attack.gif"
- pet.style.width = 100 + "px"
- attack.current++
- }
- // 开始播放攻击状态动画,这里可以拓展在某些帧(current计数)的时候设置攻击范围和攻击处理函数之类的
- else if (attack.current < attack.max) {
- attack.current++;
- }
- // 结束播放攻击动画,改变对应状态,播放待机动画。
- else if (attack.current >= attack.max) {
- // 将动画设置复原
- isCatchUp = false;
- isIdle = true;
- attack.current = 0;
- document.getElementById("pet").src = "./img/Idle.gif"
- pet.style.width = 50 + "px"
-
- }
-
- }
-
- function clickState() {
- // 准备播放受击动画
- if (click.current == 0) {
- document.getElementById("pet").src = "./img/Hit.gif"
- pet.style.width = 60 + "px"
- click.current++
- }
- // 开始播放受击动画,可以在这里面处理对应受击动作函数
- else if (click.current < click.max) {
- click.current++;
- }
- // 结束播放受击动画,改变状态,播放行走动画
- else if (click.current >= click.max) {
- click.current = 0;
- document.getElementById("pet").src = "./img/Walk.gif"
- pet.style.width = 50 + "px"
- isClick = false;
- isIdle = false;
- }
-
-
- }
做这个东西主要还是想把他放在自己的个人网站上面,让网站内容不至于过于空虚。放在vue上面的话,大体没啥问题,主要是注意放的位置就欧克了,建议放在绝对路径里面。
这里资源放置的路径,建议将宠物的GIF图片放在项目public下面的文件夹中,不然可能无法正常加载。
.js文件和.vue文件同正常一样即可。
将整个js代码用一个函数start包起来,然后每个涉及到图片地址的用public下的绝对路径代替即可。
- export function start() {
- let pet = document.getElementById('pet');
- ......
- function catchUpState() {
- if (walk.current == 0) {
- // document.getElementById("pet").src = "./img/Walk.gif"
- document.getElementById("pet").src = "/image/pet/Walk.gif"
- ......
- }
- ......
- }
-
引入pet.js里面的start方法,这个需要在mounted里面初始化,不能放在created()里面进行初始化,不然会报错。
- <template>
- <div>
- <img class="pet" id="pet" src="/image/pet/Idle.gif" />
- </div>
- </template>
-
- <script>
- import { start } from "../util/pet.js";
- export default {
- // 某些父子组件交互的值
- data() {
- return {
- };
- },
- mounted() {
- start();
- },
- methods: {},
- };
- </script>
-
- <style scoped lang="less">
- .pet {
- width: 50px;
- height: 65px;
- position: absolute;
- background-size: cover;
- }
- </style>
百度网盘链接: https://pan.baidu.com/s/1585QjxSWWdX2eOXXECGpVg
提取码: hia9
vue为vue项目上更改过的文件
webpet则是可以直接打开index.html的文件
还有很多等待优化的地方,只是一个小小的demo,做着玩的,不过收获的确很多。可能有些地方会出现问题,有问题私信或者评论区留言,咱们共同探讨
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。