桌面宠物 ② 通过js制作属于自己的web网页宠物
一、網(wǎng)頁(yè)寵物素材
1.1 需要準(zhǔn)備什么素材
桌面寵物 ① 通過(guò)python制作屬于自己的桌面寵物_林林zonzon的博客-CSDN博客_python桌面寵物同前一篇文章一樣,web網(wǎng)頁(yè)寵物的動(dòng)畫(huà)效果的實(shí)現(xiàn),也是由一個(gè)個(gè)GIF圖拼接而成,我們需要準(zhǔn)備多組GIF動(dòng)圖來(lái)實(shí)現(xiàn)網(wǎng)頁(yè)寵物的動(dòng)作切換。
1.2 素材的獲取方法
① 素材網(wǎng)站:愛(ài)給網(wǎng)、素材巷等。
② 通過(guò)ps、pr自己制作 :pr制作選擇視頻輸出為GIF圖即可,ps則需要一幀一幀的找靜態(tài)圖拼接到一起,具體操作流程看上篇。
③ 通過(guò)淘寶購(gòu)買(mǎi):【淘寶某些商家的資源挺坑的】
二、js實(shí)現(xiàn)代碼
2.1 目錄結(jié)構(gòu)
項(xiàng)目的目錄結(jié)構(gòu)如下,其中index.html為可以打開(kāi)的網(wǎng)頁(yè)。
?img下的GIF圖片是網(wǎng)頁(yè)寵物對(duì)應(yīng)的可切換動(dòng)作,這里就放了4個(gè),分別為Attack攻擊動(dòng)畫(huà)、Hit受擊動(dòng)畫(huà)、Idle待機(jī)動(dòng)畫(huà)、Walk行走動(dòng)畫(huà)。
?class下的pet.js就是網(wǎng)頁(yè)寵物的行為邏輯設(shè)置。
2.2 實(shí)現(xiàn)代碼
2.2.1 index.html中的代碼設(shè)置
<img>標(biāo)簽即為展示網(wǎng)頁(yè)寵物的內(nèi)容,設(shè)置他的class和id名都為pet,src為其讀取的資源路徑,默認(rèn)讀取idle(待機(jī))的GIF圖片
<div><img class="pet" id="pet" src="./img/Idle.gif" /> </div>?script下引入對(duì)應(yīng)的JS文件
<script src="./class/pet.js" type="text/javascript"></script>?style下設(shè)置網(wǎng)頁(yè)寵物的展示樣式
.pet {width: 50px;height: 65px;position: absolute;background-size: cover;}2.2.2 實(shí)現(xiàn)功能
這次的網(wǎng)頁(yè)寵物實(shí)現(xiàn)的功能為:平常處于待機(jī)動(dòng)畫(huà)狀態(tài),在點(diǎn)擊寵物后,寵物播放受擊動(dòng)畫(huà),然后開(kāi)始追逐鼠標(biāo),追逐到后執(zhí)行攻擊動(dòng)畫(huà),攻擊動(dòng)畫(huà)執(zhí)行完畢后恢復(fù)待機(jī)狀態(tài)。
① 寵物元素設(shè)置
首先通過(guò)getElementById,根據(jù)id獲取對(duì)應(yīng)image的相關(guān)屬性
// 獲取寵物元素 let pet = document.getElementById('pet');定義旋轉(zhuǎn)角度,寵物位置、鼠標(biāo)位置、移動(dòng)次數(shù)來(lái)實(shí)現(xiàn)寵物追逐鼠標(biāo)時(shí)候位置方向的旋轉(zhuǎn)移動(dòng)。
// 旋轉(zhuǎn)角度 let deg = 0; // 旋轉(zhuǎn)角度Y let deg_y = 0; // 記錄寵物位置 let position = {x: 0,y: 0, } // 記錄寵物距離鼠標(biāo)需要移動(dòng)的距離 let mousePosition = {x: 0,y: 0, } // 記錄當(dāng)前移動(dòng)次數(shù) let count = 0; // 寵物移動(dòng)到鼠標(biāo)位置,所需要的次數(shù) let speed = 50;定義相關(guān)狀態(tài),與動(dòng)畫(huà)切換時(shí)間,實(shí)現(xiàn)狀態(tài)切換和動(dòng)畫(huà)播放
// 是否處于追逐狀態(tài) let isCatchUp = false; // 是否處于點(diǎn)擊狀態(tài) let isClick = false; // 是否處于待機(jī)狀態(tài) let isIdle = true;// 攻擊動(dòng)畫(huà)狀態(tài)記錄 let attack = {// 當(dāng)前幀current: 0,// 持續(xù)時(shí)間max: 340, } // 點(diǎn)擊動(dòng)畫(huà)狀態(tài)記錄 let click = {current: 0,max: 40 } // 行走動(dòng)畫(huà)狀態(tài)記錄 let walk = {current: 0,max: 130 }② 鼠標(biāo)點(diǎn)擊的監(jiān)聽(tīng)事件,將其設(shè)置為點(diǎn)擊狀態(tài)
// 點(diǎn)擊事件監(jiān)聽(tīng) document.getElementById("pet").onclick = function () {isClick = true; };③ 監(jiān)聽(tīng)鼠標(biāo)移動(dòng)事件
????????首先通過(guò)當(dāng)前鼠標(biāo)位置-當(dāng)前寵物距離瀏覽器左邊的距離-寵物寬度的中心位置的方式算出需要移動(dòng)的距離mousePosition;
????????通過(guò)相關(guān)公式算出需要翻轉(zhuǎn)的角度deg;
????????判斷鼠標(biāo)當(dāng)時(shí)的落點(diǎn)與寵物離瀏覽器左邊距離的關(guān)系,根據(jù)你GIF圖的朝向調(diào)整是大于還是小于;
????????最后將count計(jì)數(shù)清零,因?yàn)槊恳淮问髽?biāo)移動(dòng)都需要重新計(jì)算鼠標(biāo)距離。
// 鼠標(biāo)移動(dòng)事件處理 window.addEventListener('mousemove', function (event) {// 需要移動(dòng)的x軸距離 = 當(dāng)前鼠標(biāo)位置-距離瀏覽器左邊的距離-寵物相對(duì)于瀏覽器頁(yè)面寬度/2(寬的中心位置)mousePosition.x = event.x - pet.offsetLeft - pet.clientWidth / 2;mousePosition.y = event.y - pet.offsetTop - pet.clientHeight / 2;// 需要的旋轉(zhuǎn)角度計(jì)算deg = 360 * Math.atan(mousePosition.y / mousePosition.x) / (2 * Math.PI);// 這里的event.clientX 返回當(dāng)事件被觸發(fā)時(shí)鼠標(biāo)指針相對(duì)于瀏覽器頁(yè)面(或客戶區(qū))的水平坐標(biāo)。// 這里有關(guān)于圖片位置的設(shè)置,注意你的gif圖的方向,原圖方向向左,那么這里就是小于,原圖方向向右,這里就是大于。// 翻轉(zhuǎn)圖片if (pet.offsetLeft > event.clientX) {deg_y = - 180;} else {deg_y = 0;}//這里每一次移動(dòng)鼠標(biāo)都要重新計(jì)算距離,所以這里的count需要清零count = 0; })④ 寵物更新?tīng)顟B(tài)事件,網(wǎng)頁(yè)寵物的動(dòng)作切換流程,主體由setInterval完成,setInterval為一個(gè)不斷執(zhí)行的定時(shí)函數(shù),每過(guò)10毫秒循環(huán)執(zhí)行。
// 每過(guò)10毫秒,循環(huán)執(zhí)行 setInterval(() => {// 處于追逐鼠標(biāo)狀態(tài)if (isCatchUp == false && isIdle == false) {catchUpState();}// 處于攻擊狀態(tài)else if (isCatchUp == true && isIdle == false) {attackState();}// 處于點(diǎn)擊狀態(tài)else if (isClick == true) {clickState();} }, 10)⑤ 鼠標(biāo)追逐狀態(tài) catchUpState()
用walk.current模擬GIF播放的當(dāng)前幀,walk.max模擬GIF圖的一次播放時(shí)間。 ?walk.current = 1 就相當(dāng)于GIF播放到第1幀。
function catchUpState() {// 準(zhǔn)備播放追逐狀態(tài)動(dòng)畫(huà)if (walk.current == 0) {(1)......}// 開(kāi)始播放追逐狀態(tài)GIFelse if (walk.current < walk.max) {(2)......}// 結(jié)束播放追逐狀態(tài)GIF,同時(shí)開(kāi)始重新播放追逐狀態(tài)GIF圖else if (walk.current >= walk.max) {(3)......}}?(1)在current等于0時(shí),切換成需要的GIF圖,并根據(jù)你自己GIF圖的大小決定調(diào)整情況,最后current++。
// 此時(shí)寵物為追逐狀態(tài),gif圖切換為walk.gifdocument.getElementById("pet").src = "./img/Walk.gif" // 因?yàn)椴煌腉IF圖對(duì)應(yīng)的寬高可能有差別,需要調(diào)整的可以在這里調(diào)整pet.style.width = 50 + "px" // 當(dāng)前動(dòng)畫(huà)幀+1walk.current++(2)在current>0而小于設(shè)定的max時(shí) ,就執(zhí)行當(dāng)前狀態(tài)下的一些操作。
walk狀態(tài)下,首先根據(jù)我們?cè)谑髽?biāo)監(jiān)聽(tīng)事件中獲取的deg調(diào)整寵物旋轉(zhuǎn)角度。
// 調(diào)整寵物角度 pet.style.transform = "rotateZ(" + deg + "deg) rotateY(" + deg_y + "deg)"然后再通過(guò)count和speed的大小判斷寵物是否到達(dá)鼠標(biāo)位置,沒(méi)到達(dá)就改變寵物對(duì)應(yīng)的位置,到達(dá)就調(diào)整寵物狀態(tài)。【speed為我們?cè)O(shè)定的需要移動(dòng)距離的份數(shù),count為當(dāng)前移動(dòng)距離的份數(shù)】
// 如果沒(méi)追到鼠標(biāo) if (count < speed) {// position.x和y分別記錄當(dāng)前寵物的橫縱坐標(biāo)位置// 此時(shí)的橫縱坐標(biāo)位置,通過(guò)+=的方式移過(guò)去,speed越大,移動(dòng)速度越慢// 相當(dāng)于將兩點(diǎn)之間的位置分為speed份,每一次刷新移動(dòng)一份的距離position.x += mousePosition.x / speedposition.y += mousePosition.y / speed } // 追到鼠標(biāo) else {// 改變狀態(tài)isCatchUp = true }?最后改變寵物實(shí)際的樣式屬性,實(shí)現(xiàn)寵物的移動(dòng)。
// 實(shí)際的畫(huà)出當(dāng)前的寵物位置pet.style.left = position.x + "px"pet.style.top = position.y + "px"count++walk.current++;(3)在current>=max時(shí),即是行走動(dòng)畫(huà)播放完畢,在walk狀態(tài)下,如果沒(méi)有追逐到鼠標(biāo),將會(huì)繼續(xù)循環(huán)播放walk.gif動(dòng)畫(huà)。
//當(dāng)前幀歸零walk.current = 0;//繼續(xù)播放walk.gif圖片document.getElementById("pet").src = "./img/Walk.gif"⑥ 寵物攻擊狀態(tài) attackState(),這里的邏輯和上面的邏輯是一樣的,就不過(guò)多講述了。
function attackState() {// 準(zhǔn)備播放攻擊狀態(tài)動(dòng)畫(huà)if (attack.current == 0) {// 調(diào)整播放的動(dòng)畫(huà)document.getElementById("pet").src = "./img/Attack.gif"pet.style.width = 100 + "px"attack.current++}// 開(kāi)始播放攻擊狀態(tài)動(dòng)畫(huà),這里可以拓展在某些幀(current計(jì)數(shù))的時(shí)候設(shè)置攻擊范圍和攻擊處理函數(shù)之類(lèi)的else if (attack.current < attack.max) {attack.current++;}// 結(jié)束播放攻擊動(dòng)畫(huà),改變對(duì)應(yīng)狀態(tài),播放待機(jī)動(dòng)畫(huà)。else if (attack.current >= attack.max) {// 將動(dòng)畫(huà)設(shè)置復(fù)原isCatchUp = false;isIdle = true;attack.current = 0;document.getElementById("pet").src = "./img/Idle.gif"pet.style.width = 50 + "px"}}?⑦ 寵物點(diǎn)擊狀態(tài) clickState()
function clickState() {// 準(zhǔn)備播放受擊動(dòng)畫(huà)if (click.current == 0) {document.getElementById("pet").src = "./img/Hit.gif"pet.style.width = 60 + "px"click.current++}// 開(kāi)始播放受擊動(dòng)畫(huà),可以在這里面處理對(duì)應(yīng)受擊動(dòng)作函數(shù)else if (click.current < click.max) {click.current++;}// 結(jié)束播放受擊動(dòng)畫(huà),改變狀態(tài),播放行走動(dòng)畫(huà)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;}}2.3 完整源碼
2.3.1 index.html
<!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>2.3.2 pet.js
// 獲取寵物元素 let pet = document.getElementById('pet'); // 旋轉(zhuǎn)角度 let deg = 0; // 旋轉(zhuǎn)角度Y let deg_y = 0; // 記錄寵物距離鼠標(biāo)需要移動(dòng)的距離 let mousePosition = {x: 0,y: 0, } // 記錄寵物位置 let position = {x: 0,y: 0, }// 記錄當(dāng)前移動(dòng)次數(shù) let count = 0; // 寵物移動(dòng)到鼠標(biāo)位置,所需要的次數(shù) let speed = 50;// 是否處于追逐狀態(tài) let isCatchUp = false; // 是否處于點(diǎn)擊狀態(tài) let isClick = false;// 是否處于待機(jī)狀態(tài) let isIdle = true;// 攻擊動(dòng)畫(huà)狀態(tài)記錄 let attack = {// 當(dāng)前幀current: 0,// 持續(xù)時(shí)間max: 340, } // 點(diǎn)擊動(dòng)畫(huà)狀態(tài)記錄 let click = {current: 0,max: 40 }// 行走動(dòng)畫(huà)狀態(tài)記錄 let walk = {current: 0,max: 130 }// 點(diǎn)擊事件處理 document.getElementById("pet").onclick = function () {isClick = true; };// 鼠標(biāo)移動(dòng)事件處理 window.addEventListener('mousemove', function (event) {// 期望圖片移動(dòng)到的鼠標(biāo)x軸位置 = 當(dāng)前鼠標(biāo)位置-距離瀏覽器左邊的距離-寵物相對(duì)于瀏覽器頁(yè)面寬度/2(寬的中心位置)mousePosition.x = event.x - pet.offsetLeft - pet.clientWidth / 2;mousePosition.y = event.y - pet.offsetTop - pet.clientHeight / 2;// 旋轉(zhuǎn)角度deg = 360 * Math.atan(mousePosition.y / mousePosition.x) / (2 * Math.PI);// clientX 事件屬性返回當(dāng)事件被觸發(fā)時(shí)鼠標(biāo)指針相對(duì)于瀏覽器頁(yè)面(或客戶區(qū))的水平坐標(biāo)。// 這里有關(guān)于圖片位置的設(shè)置,注意你的gif圖的方向,原圖方向向左,那么這里就是小于,原圖方向向右,這里就是大于。// 翻轉(zhuǎn)圖片if (pet.offsetLeft > event.clientX) {deg_y = - 180;} else {deg_y = 0;}//這里每一次移動(dòng)鼠標(biāo)都要重新計(jì)算距離,所以這里的count需要清零count = 0; })// 每過(guò)10毫秒,循環(huán)執(zhí)行 setInterval(() => {// 處于追逐鼠標(biāo)狀態(tài)if (isCatchUp == false && isIdle == false) {catchUpState();}// 處于攻擊狀態(tài)else if (isCatchUp == true && isIdle == false) {attackState();}// 處于點(diǎn)擊狀態(tài)else if (isClick == true) {clickState();} }, 10)function catchUpState() {// 準(zhǔn)備播放追逐狀態(tài)動(dòng)畫(huà)if (walk.current == 0) {// 此時(shí)寵物為追逐狀態(tài),gif圖切換為walk.gifdocument.getElementById("pet").src = "./img/Walk.gif"// 因?yàn)椴煌腉IF圖對(duì)應(yīng)的寬高可能有差別,需要調(diào)整的可以在這里調(diào)整pet.style.width = 50 + "px"// 當(dāng)前動(dòng)畫(huà)幀+1walk.current++}// 開(kāi)始播放追逐狀態(tài)GIFelse if (walk.current < walk.max) {// 調(diào)整寵物角度pet.style.transform = "rotateZ(" + deg + "deg) rotateY(" + deg_y + "deg)"// 如果沒(méi)追到鼠標(biāo)if (count < speed) {// position.x和y分別記錄當(dāng)前寵物的橫縱坐標(biāo)位置// 此時(shí)的橫縱坐標(biāo)位置,通過(guò)+=的方式移過(guò)去,speed越大,移動(dòng)速度越慢// 相當(dāng)于將兩點(diǎn)之間的位置分為speed份,每一次刷新移動(dòng)一份的距離position.x += mousePosition.x / speedposition.y += mousePosition.y / speed}// 追到鼠標(biāo)else {// 改變狀態(tài)isCatchUp = truewalk.current = 0}// 實(shí)際的畫(huà)出當(dāng)前的寵物位置pet.style.left = position.x + "px"pet.style.top = position.y + "px"count++walk.current++;}// 結(jié)束播放追逐狀態(tài)GIF,同時(shí)開(kāi)始重新播放追逐狀態(tài)GIF圖else if (walk.current >= walk.max) {walk.current = 0;document.getElementById("pet").src = "./img/Walk.gif"}}function attackState() {// 準(zhǔn)備播放攻擊狀態(tài)動(dòng)畫(huà)if (attack.current == 0) {// 調(diào)整播放的動(dòng)畫(huà)document.getElementById("pet").src = "./img/Attack.gif"pet.style.width = 100 + "px"attack.current++}// 開(kāi)始播放攻擊狀態(tài)動(dòng)畫(huà),這里可以拓展在某些幀(current計(jì)數(shù))的時(shí)候設(shè)置攻擊范圍和攻擊處理函數(shù)之類(lèi)的else if (attack.current < attack.max) {attack.current++;}// 結(jié)束播放攻擊動(dòng)畫(huà),改變對(duì)應(yīng)狀態(tài),播放待機(jī)動(dòng)畫(huà)。else if (attack.current >= attack.max) {// 將動(dòng)畫(huà)設(shè)置復(fù)原isCatchUp = false;isIdle = true;attack.current = 0;document.getElementById("pet").src = "./img/Idle.gif"pet.style.width = 50 + "px"}}function clickState() {// 準(zhǔn)備播放受擊動(dòng)畫(huà)if (click.current == 0) {document.getElementById("pet").src = "./img/Hit.gif"pet.style.width = 60 + "px"click.current++}// 開(kāi)始播放受擊動(dòng)畫(huà),可以在這里面處理對(duì)應(yīng)受擊動(dòng)作函數(shù)else if (click.current < click.max) {click.current++;}// 結(jié)束播放受擊動(dòng)畫(huà),改變狀態(tài),播放行走動(dòng)畫(huà)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項(xiàng)目中展示網(wǎng)頁(yè)寵物
做這個(gè)東西主要還是想把他放在自己的個(gè)人網(wǎng)站上面,讓網(wǎng)站內(nèi)容不至于過(guò)于空虛。放在vue上面的話,大體沒(méi)啥問(wèn)題,主要是注意放的位置就歐克了,建議放在絕對(duì)路徑里面。
3.1 資源位置
這里資源放置的路徑,建議將寵物的GIF圖片放在項(xiàng)目public下面的文件夾中,不然可能無(wú)法正常加載。
?.js文件和.vue文件同正常一樣即可。
3.2 pet.js代碼
將整個(gè)js代碼用一個(gè)函數(shù)start包起來(lái),然后每個(gè)涉及到圖片地址的用public下的絕對(duì)路徑代替即可。
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"......}......}3.3 vue界面代碼
引入pet.js里面的start方法,這個(gè)需要在mounted里面初始化,不能放在created()里面進(jìn)行初始化,不然會(huì)報(bào)錯(cuò)。
<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>四、總結(jié)
4.1 項(xiàng)目百度網(wǎng)盤(pán)
百度網(wǎng)盤(pán)鏈接: https://pan.baidu.com/s/1585QjxSWWdX2eOXXECGpVg
提取碼: hia9
vue為vue項(xiàng)目上更改過(guò)的文件
webpet則是可以直接打開(kāi)index.html的文件
4.2 總結(jié)
還有很多等待優(yōu)化的地方,只是一個(gè)小小的demo,做著玩的,不過(guò)收獲的確很多。可能有些地方會(huì)出現(xiàn)問(wèn)題,有問(wèn)題私信或者評(píng)論區(qū)留言,咱們共同探討🐵
總結(jié)
以上是生活随笔為你收集整理的桌面宠物 ② 通过js制作属于自己的web网页宠物的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 巴菲特致股东的一封信:2012年 和学习
- 下一篇: 02、cordic算法原理及verilo