前端可视化游戏基础

初识canvas

绘制三角形

useEffect(()=>{
    if(canvasRef.current){
      const ctx = canvasRef.current.getContext('2d')

      // 定位开始点
      ctx?.moveTo(30, 30)
      
	//拖动,从第一个点移动到第二个点,只是描绘路径,(保存内存当中),还没上色。
       
      ctx?.lineTo(30, 90)
      ctx?.lineTo(60,60)
      //ctx?.lineTo(30,30)
      // 形成闭合点,关闭当前的路径
      ctx?.closePath() 
 
 //绘制
      ctx?.stroke()
  },[])

  return <div>
    <canvas ref={canvasRef} height={800} width={1240} style={{border: '1px solid #eee'}}></canvas>
  </div>;

关键语法:

//获取画布元素
canvasRef.current

// 获取画布的工具集,可以🌹直线,圆等等。
const ctx = canvasRef.current.getContext('2d')

// 定位开始点(将点移动到30,30的位置,但是不会绘制出来。)
ctx.moveTo(30,30)

//拖动,从第一个点移动到第二个点,只是描绘路径,(保存内存当中)
ctx?.lineTo(30, 90)

// 闭合点
ctx?.closePath() 

 //调用stroke才是真正绘制
  ctx?.stroke()

在这里插入图片描述

绘制不同线条颜色的三角形。

 //线条颜色
      ctx!.strokeStyle = "red"
//线条宽度
      ctx!.lineWidth = 10
  • 重置路径:开始一条路径,切换与上一个图形的联系。可以实现不同大小和颜色图形的单独绘制
 //线条宽度
      ctx!.lineWidth = 5;

      //线条颜色
      ctx!.strokeStyle = "red";
      // 定位开始点
      ctx?.moveTo(30, 30);
      //拖动,从第一个点移动到第二个点,只是描绘路径,(保存内存当中),还没上色。
      ctx?.lineTo(30, 90);
      //绘制
      ctx?.stroke();
      // 绘制完毕断开联系
      ctx?.beginPath();

      //绘制第二条线的起始点
      ctx?.moveTo(30, 90);
      ctx?.lineTo(60, 60);
      ctx!.strokeStyle = "blue";
      //绘制
      ctx?.stroke();
      // 绘制完毕断开联系
      ctx?.beginPath();

      //绘制第三条线的起始点
      ctx?.moveTo(60, 60);
      ctx?.lineTo(30, 30);
      ctx!.strokeStyle = "yellow";
      ctx?.stroke();

没描绘一条线的路径就直接绘制,然后调用beginPath断开联系,然后重新绘制起始点,继续绘制第二条线。
在这里插入图片描述

其他绘制的api

文字

//文字的绘制 font可以绘制样式
 ctx!.font = "bold 32px 黑体"
 //填充式
ctx?.fillText('哈哈哈', 100, 100)

// 描边
 ctx?.strokeText("哈哈哈", 200, 200);

在这里插入图片描述

 // // 文字的绘制 font可以绘制样式
ctx!.font = "bold 32px 黑体";
 //以文字绘制的坐标为坐标轴起点,如以30,30位坐标轴原点,水平对齐
ctx!.textAlign = "left" ;
ctx!.textBaseline = 'top'
// 垂直对齐
ctx?.fillText("哈哈哈", 30, 30);

在这里插入图片描述
textAlign,水平对齐,以30,30的y轴,right表示在右边。
textBaseLine,垂直对齐,以30,30的x轴,top表示轴在上方。

toDataURL

canvas.toDataURL()
转为base64字符串。

const imgUrl = canvasRef.current.toDataURL("image/png",1)

绘制矩形圆形及图片。

  • 矩形,先描边,再绘制。
 // 矩形, x,y,width,height
      ctx?.rect(100,100,100,100)
      // 绘制或者填充
      //ctx?.stroke()
      ctx?.fill()

一次性。

//调用一次性
      ctx?.strokeRect(200,200, 100,100)

清除内容。

ctx?.clearRect(190,190,120,120)

从190,190,开始,width 120,height 120清除内容。

  • 圆形
///200,200 , 半径30, 从0度开始移动到360度,顺时针
      ctx?.arc(300,300, 30, 0, Math.PI * 2 )
      ctx?.stroke()
  • 图片
 const img = document.createElement('img')
      img.src = png
      img.onload=()=>{
       //图片element, x, y, 图片w, 图片h
        ctx?.drawImage(img, 200, 200, 100, 100)
        const imgUrl = canvasRef.current!.toDataURL("image/png",1)
        console.log('imgUrl',imgUrl);
        setImgUrl(imgUrl)
      }
   

放大

// element,    x1,y1,w1,h1,  x2,y2,w2,h2
ctx?.drawImage(img, 400,0, 500,500, 200,200, 100,100)

图片element, 图片x400,y0,图片400,0出发截取x轴500,图片400,0出发截取y轴500。
绘制到画布
200,200,高度200,宽度200

实现刮刮卡效果

 const { width, height } = canvasRef.current;

      //绘制
      const arrGifs = ["一等奖", "二等奖", "未中奖"];
      const text = arrGifs[Math.floor(Math.random() * arrGifs.length)];
      ctx!.font = "bold 35px 黑体";
      ctx!.textAlign = "center";
      ctx!.textBaseline = "middle";
      ctx!.fillStyle = "red";
      ctx?.fillText(text, width / 2, height / 2);
      const imgUrl = canvasRef.current.toDataURL("image/png", 1);
      canvasRef.current.style.background = `url(${imgUrl})`;

      //擦除元素
      ctx?.clearRect(0, 0, width, height);

      //绘制矩形 盖住信息
      ctx!.fillStyle = "#999";
      ctx?.fillRect(0, 0, width, height);

      // 鼠标划擦,实现画布区域
      let isDrag = false;
      canvasRef.current.addEventListener("mousedown", () => {
        isDrag = true;
        //将绘制的区域置为透明
        ctx!.globalCompositeOperation = "destination-out"
      });
      canvasRef.current.addEventListener("mousemove", (e) => {
        if (isDrag) {
          const { clientX: x, clientY: y } = e;
          ctx!.fillStyle = "red";
          ctx?.fillRect(x, y, 20, 20);
        }
      });
      canvasRef.current.addEventListener("mouseup", () => {
        isDrag = false;
      });

主要分为三部分,

  • 随机生成文字,转成base64,切成背景图存放。
  • 使用灰色覆盖整个canvas
  • 监听鼠标事件,鼠标经过哪绘制一个小的正方形,并且设置透明。这样就可以看到中奖文字。
    效果:
    在这里插入图片描述

three.js电子书

对webgl的封装。

three.js要素

  • 渲染器 可以理解成电视机
new Three.WebGLRenderer({antialias: true})
  • 场景 可以理解成拍电影时候的场景
const scene = new Three.Scene()
  • 相机 可以理解成摄影机
透视相机,跟人的眼睛类似
const camera = new Three.PerspectiveCamera(100,狂高比,0.1, 100)
正交相机
new Three.OrthographicCamera(
      window.innerWidth / -50, //相机左边范围
      window.innerWidth / 50, //相机右边范围
      window.innerHeight / 50, //相机上边范围
      window.innerHeight / -50, //相机下边范围
      0, //远近
      5000 //远处的大小
    );
  • 几何体 可以理解成演员,需要放入到特定的场景
//创建一个几何体
    //几何体宽高  宽,高,深度
    const geomerty = new Three.CubeGeometry(4, 2, 4);
    //材质 不反射光
    const materital = new Three.MeshLambertMaterial({ color: "#eee" });
    const cube = new Three.Mesh(geomerty, materital);
 //将几何体放入场景
scene.add(cube)
  • 光照, 可以理解成拍照片或者电影时候的补光,也需要放入特定的场景
  //来点光照
    const dirctionalLight = new Three.DirectionalLight("#fff", 1.1);
    dirctionalLight.position.set(3, 2, 1);
    scene.add(dirctionalLight);
相机获取场景内显示的内容,通过渲染器渲染到画布上去。

基本用法

  //初始化场景
    const scene = new Three.Scene(); //实例化场景

    //初始化相机 参数: 人视野的范围,全景宽高比,近裁面(离人眼最近的距离),远裁面(离人眼最远的距离)
    const camera = new Three.PerspectiveCamera(
      45,
      window.innerWidth / window.innerHeight,
      0.1,
      200
    );
    camera.position.set(0, 0, 15);

    //创建一个几何体
    //几何体宽高  宽,高,深度
    const geomerty = new Three.CubeGeometry(4,2,4)
    //材质 不反射光
    const materital = new Three.MeshBasicMaterial({color: '#fff'})
    // 通过立体+材质创建了一个几何体
    const cube = new Three.Mesh(geomerty, materital)

    //将几何体放入场景
    scene.add(cube)

    //初始化渲染器
     //渲染器 antialias抗锯齿,渲染器渲染出来的就是canvas标签,需要插入documetn上
     const renderer = new Three.WebGLRenderer({antialias: true});
     renderer.setSize(innerWidth, window.innerHeight);
     document.body.appendChild(renderer.domElement);

     //渲染,放入场景和相机
     renderer.render(scene, camera )
  • 初始化一个场景
  • 初始化一个相机,目前我们使用的是透视相机,他的位置在
    在这里插入图片描述
    这种比较符合人的眼睛
    除此自外还有一种正交相机。
    在这里插入图片描述
    他的坐标轴跟几何体是一样的。
  • 设置相机的位置。camera.position.set(4, 2, 6);xyz轴。
    在这里插入图片描述
    在这里插入图片描述

这就是相机的坐标轴(右手坐标系),如果设置0,0,6,那么他只看到z那一面
在这里插入图片描述
。设置了426之后
在这里插入图片描述
有点立体的效果了。

  • 创建一个几何体
  • 将几何体放入相机
  • 初始化渲染器,并将渲染器渲染出的canvas插入document
  • 将场景和相机放入渲染器
//初始化场景
    const scene = new Three.Scene(); //实例化场景

    //初始化相机 参数: 人视野的范围,全景宽高比,近裁面(离人眼最近的距离),远裁面(离人眼最远的距离)
    const camera = new Three.PerspectiveCamera(
      100,
      window.innerWidth / window.innerHeight,
      0.1,
      200
    );
    // 设置相机
    camera.position.set(4, 2, 6);

    //创建一个几何体
    //几何体宽高  宽,高,深度
    const geomerty = new Three.CubeGeometry(4, 2, 4);
    //材质 不反射光
    const materital = new Three.MeshLambertMaterial({ color: "#eee" });
    const cube = new Three.Mesh(geomerty, materital);

    //将几何体放入场景
    scene.add(cube);

    //来点光照
    const dirctionalLight = new Three.DirectionalLight("#fff", 1.1);
    dirctionalLight.position.set(3, 10, 5);
    // 光照也需要放入场景
    scene.add(dirctionalLight);

    //初始化渲染器
    //渲染器 antialias抗锯齿,渲染器渲染出来的就是canvas标签,需要插入documetn上
    const renderer = new Three.WebGLRenderer({ antialias: true });
    renderer.setSize(innerWidth, window.innerHeight);
    document.body.appendChild(renderer.dom Element);

    //渲染,放入场景和相机
    renderer.render(scene, camera);

新增一些光照,并且几何体的材质改成反光的。
在这里插入图片描述
可以看到比较明显的立体感。
动画效果:不断地移动相机就行

 let index = 8;
    function render() {
      index -= 0.1;
      if (index > -8) {
        console.log(123123);
        camera.position.set(index, 2, 6);
        //改完坐标需要重新渲染
        renderer.render(scene, camera);
        requestAnimationFrame(render);
      }
    }
    render();

在这里插入图片描述
以上我们就基于three.js完成了一个小的demo.

总结:

three.js三要素,场景,相机,渲染器。
可以创建几何体并且设置大小,放入场景。
相机必须调整好位置,做好拍照准备。
然后将场景和相机放入渲染器(renderer.render(xx,xx)),相机就会根据自身位置以及场景内容“拍照”,最终反映到渲染器的canvas元素,将其插入dom中即可看到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coderlin_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值