NodeJS: 用Canvas生成游戏资源图片

3,282 阅读4分钟

当代游戏开发中,图像资源在游戏的视觉呈现和用户体验中起着至关重要的作用。对于独立开发者来说,如果没有美术设计的支持或者对Photoshop等图像处理工具不够熟悉,生成自己想要的游戏资源图片可能会成为一项挑战。在这种情况下,使用Node.js和Canvas来生成游戏资源图片是一个不错的选择。

Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,它允许我们在服务器端使用JavaScript进行开发。而Canvas是一个HTML5的绘图API,可以在服务器端使用Node.js模块进行图像处理和绘制操作。

在本文中,将介绍如何使用Node.js和Canvas来生成游戏资源图片。

准备工作

在开始之前,确保已经安装了Node.js和Canvas模块。您可以在Node.js的官方网站(nodejs.org)下载并安装最新版本的Node.js。安装完成后,打开命令行工具,并执行以下命令来安装Canvas模块:

npm install canvas

一旦安装完成,我们就可以开始编写代码来生成游戏资源图片了。

创建画布和上下文

首先,我们需要创建一个画布(Canvas)来绘制图像。在Node.js中,我们可以使用Canvas模块的createCanvas函数来创建画布,并使用getContext方法获取画布的上下文(Context)。

const { createCanvas } = require('canvas');

const canvasWidth = 800; // 画布宽度
const canvasHeight = 600; // 画布高度

const canvas = createCanvas(canvasWidth, canvasHeight);
const ctx = canvas.getContext('2d');

在上述代码中,我们创建了一个800x600像素大小的画布,并获取了2D上下文。

绘制图像

接下来,我们可以使用Canvas的绘图API来绘制图像。Canvas提供了丰富的绘制函数,包括绘制形状、路径、文本和图像等。

例如,我们可以使用drawImage方法来绘制一张图片:

const { loadImage } = require('canvas');

// 加载图像
const image = await loadImage('image.png');

// 绘制图像
ctx.drawImage(image, 0, 0);

上述代码中,我们使用loadImage函数加载了一张名为image.png的图像文件,并使用drawImage方法将其绘制在画布上。

图像编辑和处理

除了简单地绘制图像外,我们还可以使用Canvas进行图像编辑和处理。例如,我们可以裁剪图像、改变图像大小、旋转图像,

甚至应用滤镜效果。

下面是一些常见的图像处理操作示例:

裁剪图像:

const { createImageData } = require('canvas');

// 裁剪图像
const imageData = ctx.getImageData(x, y, width, height);
const croppedCanvas = createCanvas(width, height);
const croppedCtx = croppedCanvas.getContext('2d');
croppedCtx.putImageData(imageData, 0, 0);

缩放图像:

// 缩放图像
const scaledCanvas = createCanvas(newWidth, newHeight);
const scaledCtx = scaledCanvas.getContext('2d');
scaledCtx.drawImage(image, 0, 0, newWidth, newHeight);

旋转图像:

// 旋转图像
ctx.translate(canvasWidth / 2, canvasHeight / 2);
ctx.rotate(angleInRadians);
ctx.drawImage(image, -image.width / 2, -image.height / 2);

应用滤镜效果:

// 应用滤镜效果
ctx.filter = 'blur(5px)';
ctx.drawImage(image, 0, 0);

保存图像

最后,当我们完成了图像处理和编辑后,我们可以将生成的图像保存到本地或者输出到客户端。

const fs = require('fs');

// 保存图像到本地
const outputPath = 'output.png';
const outputStream = fs.createWriteStream(outputPath);
const stream = canvas.createPNGStream();
stream.pipe(outputStream);
outputStream.on('finish', () => {
  console.log(`图像已保存到 ${outputPath}`);
});

// 将图像输出到客户端
const imageBuffer = canvas.toBuffer('image/png');
response.setHeader('Content-Type', 'image/png');
response.end(imageBuffer);

在上述代码中,我们使用Node.js的fs模块创建了一个写入流(WriteStream),并使用Canvas的createPNGStream方法创建了一个PNG图像流。然后,我们将图像流导入到写入流中,将生成的图像保存到本地。

如果要将图像输出到客户端,我们可以使用canvas.toBuffer方法将画布转换为图像数据的Buffer,然后通过HTTP响应将图像数据发送给客户端。

例子

接下来来看一个在cocoscreator中的例子

overstep.gif

这个动画除了美术提供的头像和金框外,还需要一个白色圆环和一个像素由中间向外渐变透明的圆

image.png

仔细看了下这个圆环的像素透明度也是从里向外平滑的渐变,接下来实现这两张图片。

像素透明度由内向外平滑渐变的圆环

创建一个名为vague_circle.js的文件, 代码如下:

const { createCanvas, loadImage } = require('canvas');
const fs = require('fs');

// 图像尺寸
const width = 200;
const height = 200;

// 创建画布
const canvas = createCanvas(width, height);
const context = canvas.getContext('2d');

// 绘制函数
function draw() {
  // 清空画布
  context.clearRect(0, 0, width, height);

  // 设置抗锯齿
  context.antialias = 'subpixel';

  // 绘制圆
  const centerX = width / 2;
  const centerY = height / 2;
  const outerRadius = 0.5 * Math.min(width, height);
  const innerRadius = 0.4 * Math.min(width, height);

  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const distanceFromCenter = Math.hypot(x - centerX, y - centerY);
      const gradient = smoothstep(innerRadius, outerRadius, distanceFromCenter);
      const alpha = 1.0 - gradient;

      if (distanceFromCenter <= outerRadius && distanceFromCenter >= innerRadius) {
        context.fillStyle = `rgba(255, 255, 255, ${alpha})`;
        context.fillRect(x, y, 1, 1);
      }
    }
  }

  // 保存图像为文件
  const fileName = 'vague_circle.png';
  const filePath = __dirname + '/' + fileName;
  const buffer = canvas.toBuffer('image/png');
  fs.writeFileSync(filePath, buffer);

  console.log('生成红色圆成功!保存路径:', filePath);
}

// 平滑阶梯函数
function smoothstep(min, max, value) {
  const x = Math.max(0, Math.min(1, (value - min) / (max - min)));
  return x * x * (3 - 2 * x);
}

// 运行绘制函数
draw();

执行node vague_circle.js后,得到图片

image.png

像素由中间向外渐变透明的圆 创建一个名为glow_circle.js,代码如下:

const { createCanvas, loadImage } = require('canvas');
const fs = require('fs');

// 图像尺寸
const width = 200;
const height = 200;

// 创建画布
const canvas = createCanvas(width, height);
const context = canvas.getContext('2d');

// 绘制函数
function draw() {
  // 清空画布
  context.clearRect(0, 0, width, height);

  // 绘制图像
  const imageData = context.createImageData(width, height);
  const pixels = imageData.data;

  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const index = (y * width + x) * 4;

      const v_uv0 = [
        (x + 0.5) / width,
        (y + 0.5) / height
      ];

      const o = [1, 1, 1, 1];

      const distanceFromCenter = Math.hypot(v_uv0[0] - 0.5, v_uv0[1] - 0.5);
      const radius = 0.5;
      const glowIntensity = 0.6;
      const glowWidth = 0.1;

      if (distanceFromCenter > radius) {
        o[3] = 0;
      } else {
        const glowFactor = smoothstep(0.5, 0.1, Math.abs(Math.sqrt(Math.pow(v_uv0[0] - 0.5, 2) + Math.pow(v_uv0[1] - 0.5, 2))));
        o[3] *= glowFactor;
      }

      // 像素颜色写入像素数据
      pixels[index] = o[0] * 255;
      pixels[index + 1] = o[1] * 255;
      pixels[index + 2] = o[2] * 255;
      pixels[index + 3] = o[3] * 255;
    }
  }

  // 将像素数据绘制到画布上
  context.putImageData(imageData, 0, 0);

  // 保存图像为文件
  const fileName = 'glow_circle.png';
  const filePath = __dirname + '/' + fileName;
  const buffer = canvas.toBuffer('image/png');
  fs.writeFileSync(filePath, buffer);

  console.log('生成图像成功!保存路径:', filePath);
}

// 平滑阶梯函数
function smoothstep(min, max, value) {
  const x = Math.max(0, Math.min(1, (value - min) / (max - min)));
  return x * x * (3 - 2 * x);
}

// 运行绘制函数
draw();

执行node glow_circle.js后,得到图片

image.png

上述的图片用shader也很容易就可以做到,但由于shader有打断渲染合批,因此能用图片就尽量用图片来展示。

结语

使用Node.js和Canvas来生成游戏资源图片是一种简单而灵活的方式,特别适合独立开发者或不熟悉图像处理工具的开发者。通过Canvas的丰富绘图API和图像处理功能,您可以创建自己想要的游戏资源图片,包括角色、背景、道具等。

在本文中,我们简要介绍了如何使用Node.js和Canvas来生成游戏资源图片,并提供了一些基本的示例代码。您可以根据自己的需求和创意,进一步探索Canvas的功能,并创建出独特而精美的游戏图像。

希望这篇博文对您有所帮助,祝您在游戏开发中取得成功!