面向对象canvas鼠标粒子连线放烟花

背景:
准备写一个桌面鼠标轨迹、事件可视化插件的,写着写着发现带点游戏效果挺好的。
要用JS写面向对象的代码,我个人认为最好的场景一定是游戏,特别适用于canvas。
写得仓促,关于代码不足的还望各位不吝赐教。

🫠、效果演示

面向对象canvas鼠标粒子连线放烟花

面向对象canvas鼠标粒子连线放烟花

一、程序入口

项目目录:

面向对象canvas鼠标粒子连线放烟花

+[js]文件夹
   -fun.js //存放用到的自定义函数
   -自定义类.js //存放自定义类
   -main.js //存放主入口函数
+index.html

二、程序主要目标

1.每秒60次动画循环

使用浏览器 window.requestAnimationFrame设置每秒60次动画循环。创建的对象都要放到自定义函数animate内部绘制,每次绘制前使用c2d.clearRect清除画布。

面向对象canvas鼠标粒子连线放烟花

animate();//循环动画函数 
function animate(t){ //t表示当前时间 毫秒 一直在增加
	nowTime = t     //暂未用到
	c2d.clearRect(0,0,canvas.width,canvas.height);
	
	//设置网格线
	tool.drawGrid(c2d,网格宽,网格高);
	
    画十字线(鼠标.x, 鼠标.y)
    
    for(let one of arr){
        one.draw(c2d)
    }

	requestAnimationFrame(animate);//每隔16.67ms去调用
}

2.绘制网格线

面向对象canvas鼠标粒子连线放烟花
调用:

let tool = new Tool();//创建一个工具人
const 网格宽 = 网格高 = 10
//... ...此处省略其他代码,下同

function animate(t){
	//... ...
	tool.drawGrid(c2d,网格宽,网格高);
       //... ...
}

定义:

class Tool{ /* 声明一个工具类 */
	
	//绘制网格 
	drawGrid(c2d,sizeX=10,sizeY=10,color="lightgray"){
		c2d.save();//新建一个绘图状态
		//设置一些参数
		c2d.strokeStyle = color;//设置线条颜色
		c2d.lineWidth 	= 0.5; //绘制线条的宽度
		
		//绘制水平辅助线
		for(let x = sizeX+0.5; x<c2d.canvas.width ; x+=sizeX  ){
			c2d.beginPath();//开始一个独立的路径
			c2d.moveTo(x,0);
			c2d.lineTo(x,c2d.canvas.height);
			c2d.stroke();
		}
		
		//绘制垂直辅助线
		for(let y = sizeY+0.5; y<c2d.canvas.height ; y+=sizeY  ){
			c2d.beginPath();//开始一个独立的路径
			c2d.moveTo(0,y);
			c2d.lineTo(c2d.canvas.width,y);
			c2d.stroke();
		}
		
		c2d.restore();//返回"新建sava()"之前的画布状态
	}//end drawGrid
}

3.绘制跟随鼠标移动的十字线

首先需要获得鼠标的坐标,结合canvas的最大宽度、高度可以知道两条交叉线两端的坐标。

面向对象canvas鼠标粒子连线放烟花

3.1 获取鼠标位置

定义鼠标坐标的全局变量,在网页中获取鼠标相对于canvas元素的精确坐标。

let 鼠标 = {    //定义鼠标的坐标
    x:0,
    y:0
}

function 更新鼠标坐标(e){
    let rect = canvas.getBoundingClientRect();
    鼠标.x = e.clientX - rect.left;
    鼠标.y = e.clientY - rect.top;

}

3.2 绘制十字线和交叉点坐标

默认交叉点坐标绘制在鼠标右上角,到边缘需要调整坐标显示值,做个边缘顶部和右侧边缘检测。
面向对象canvas鼠标粒子连线放烟花

//文件fun.js
function 画十字线(x, y) {

    // 绘制十字线
    c2d.save()
    let text = `( ${Math.round(x)}  , ${Math.round(y)} )`    
    let textSize = c2d.measureText(text);
    let textX = x + 10; // 右偏移量以离开鼠标点
    let textY = y - 10; // 上偏移量以放在鼠标点上方

    //判断 如果 x 靠近右侧边缘 , y靠近上册边缘 
    if(x >= canvas.width -80){
        textX = x - 80
    }

    if(y < 50){
        textY =   y + 30
    }

    c2d.fillStyle = 'red';// 设置文本颜色为红色
    c2d.fillText(text, textX, textY);


    // 设置十字线的颜色和粗细
    
    c2d.strokeStyle = '#FF0000'; // 示例颜色为红色
   
    c2d.lineWidth = 1; // 示例设置更明显的线宽

    // 水平线
    c2d.beginPath();
    c2d.moveTo(x, 0);
    c2d.lineTo(x, canvas.height);
    c2d.stroke();

    // 垂直线
    c2d.beginPath();
    c2d.moveTo(0, y);
    c2d.lineTo(canvas.width, y);
    c2d.stroke();

    c2d.restore()
}//画十字线

4.鼠标点击时绘制圆圈

当鼠标左键按下时绘制圆点,抬起时也绘制圆点。是为了绘制线时两端都有圆点。
为了防止圆重复绘制在同一个地方,代码中采用了一些判断,
先根据 name 获得 全局arr绘图对象数组中的圆圈,然后通过 数组.some进行判断。

面向对象canvas鼠标粒子连线放烟花

调用:

let arr = []    //存放全局绘图对象 ,包括 圆点、线段、子弹等

canvas.addEventListener('mousedown', (e)=>{
    线段.画 = true

    更新鼠标坐标(e)
    增加圆点() // ********此处调用***********

    线段.x = 鼠标.x
    线段.y = 鼠标.y


    canvas.addEventListener('mouseup',(e)=>{
        增加圆点() // ********此处调用***********
        创建子弹()  
        线段.画 = false
        线段.x = 鼠标.x
        线段.y = 鼠标.y
    })

});

定义:
面向对象canvas鼠标粒子连线放烟花

4.按住鼠标左键画线

定义:

let 线段 = {    //定义一个 线段 起点(x,y) 终点(x2,y2)
    画:false,   //表示是否开始画一个线段
    x:0,
    y:0,
    x2:0,
    y2:0,
}

设置一个线段的数据(两个端点),鼠标画线就是不断地连接两个点,然后记录下终点作为第二个线段的起点。
如果漏掉了赋值,就会出现下图的效果。
当鼠标按下,开始画线,获得第一个起点(x,y)
当鼠标移动,获得第二个起点(x2,y2),存入全局arr,并且将鼠标位置覆盖(x,y) ,作为第二段线段起点
当鼠标抬起,结束画线。
很有微积分的感觉,极小的线段不断相连组成连贯的曲线。
面向对象canvas鼠标粒子连线放烟花

5.绽放烟花效果

面向对象canvas鼠标粒子连线放烟花
当点击鼠标左键时,以鼠标位置创建速度一样的点对象。
定义:
面向对象canvas鼠标粒子连线放烟花

三、面向对象程序总结

定义一个父类W, 子类 子弹、线、圆点继承父类,都有各自的绘图方法draw。
程序还有值得优化的地方,欢迎愿大佬


class W{
	constructor(x,y,name='名字') {
	    this.x = x;
		this.y = y;
		this.name = name
		//自身动画相关的
		this.i = -1;//表示裁剪的图片位置
		this.imgW = 80;//裁剪的宽度

		this.sx = 0;//裁剪的起始x坐标
		this.t = 0; //存放上一次图片切换的时间
	}

}//结束 物体类

class 子弹 extends W{

	constructor(x,y,angle,v=1){
		super(x,y,'子弹')
		this.angle =  angle
		this.v = v
	}



	move(){
		this.x += Math.cos(this.angle) * this.v;
		this.y += Math.sin(this.angle) * this.v;
	}


	draw(c2d){ 
		this.move()
		//绘图方法
	}

}

//创建一个线条类
class 线 extends W{

	constructor(x,y,x2,y2){
		super(x,y,'线段')

		this.x2 = x
		this.y2 = y2

	}

	draw(c2d){ 
		//绘图方法
	}


}



// 绘制一个圆圈
class 圆点 extends W{
	constructor(x,y){
		super(x,y,'圆点')
	}

	draw(c2d){ 
		//绘图方法
	}
}

原文链接:https://juejin.cn/post/7334311273340239887 作者:百万蹄蹄向前冲

(0)
上一篇 2024年2月17日 上午10:00
下一篇 2024年2月17日 上午10:11

相关推荐

发表回复

登录后才能评论