跳到主要内容

使用矢量图形节点

  Dora SSR 基于 nanovg 库,提供了一套强大的矢量图形绘制功能。本教程将引导您在 Dora SSR 中使用这些矢量图形功能。您将学习如何创建矢量图形节点、渲染形状、应用变换,以及加载和显示 SVG 文件。

1. 简介​

  矢量图形允许使用数学方程而非像素网格来创建可缩放、与分辨率无关的图像。Dora SSR 的矢量图形功能基于 nanovg 库,提供了基础的类似于 HTML5 Canvas 的矢量绘图 API。并且可以和 Dora SSR 的场景节点系统进行集成使用。

  在本教程中,我们将探索如何使用 Dora SSR 的矢量图形 API 来:

  • 创建矢量图形节点(VGNode)
  • 直接在屏幕上绘制矢量图形
  • 渲染形状和路径
  • 应用变换
  • 加载和显示 SVG 文件

2. 使用 VGNode​

  VGNode 是 Dora SSR 中用于将矢量图形静态渲染到一张纹理上,并挂载到游戏场景中展示的节点。所以它的内部包含了一张用于绘制矢量图形的帧缓冲纹理,并且本身是一个场景节点对象。要创建一个 VGNode,您需要指定其尺寸,以及可选的缩放比例和边缘抗锯齿系数。

2.1 创建节点对象​

local VGNode <const> = require("VGNode")

-- 创建一个宽800,高600,默认缩放比例和边缘抗锯齿的 VGNode
local node = VGNode(
800, -- 帧缓冲纹理的宽度
600, -- 帧缓冲纹理的高度
1.0, -- 可选渲染单位的缩放比例。默认值为 `1.0`
1 -- 可选的边缘抗锯齿系数。默认值为 `1`
)

  这将创建一个 VGNode 实例,我们将使用它把矢量图形渲染到自带的帧缓冲纹理上。

2.2 渲染矢量图形​

  要渲染矢量图形,使用 VGNode 实例的 render 方法。您需要传递一个包含使用 nvg 模块的绘图命令的函数(闭包)。这些绘图命令会将图形绘制到 VGNode 的帧缓冲纹理上。

  nvg 模块提供了绘制矩形、圆形、线条和路径等基本形状的函数。您还可以使用颜色和画笔来自定义形状的外观。

示例:绘制矩形​

local VGNode <const> = require("VGNode")
local nvg <const> = require("nvg")
local Color <const> = require("Color")

local node = VGNode(200, 150)

node:render(function()
nvg.BeginPath() -- 开始新路径
nvg.Rect(0, 0, 200, 150) -- x, y, 宽度, 高度
nvg.FillColor(Color(255, 0, 0, 255)) -- 红色
nvg.Fill()
end)

  上述代码绘制了一个宽 200、高 150 的红色矩形。并且 render 方法只会在第一次调用时执行,之后会自动缓存渲染结果进行复用。

提示

  使用 VGNode 渲染矢量图形时,坐标系原点在节点纹理的左上角,x 轴向右,y 轴向下。以纹理像素乘以缩放值为图形计算单位。

示例:绘制圆形​

local VGNode <const> = require("VGNode")
local nvg <const> = require("nvg")
local Color <const> = require("Color")

local node = VGNode(100, 100)

node:render(function()
nvg.BeginPath()
nvg.Circle(50, 50, 50) -- 中心 x, y 和半径
nvg.FillColor(Color(255, 255, 0, 255)) -- 黄色
nvg.Fill()
end)

  该代码绘制了一个半径为 50 的黄色圆形。同样,render 方法只会执行一次,并缓存渲染结果进行复用。

3. 直接绘制矢量图形到屏幕​

  除了使用 VGNode,Dora SSR 还支持直接在屏幕缓冲区的最上层绘制矢量图形。只需在每一帧调用 nvg 模块的绘图函数,即可直接将矢量图形绘制到屏幕上,无需借助 VGNode。

local nvg <const> = require("nvg")
local Color <const> = require("Color")
local threadLoop <const> = require("threadLoop")

threadLoop(function()
nvg.BeginPath()
nvg.Rect(100, 100, 200, 150)
nvg.FillColor(Color(255, 0, 0, 255))
nvg.Fill()
end)

  上述代码在屏幕上绘制了一个红色矩形。请注意,这种方式会直接绘制到屏幕缓冲区,并覆盖下面的游戏场景。比较适合用于绘制游戏的 HUD 界面、显示调试信息等。

提示

  使用这种绘制方式时,坐标系原点在屏幕左上角,x 轴向右,y 轴向下。在屏幕的可见区,坐标横轴的最大值为 App.visualSize.width,纵轴的最大值为 App.visualSize.height。

3.1 结合游戏场景节点和矢量图形​

  您可以使用 nvg.ApplyTransform(node) 函数将一个场景节点的变换应用到要绘制的矢量图形上。这样您可以在游戏场景中,用更便捷的方式,通过控制节点的变换来改变矢量图形的位置、旋转和缩放。

local nvg <const> = require("nvg")
local Color <const> = require("Color")
local Node <const> = require("Node")
local Size <const> = require("Size")
local Scale <const> = require("Scale")

local node = Node()
node.size = Size(200, 150)
node:onRender(function()
nvg.ApplyTransform(node)
nvg.BeginPath()
nvg.Rect(0, 0, 200, 150)
nvg.FillColor(Color(255, 0, 0, 255))
nvg.Fill()
end)

node.x = 50
node.y = 50
node.angle = 45
node:perform(Scale(0.5, 0, 1))

  上述代码创建了一个节点,将一个红色矩形绘制到节点上。然后,通过设置节点的位置、旋转控制矩形的显示效果,并通过在节点上播放缩放动作来控制矩形的缩放。

提示

  使用 nvg.ApplyTransform(node) 函数后,矢量图形的坐标系原点会改变为场景节点的左下角,并且 x 轴向右,y 轴变为向上。节点的缩放、旋转和位置变换会应用到矢量图形的绘制上。建议使用节点的 onRender 方法来绘制矢量图形,因为 onRender 方法在每一帧都会被调用,并且能确保它的调用顺序与场景树的渲染顺序一致,如使子节点在父节点之后渲染。

4. 使用颜色和画笔​

  您可以使用颜色和画笔来自定义形状的外观。

填充和描边颜色​

  • nvg.FillColor(color):设置填充颜色。
  • nvg.StrokeColor(color):设置描边(轮廓)颜色。
  • nvg.StrokeWidth(width):设置描边宽度。

示例:填充和描边​

local nvg <const> = require("nvg")
local Color <const> = require("Color")
local threadLoop <const> = require("threadLoop")

threadLoop(function()
nvg.BeginPath()
nvg.Rect(10, 10, 100, 80)
nvg.FillColor(Color(255, 0, 255, 255)) -- 粉色填充
nvg.Fill()
nvg.StrokeColor(Color(255, 255, 0, 255)) -- 黄色描边
nvg.StrokeWidth(5)
nvg.Stroke()
end)

5. 应用变换​

  变换允许您通过平移、旋转或缩放来操作形状。

变换函数​

  • nvg.Translate(x, y):移动坐标系。
  • nvg.Rotate(angle):旋转坐标系(角度以度为单位)。
  • nvg.Scale(sx, sy):缩放坐标系。
  • nvg.Save():保存当前变换状态。
  • nvg.Restore():恢复上一次保存的状态。

示例:旋转矩形​

local nvg <const> = require("nvg")
local Color <const> = require("Color")
local threadLoop <const> = require("threadLoop")

local function Rect(x, y, angle)
nvg.Save()
nvg.Translate(x, y) -- 移动
nvg.Rotate(angle) -- 旋转
nvg.BeginPath()
nvg.Rect(-100, -50, 200, 100) -- 中心对齐的矩形
nvg.FillColor(Color(255, 128, 0, 128)) -- 褐色
nvg.Fill()
nvg.Restore()
end

threadLoop(function()
-- 绘制几何变换互不影响的矩形
Rect(300, 200, 45)
Rect(100, 200, 90)
end)

  上述代码绘制了两个旋转的矩形,一个顺时针旋转 45 度,另一个顺时针旋转 90 度。它们的旋转中心都在矩形的中心,同时它们各自执行的几何变换互不影响。

6. 加载和渲染 SVG 文件​

  Dora SSR 提供了一个 SVG 类,用于加载和渲染 SVG 文件。请注意,目前仅支持一部分可以通过 picosvg 工具处理简化的 SVG 文件。

6.1 加载和直接渲染 SVG 图形​

local SVG <const> = require("SVG")
local threadLoop <const> = require("threadLoop")

local svg = SVG("Image/Dora.svg")

threadLoop(function()
-- 在每一帧调用 SVG 实例的 `render` 方法来显示它。
svg:render()
end)

6.2 使用场景节点控制 SVG 图形渲染​

  您可以使用场景节点来控制 SVG 图形的位置、旋转和缩放。

local SVG <const> = require("SVG")
local Node <const> = require("Node")
local nvg <const> = require("nvg")

local svg = SVG("Image/Dora.svg")

local node = Node()
node:onRender(function()
nvg.ApplyTransform(node)
nvg.Scale(0.2, -0.2)
nvg.Translate(-566.5, -566.5)
svg:render()
end)

node.angle = 45

  上述代码创建了一个节点,将 SVG 图形渲染绑定到节点上。然后,通过设置节点的旋转控制 SVG 图形的显示效果。

7. 总结​

  在本教程中,我们介绍了如何使用 Dora SSR 的矢量图形功能来绘制形状、应用变换和渲染 SVG 文件。利用这些工具,您可以为您的应用程序创建丰富的矢量图形和动画。

  请记住,nvg 模块还提供了更多高级绘图和文本渲染的函数。您可以探索诸如 nvg.Text、nvg.FontFace 和渐变画笔如 nvg.LinearGradient 等函数,以实现更复杂的图形。

  欢迎您尝试不同的形状、颜色和变换,创造独特的 Dora SSR 矢量图形项目!