首页 > 分享 > 前端练习小项目 —— 养一只电子蜘蛛

前端练习小项目 —— 养一只电子蜘蛛

        前言:在学习完JavaScript之后,我们就可以使用JavaScript来实现一下好玩的效果了,本篇文章讲解的是如何纯使用JavaScript来实现一个网页中的电子蜘蛛。

✨✨✨这里是秋刀鱼不做梦的BLOG

✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客

在开始学习如何编写一个网页蜘蛛之前,先让我们看一下这个电子蜘蛛长什么样:

        ——我们可以看到,其会跟随着我们的鼠标进行移动,那么我们如何实现这样的效果呢?接下来让我们开始讲解。

1.HTML代码

        我们的html代码十分的简单,就是创建一个画布,而我们接下来的操作,都是在此上边进行操作的:

<!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>秋刀鱼不做梦</title>

<script src="./test.js"></script>

<style>

body {

margin: 0px;

padding: 0px;

position: fixed;

background: rgb(0, 0, 0);

}

</style>

</head>

<body>

<canvas id="canvas"></canvas>

</body>

</html>

        可以看到我们的HTML代码非常的简单,接下来让我们开始在其上边进行操作!

2.JavaScript代码

        在开始编写JavaScript代码之前,先让我们理清一下思路:

总体流程

页面加载时,canvas 元素和绘图上下文初始化。

定义触手对象,每条触手由多个段组成。

监听鼠标移动事件,实时更新鼠标的位置。

通过动画循环绘制触手,触手根据鼠标的位置动态变化,形成流畅的动画效果。

        大致的流程就是上边的步骤,但是我相信读者在没用自己完成此代码的编写之前,可能不能理解上边的流程,不过没关系,现在让我们开始我们的网页小蜘蛛的编写:

                写在前面:为了让读者可以更好的理解代码的逻辑,我们给没一句代码都加上了注释,希望读者可以根据注释的帮助一点一点的理解代码:

JavaScript代码:

window.requestAnimFrame = function () {

return (

window.requestAnimationFrame ||

window.webkitRequestAnimationFrame ||

window.mozRequestAnimationFrame ||

window.oRequestAnimationFrame ||

window.msRequestAnimationFrame ||

function (callback) {

window.setTimeout(callback)

}

)

}

function init(elemid) {

let canvas = document.getElementById(elemid)

c = canvas.getContext('2d')

w = (canvas.width = window.innerWidth)

h = (canvas.height = window.innerHeight)

c.fillStyle = "rgba(30,30,30,1)"

c.fillRect(0, 0, w, h)

return { c: c, canvas: canvas }

}

window.onload = function () {

let c = init("canvas").c,

canvas = init("canvas").canvas,

w = (canvas.width = window.innerWidth),

h = (canvas.height = window.innerHeight),

mouse = { x: false, y: false },

last_mouse = {}

function dist(p1x, p1y, p2x, p2y) {

return Math.sqrt(Math.pow(p2x - p1x, 2) + Math.pow(p2y - p1y, 2))

}

class segment {

constructor(parent, l, a, first) {

this.first = first

if (first) {

this.pos = {

x: parent.x,

y: parent.y,

}

} else {

this.pos = {

x: parent.nextPos.x,

y: parent.nextPos.y,

}

}

this.l = l

this.ang = a

this.nextPos = {

x: this.pos.x + this.l * Math.cos(this.ang),

y: this.pos.y + this.l * Math.sin(this.ang),

}

}

update(t) {

this.ang = Math.atan2(t.y - this.pos.y, t.x - this.pos.x)

this.pos.x = t.x + this.l * Math.cos(this.ang - Math.PI)

this.pos.y = t.y + this.l * Math.sin(this.ang - Math.PI)

this.nextPos.x = this.pos.x + this.l * Math.cos(this.ang)

this.nextPos.y = this.pos.y + this.l * Math.sin(this.ang)

}

fallback(t) {

this.pos.x = t.x

this.pos.y = t.y

this.nextPos.x = this.pos.x + this.l * Math.cos(this.ang)

this.nextPos.y = this.pos.y + this.l * Math.sin(this.ang)

}

show() {

c.lineTo(this.nextPos.x, this.nextPos.y)

}

}

class tentacle {

constructor(x, y, l, n, a) {

this.x = x

this.y = y

this.l = l

this.n = n

this.t = {}

this.rand = Math.random()

this.segments = [new segment(this, this.l / this.n, 0, true)]

for (let i = 1; i < this.n; i++) {

this.segments.push(

new segment(this.segments[i - 1], this.l / this.n, 0, false)

)

}

}

move(last_target, target) {

this.angle = Math.atan2(target.y - this.y, target.x - this.x)

this.dt = dist(last_target.x, last_target.y, target.x, target.y)

this.t = {

x: target.x - 0.8 * this.dt * Math.cos(this.angle),

y: target.y - 0.8 * this.dt * Math.sin(this.angle)

}

if (this.t.x) {

this.segments[this.n - 1].update(this.t)

} else {

this.segments[this.n - 1].update(target)

}

for (let i = this.n - 2; i >= 0; i--) {

this.segments[i].update(this.segments[i + 1].pos)

}

if (

dist(this.x, this.y, target.x, target.y) <=

this.l + dist(last_target.x, last_target.y, target.x, target.y)

) {

this.segments[0].fallback({ x: this.x, y: this.y })

for (let i = 1; i < this.n; i++) {

this.segments[i].fallback(this.segments[i - 1].nextPos)

}

}

}

show(target) {

if (dist(this.x, this.y, target.x, target.y) <= this.l) {

c.globalCompositeOperation = "lighter"

c.beginPath()

c.moveTo(this.x, this.y)

for (let i = 0; i < this.n; i++) {

this.segments[i].show()

}

c.strokeStyle = "hsl(" + (this.rand * 60 + 180) +

",100%," + (this.rand * 60 + 25) + "%)"

c.lineWidth = this.rand * 2

c.lineCap = "round"

c.lineJoin = "round"

c.stroke()

c.globalCompositeOperation = "source-over"

}

}

show2(target) {

c.beginPath()

if (dist(this.x, this.y, target.x, target.y) <= this.l) {

c.arc(this.x, this.y, 2 * this.rand + 1, 0, 2 * Math.PI)

c.fillStyle = "whith"

} else {

c.arc(this.x, this.y, this.rand * 2, 0, 2 * Math.PI)

c.fillStyle = "darkcyan"

}

c.fill()

}

}

let maxl = 400,

minl = 50,

n = 30,

numt = 600,

tent = [],

clicked = false,

target = { x: 0, y: 0 },

last_target = {},

t = 0,

q = 10;

for (let i = 0; i < numt; i++) {

tent.push(

new tentacle(

Math.random() * w,

Math.random() * h,

Math.random() * (maxl - minl) + minl,

n,

Math.random() * 2 * Math.PI,

)

)

}

function draw() {

if (mouse.x) {

target.errx = mouse.x - target.x

target.erry = mouse.y - target.y

} else {

target.errx =

w / 2 +

((h / 2 - q) * Math.sqrt(2) * Math.cos(t)) /

(Math.pow(Math.sin(t), 2) + 1) -

target.x;

target.erry =

h / 2 +

((h / 2 - q) * Math.sqrt(2) * Math.cos(t) * Math.sin(t)) /

(Math.pow(Math.sin(t), 2) + 1) -

target.y;

}

target.x += target.errx / 10

target.y += target.erry / 10

t += 0.01;

c.beginPath();

c.arc(

target.x,

target.y,

dist(last_target.x, last_target.y, target.x, target.y) + 5,

0,

2 * Math.PI

);

c.fillStyle = "hsl(210,100%,80%)"

c.fill();

for (i = 0; i < numt; i++) {

tent[i].move(last_target, target)

tent[i].show2(target)

}

for (i = 0; i < numt; i++) {

tent[i].show(target)

}

last_target.x = target.x

last_target.y = target.y

}

function loop() {

window.requestAnimFrame(loop)

c.clearRect(0, 0, w, h)

draw()

}

window.addEventListener("resize", function () {

w = canvas.width = window.innerWidth

w = canvas.height = window.innerHeight

loop()

})

loop()

setInterval(loop, 1000 / 60)

canvas.addEventListener("mousemove", function (e) {

last_mouse.x = mouse.x

last_mouse.y = mouse.y

mouse.x = e.pageX - this.offsetLeft

mouse.y = e.pageY - this.offsetTop

}, false)

canvas.addEventListener("mouseleave", function (e) {

mouse.x = false

mouse.y = false

})

}

'

这里我们在大致的梳理一下上述代码的流程:

1. 初始化阶段 init 函数:当页面加载时,init 函数被调用,获取 canvas 元素并设置其宽高为窗口的大小。获取到的 2D 绘图上下文(context)用于后续绘制。window.onload:页面加载完成后,初始化 canvas 和 context,并设置鼠标初始状态。 2. 触手对象的定义 segment 类:这是触手的一段,每个段有起始点(pos)、长度(l)、角度(ang),并通过角度计算出下一段的位置(nextPos)。tentacle 类:代表完整的触手,由若干个 segment 组成。触手的起始点在屏幕中心,并且每个触手包含多个段。tentacle 的主要方法有: move:根据鼠标位置更新每一段的位置。show:绘制触手的路径。 3. 事件监听 canvas.addEventListener("mousemove", ...):当鼠标移动时,捕捉鼠标的位置并存储在 mouse 变量中。每次鼠标移动会更新 mouse 和 last_mouse 的坐标,用于后续的动画。 4. 动画循环 draw 函数:这是一个递归的函数,用于创建动画效果。 首先,它会在每一帧中为画布填充半透明背景,使得之前绘制的内容逐渐消失,产生拖影效果。然后,遍历所有触手(tentacles),调用它们的 move 和 show 方法,更新位置并绘制每一帧。最后,使用 requestAnimFrame(draw) 不断递归调用 draw,形成一个动画循环。 5. 触手的行为 触手的运动是通过 move 函数实现的,触手的最后一个段首先更新位置,然后其他段依次跟随。触手的绘制通过 show 函数,遍历所有段并绘制线条,最后显示在屏幕上。

        ——这样我们就完成了电子小蜘蛛的制作了!!!

最后,在让我们看一下最终效果:

以上就是本篇文章的全部内容了!!

相关知识

前端练习小项目 —— 养一只电子蜘蛛
【如何养一只蜘蛛:详细指南】
UniPet宠物领养平台前端开源项目
团队项目:电子宠物
玩转蜘蛛乐园:养一只蜘蛛,带你探索不一样的宠物世界!
计算机毕业设计web前端毕设项目之宠物狗个性化服务网站前端设计与实现(静态网页)
一只蜘蛛,不知道宠物蜘蛛多少钱一只哦?
蜘蛛:各位蜘蛛爱好者们,你们知道如何饲养好一只蜘蛛吗?
电子宠物进化出 AI 来治愈群体性孤独,你要不要养一只?
初学javaweb+mybatis练习宠物管理系统小项目

网址: 前端练习小项目 —— 养一只电子蜘蛛 https://m.mcbbbk.com/newsview673936.html

所属分类:萌宠日常
上一篇: 宠物新选择:探索蜘蛛饲养的奥秘
下一篇: 【宠物蜘蛛安全】