致敬童年系列----切水果3(canvas)(水果轨迹与图形绘制)

在讲解优美水果模型之前,作者想为大家分享下水果模型是如何动起来的,以及我们是如何基本绘制的😎


水果的运动

一个二维物体,为了方便其运动,我们可以建系来控制其轨迹。

是不是梦回高中数学了呢🤓🐣

废话少说,直接上代码:

       class GameObject {
           constructor(x, y, type) { // 构造函数
               this.x = x; // 初始化x坐标
               this.y = y; // 初始化y坐标
               this.type = type; // 初始化类型
               this.sliced = false; // 初始化切割状态
               this.velocityX = Math.random() * 5 - 4; // 初始化x方向速度
               this.velocityY = -15 - Math.random() * 3; // 初始化y方向速度
               this.gravity = 0.3; // 初始化重力
               this.rotation = 0; // 初始化旋转角度
               this.rotationSpeed = Math.random() * 0.5 - 0.05; // 初始化旋转速度

定义了一个名为 GameObject 的 JavaScript 类,它用于创建具有特定属性和行为的游戏对象。

很明显,先用constructor来构造函数

x,y对应初始坐标(二维坐标系)

type:定义对象类型,其值由constructor传入的参数决定。

this.sliced=false,false为布尔属性,这里表示默认未被切割。

•  this.velocityX 和 this.velocityY 分别表示对象在 x 方向和 y 方向上的速度。

•  Math.random() 返回一个 0(包含)到 1(不包含)之间的随机数。

•  Math.random() * 5 - 4 的结果范围是 -4 到 1,表示 x 方向的速度在 -4 到 1 之间随机变化。

•  -15 - Math.random() * 3 的结果范围是 -18 到 -15,表示 y 方向的速度始终为负(向上移动),且在 -18 到 -15 之间随机变化。

• this.rotation 表示对象的旋转角度,初始值为 0。
• this.rotationSpeed 表示对象的旋转速度,其值由 Math.random
()*0.5- 0.05 计算得出,范围是-0.05 到 0.45。
•这意味着对象在创建时会随机获得一个旋转速度,可能是顺时针或逆时针旋转。

总结:

1. 位置:由x和y坐标确定。
2. 类型:由type 属性标识。
3. 状态:是否被切割(sliced)。
4. 运动:具有水平和垂直方向的速度(velocityX 和 velocityY),受到重力影响(gravity)。
5. 旋转:具有初始旋转角度(rotation) 和随机的旋转速度(rotationSpeed).

反正该有的我觉得都有了😋🫵


绘图

在绘制前,作者为大家介绍一位新朋友

canvas api


HTML5 Canvas 是一种通过 JavaScript 绘制图形的技术。它在网页上提供了一个绘图区域,开发者可以使用 Canvas API 在这个区域上绘制各种图形、图像和文本,实现丰富的视觉效果
1. canvas 元素:
   - 在 HTML 中,使用 <canvas>标签定义绘图区域。
   示例

     <canvas id="myCanvas" width="800" height="600"></canvas>

width 和 height属性定义了画布的宽度和高度。

2. 绘图上下文(Context): 通过 canvas.getContext('2d') 获取 2D 绘图上下文对象。
   示例:

     const canvas = document.getElementById('myCanvas');
     const ctx = canvas.getContext('2d');

 绘制图形

矩形

填充矩形:

  ctx.fillRect(x, y, width, height);

x、y:矩形左上角的坐标。
width、height:矩形的宽度和高度。

描边矩形:

  ctx.strokeRect(x, y, width, height);

 路径


开始路径:

  ctx.beginPath();

移动画笔:

  ctx.moveTo(x, y);

绘制直线:


  ctx.lineTo(x, y);

绘制曲线:

具体贝塞尔曲线画法及原理 可以看作者的 致敬童年系列--切水果2


  二次贝塞尔曲线:

    ctx.quadraticCurveTo(cpx, cpy, x, y);

cpx、cpy:控制点的坐标。
x、y:终点的坐标。

三次贝塞尔曲线:

    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);

cp1x、cp1y:第一个控制点的坐标。
cp2x、cp2y:第二个控制点的坐标。
x、y:终点的坐标。


绘制弧形:

  ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

x、y:圆心的坐标。
radius:半径。
startAngle:起始角度(以弧度为单位)。
endAngle:结束角度(以弧度为单位)。
anticlockwise:可选,布尔值,指定弧形的方向(顺时针或逆时针)。

关闭路径:

  ctx.closePath();

填充路径:

  ctx.fill();

描边路径:

  ctx.stroke();

 圆形

绘制圆形:

  ctx.arc(x, y, radius, 0, Math.PI * 2);
  ctx.fill();

样式和颜色


1.填充颜色:

   ctx.fillStyle = color;

color可以是颜色名称、十六进制颜色值或 rgba 颜色值。

2.描边颜色:

   ctx.strokeStyle = color;

3.线条宽度:

   ctx.lineWidth = width;

4.线条样式:
   虚线:

  ctx.setLineDash([5, 15]);

参数是一个数组,表示虚线的绘制模式。

5. 渐变:
   线性渐变:

    const gradient = ctx.createLinearGradient(x0, y0, x1, y1);
     gradient.addColorStop(offset, color);
     ctx.fillStyle = gradient;

     x0,y0:渐变起点的坐标。
     x1、y1:渐变终点的坐标。
     offset:颜色停止点的位置(范围 0 到 1)。
     color:颜色值。

   径向渐变

     const gradient = ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
     gradient.addColorStop(offset, color);
     ctx.fillStyle = gradient;


    x0、y0、r0:内圆的圆心坐标和半径。
    x1、y1、r1:外圆的圆心坐标和半径。

6. 图案填充

   const pattern = ctx.createPattern(image, repetition);
   ctx.fillStyle = pattern;


   image:用于填充的图像。
   repetition:指定图案的重复方式(repeat、repeat-x、repeat-y,no-repeat)。


绘制文本


1. 填充文本

   ctx.fillText(text, x, y, maxWidth);

text:要绘制的文本。
x、y:文本的左上角坐标。
maxWidth:可选,文本的最大宽度。

2. 描边文本

   ctx.strokeText(text, x, y, maxWidth);

3. 文本样式:
 字体

ctx.font = 'italic bold 20px Arial';

  文本对齐方式  

ctx.textAlign = 'start' | 'end' | 'left' | 'right' | 'center';

  文本基线

     ctx.textBaseline = 'top' | 'hanging' | 'middle' | 'alphabetic' | 'ideographic' | 'bottom';

图像操作


1.绘制图像:

   ctx.drawImage(image, dx, dy, dWidth, dHeight);

  image:要绘制的图像。
  dx,dy:图像在画布上的左上角坐标。
  dWidth、dHeight:可选,图像在画布上的宽度和高度。

2. 从画布创建图像:

  const image = canvas.toDataURL('image/png');

变换


1. 保存和恢复绘图状态:

   ctx.save();
   // 绘图操作
   ctx.restore();

2. 平移

   ctx.translate(x, y);

3. 旋转

   ctx.rotate(angle);

 angle:旋转角度(以弧度为单位)。

4. 缩放:

   ctx.scale(x, y);

合成和裁剪


1.合成模式:

   ctx.globalCompositeOperation = 'source-over' | 'source-in' | 'source-out' | 'source-atop' | 'destination-over' | 'destination-in' | 'destination-out' | 'destination-atop' | 'lighter' | 'copy' | 'xor';

2. 剪区域

   ctx.clip();

事件处理


Canvas 本身不支持事件处理,但可以通过监听画布上的事件(如鼠标事件或触摸事件)来实现交互功能。


动画


通过不断清除画布并重新绘制图形,可以实现动画效果。通常使用 requestAnimationFrame 来实现流畅的动画。

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // 绘图操作
  requestAnimationFrame(animate);
}

animate();

相关绘制效果图

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas 线条绘制</title>
    <style>
        canvas {
            border: 1px solid #000;
        }
    </style>
</head>
<body>
    <canvas id="myCanvas" width="800" height="600"></canvas>

    <script>
        // 获取 canvas 元素和绘图上下文
        const canvas = document.getElementById('myCanvas');
        const ctx = canvas.getContext('2d');

        // 模拟切割轨迹数据
        let sliceActive = true;
        let sliceTrail = [
            { x: 100, y: 100 },
            { x: 200, y: 150 },
            { x: 300, y: 100 },
            { x: 400, y: 200 },
            { x: 500, y: 150 }
        ];

        // 绘制切割轨迹
        function drawSliceTrail() {
            if (sliceActive && sliceTrail.length > 1) {
                ctx.beginPath();
                ctx.moveTo(sliceTrail[0].x, sliceTrail[0].y);
                for (let i = 1; i < sliceTrail.length; i++) {
                    ctx.lineTo(sliceTrail[i].x, sliceTrail[i].y);
                }
                ctx.strokeStyle = 'blue';
                ctx.lineWidth = 5;
                ctx.lineCap = 'round';
                ctx.lineJoin = 'round';
                ctx.stroke();
                ctx.shadowColor = '#FFF';
                ctx.shadowBlur = 15;
                ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
                ctx.lineWidth = 15;
                ctx.stroke();
                ctx.shadowBlur = 0;
            }
        }

        // 调用绘制函数
        drawSliceTrail();
    </script>
</body>
</html>

下面是成果图

代码与成果图目的均为帮助大家复习本文知识

小结

本文主要讲了关于水果轨迹及水果图形的基本绘制,同时引入了canvas的相关知识,帮助大家更好的绘制相关的模型,体验游戏制作的乐趣。

下期预告

致敬童年系列----切水果4,将考虑讲解切割模型的制作或者是监听事件的完成,学业最近过多,更新速度会减缓些,感谢您的谅解与阅读,期待你的关注🫵🫵🤓🥳

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值