You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Nim语言的Chipmunk7绑定中正确调用eachShape迭代器

问题描述

我正在使用Nim语言的chipmunk7库绑定,尝试调用迭代器eachShape。绑定的相关代码如下:

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语言的迭代器调用示例,想请教该迭代器的正确调用语法是什么?

解决方法

当前绑定的eachShape是C风格的回调式接口,并非Nim原生的迭代器,所以不能直接用for...in语法遍历。你可以按照以下两种方式调用:

方式1:直接使用回调函数

定义一个符合SpaceShapeIteratorFunc类型的回调proc,把绘制逻辑放在里面,然后传给eachShape:

proc drawShapeCallback(shape: Shape; data: pointer) {.cdecl.} =
  case shape.shapeType
  of ShapeType.circle:
    let circle = shape as CircleShape
    drawCircle(circle.body.position, circle.radius, circle.body.angle, kColorBlack)
  of ShapeType.segment:
    let segment = shape as SegmentShape
    drawSegment(segment, kColorBlack)
  of 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*() =
  # 调用eachShape,传入回调函数,data参数不需要的话传nil
  eachShape(space, drawShapeCallback, nil)

方式2:封装成Nim迭代器(推荐)

如果想使用for...in的语法,可以自己封装一个Nim迭代器,把回调逻辑包装起来:

iterator eachShape*(space: Space): Shape =
  var currentShape: Shape
  proc captureShape(shape: Shape; data: pointer) {.cdecl.} =
    currentShape = shape
    yield currentShape
  eachShape(space, captureShape, nil)

# 现在就可以用你原本的for循环写法了
proc drawChipmunkHello*() =
  for shape in eachShape(space):
    case shape.shapeType
    of ShapeType.circle:
      let circle = shape as CircleShape
      drawCircle(circle.body.position, circle.radius, circle.body.angle, kColorBlack)
    of ShapeType.segment:
      let segment = shape as SegmentShape
      drawSegment(segment, kColorBlack)
    of 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)

封装迭代器时,yield会在回调被调用时触发,从而实现逐个返回Shape对象的效果,完全适配你原本的遍历逻辑。

内容的提问来源于stack exchange,提问作者Nino van Hooff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 20:00:24