我正在使用chipmunk7库绑定,并尝试调用迭代器
eachShape
。绑定源是here
SpaceShapeIteratorFunc* = proc (shape: Shape; data: pointer) {.cdecl.}
## Space/body iterator callback function type.
[..]
proc eachShape*(space: Space; `func`: SpaceShapeIteratorFunc; data: pointer) {.cdecl, importc: "cpSpaceEachShape".}
## Call `func` for each shape in the space.
然后这样打电话
import std/math
import chipmunk7
import playdate/api
var gravity = v(0, 100)
var timeStep = 1.0/50.0
var time = 0.0
var space = newSpace()
space.gravity = gravity
[..]
proc drawChipmunkHello*() =
# iterate over all shapes in the space
for shape in eachShape(space):
if shape.shapeType == ShapeType.circle:
let circle = shape as CircleShape
drawCircle(circle.body.position, circle.radius, circle.body.angle, kColorBlack)
elif shape.shapeType == ShapeType.segment:
let segment = shape as SegmentShape
drawSegment(segment, kColorBlack)
elif shape.shapeType == ShapeType.poly:
let poly = shape as PolyShape
for i in 0 ..< poly.count:
let a = poly.getVert(i)
let b = poly.getVert((i + 1) % poly.count)
playdate.graphics.drawLine(a.x.toInt, a.y.toInt, b.x.toInt, b.y.toInt, 1, kColorBlack);
我收到编译器错误
hello.nim(63, 25) Error: type mismatch: got <Space>
but expected one of:
proc eachShape(space: Space; func: SpaceShapeIteratorFunc; data: pointer)
first type mismatch at position: 2
missing parameter: func
1 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
第 63 行是
drawChipmunkHello()
的第一行
如何调用迭代器的 c 示例是 here
调用迭代器的正确语法是什么?
Chipmunk 所说的迭代器和 Nim 所说的迭代器是两个不同的东西。对于具有一个参数的 Nim 迭代器,您尝试调用
eachShape
的方式确实是正确的。但是 Chipmunk 称为迭代器的三参数构造不能以这种方式调用。让我们看一下错误消息,它说 eachShape
给出了 <Space>
,即类型为 Space
的单个参数,但它期望:
proc eachShape(space: Space; func: SpaceShapeIteratorFunc; data: pointer)
first type mismatch at position: 2
missing parameter: func
这是三个参数
Space
、SpaceShapeIteratorFunc
和pointer
。它还告诉我们,类型不匹配发生在位置 2,并且失败是因为它只是缺少 func
参数,这是有道理的,因为我们只提供了一个 Space
参数。现在,让我们来看看SpaceShapeIteratorFunc
:
SpaceShapeIteratorFunc* = proc (shape: Shape; data: pointer) {.cdecl.}
## Space/body iterator callback function type.
正如我们所见,这只是一个带有
Shape
和 pointer
的过程的别名。它也被定义为 {.cdecl.}
,这仅意味着它遵循标准 C 调用约定。这意味着我们必须将循环体转换为过程,然后手动将该过程传递给迭代器。被 pointer
接受并被 SpaceShapeIteratorFunc
要求的 eachShape
是我们可以存储我们想要在迭代器中可用的任何上下文的地方。
让我们做一个简单的重写:
import std/math
import chipmunk7
import playdate/api
var gravity = v(0, 100)
var timeStep = 1.0/50.0
var time = 0.0
var space = newSpace()
space.gravity = gravity
[..]
proc shapeIter(shape: Shape, data: pointer) {.cdecl.} =
if shape.shapeType == ShapeType.circle:
let circle = shape as CircleShape
drawCircle(circle.body.position, circle.radius, circle.body.angle, kColorBlack)
elif shape.shapeType == ShapeType.segment:
let segment = shape as SegmentShape
drawSegment(segment, kColorBlack)
elif shape.shapeType == ShapeType.poly:
let poly = shape as PolyShape
for i in 0 ..< poly.count:
let a = poly.getVert(i)
let b = poly.getVert((i + 1) % poly.count)
playdate.graphics.drawLine(a.x.toInt, a.y.toInt, b.x.toInt, b.y.toInt, 1, kColorBlack);
proc drawChipmunkHello*() =
# iterate over all shapes in the space
eachShape(space, shapeIter, nil)
如您所见,我们现在将迭代器主体拆分为一个新过程
shapeIter
,它与 SpaceShapeIteratorFunc
的签名相匹配,并且我们将其与 eachShape
指针一起传递给 nil
,因为我们不不需要传递任何上下文。我们不必传递任何上下文的原因是因为所需的所有变量都位于我们模块的全局范围内。如果我们确实需要将一些上下文传递到迭代器的主体中,我们需要通过 data: pointer
字段传递它。这在 C 中很常见,但在 Nim 中可能有点麻烦。这是一个更高级的主题,但您可以为此使用 Nim 闭包,并分别使用 rawProc
和 rawEnv
获取过程和环境指针。请注意,rawProc
仍然具有{.nimcall.}
调用约定,因此需要调用者帮助程序。所有这些复杂性都可以放入自定义的 for 循环宏 中,此时您可以像在第一个示例中那样调用迭代器。但这正在进入一些相当复杂的领域。