如何用 Swift 创建波浪路径

2024-01-01

我希望我的节点以正弦曲线波行进,我尝试将其用于 CGPath。 如何创建遵循正弦曲线的 CGPath?除了手动查找曲线上的点之外,还有其他方法吗?或者我可以只传递正弦函数吗?

let action = SKAction.followPath(<the sine path>, asOffset: true, orientToPath: true, duration: 5)

可以通过Bezier Paths然后转换成CGPaths来完成吗? 谢谢。


不,没有内置方法可以从函数构建路径,但您可以轻松编写自己的方法。在斯威夫特 3 中:

/// Build path within rectangle
///
/// Given a `function` that converts values between zero and one to another values between zero and one, this method will create `UIBezierPath` within `rect` using that `function`.
///
/// - parameter rect:      The `CGRect` of points on the screen.
///
/// - parameter count:     How many points should be rendered. Defaults to `rect.size.width`.
///
/// - parameter function:  A closure that will be passed an floating point number between zero and one and should return a return value between zero and one as well.

private func path(in rect: CGRect, count: Int? = nil, function: (CGFloat) -> (CGFloat)) -> UIBezierPath {
    let numberOfPoints = count ?? Int(rect.size.width)

    let path = UIBezierPath()
    path.move(to: convert(point: CGPoint(x: 0, y: function(0)), in: rect))
    for i in 1 ..< numberOfPoints {
        let x = CGFloat(i) / CGFloat(numberOfPoints - 1)
        path.addLine(to: convert(point: CGPoint(x: x, y: function(x)), in: rect))
    }
    return path
}

/// Convert point with x and y values between 0 and 1 within the `CGRect`.
///
/// - parameter point:  A `CGPoint` value with x and y values between 0 and 1.
/// - parameter rect:   The `CGRect` within which that point should be converted.

private func convert(point: CGPoint, in rect: CGRect) -> CGPoint {
    return CGPoint(
        x: rect.origin.x + point.x * rect.size.width,
        y: rect.origin.y + rect.size.height - point.y * rect.size.height
    )
}

因此,让我们传递一个函数,该函数在穿过正弦曲线时执行一条正弦曲线width的 的rect:

func sinePath(in rect: CGRect, count: Int? = nil) -> UIBezierPath {
    // note, since sine returns values between -1 and 1, let's add 1 and divide by two to get it between 0 and 1
    return path(in: rect, count: count) { (sin($0 * .pi * 2.0) + 1.0) / 2.0 }
}

请注意,上面假设您想​​要从左到右遍历,构建由函数定义的路径。您还可以进行更多参数化再现:

/// Build path within rectangle
///
/// Given a `function` that converts values between zero and one to another values between zero and one, this method will create `UIBezierPath` within `rect` using that `function`.
///
/// - parameter rect:      The `CGRect` of points on the screen.
///
/// - parameter count:     How many points should be rendered. Defaults to `rect.size.width` or `rect.size.width`, whichever is larger.
///
/// - parameter function:  A closure that will be passed an floating point number between zero and one and should return a `CGPoint` with `x` and `y` values between 0 and 1.

private func parametricPath(in rect: CGRect, count: Int? = nil, function: (CGFloat) -> (CGPoint)) -> UIBezierPath {
    let numberOfPoints = count ?? max(Int(rect.size.width), Int(rect.size.height))

    let path = UIBezierPath()
    let result = function(0)
    path.move(to: convert(point: CGPoint(x: result.x, y: result.y), in: rect))
    for i in 1 ..< numberOfPoints {
        let t = CGFloat(i) / CGFloat(numberOfPoints - 1)
        let result = function(t)
        path.addLine(to: convert(point: CGPoint(x: result.x, y: result.y), in: rect))
    }
    return path
}

然后你可以修改x使用正弦曲线进行坐标,然后递增y:

func verticalSinePath(in rect: CGRect, count: Int? = nil) -> UIBezierPath {
    // note, since sine returns values between -1 and 1, let's add 1 and divide by two to get it between 0 and 1
    return parametricPath(in: rect, count: count) { CGPoint(
        x: (sin($0 * .pi * 2.0) + 1.0) / 2.0,
        y: $0
    ) }
}

这样做的好处是您现在还可以定义您想要的任何类型的路径,例如螺旋:

func spiralPath(in rect: CGRect, count: Int? = nil) -> UIBezierPath {
    return parametricPath(in: rect, count: count) { t in
        let r = 1.0 - sin(t * .pi / 2.0)
        return CGPoint(
            x: (r * sin(t * 10.0 * .pi * 2.0) + 1.0) / 2.0,
            y: (r * cos(t * 10.0 * .pi * 2.0) + 1.0) / 2.0
        )
    }
}

以下是上述内容的 Swift 2 版本:

/// Build path within rectangle
///
/// Given a `function` that converts values between zero and one to another values between zero and one, this method will create `UIBezierPath` within `rect` using that `function`.
///
/// - parameter rect:      The `CGRect` of points on the screen.
///
/// - parameter count:     How many points should be rendered. Defaults to `rect.size.width`.
///
/// - parameter function:  A closure that will be passed an floating point number between zero and one and should return a return value between zero and one as well.

private func path(in rect: CGRect, count: Int? = nil, function: (CGFloat) -> (CGFloat)) -> UIBezierPath {
    let numberOfPoints = count ?? Int(rect.size.width)

    let path = UIBezierPath()
    path.moveToPoint(convert(point: CGPoint(x: 0, y: function(0)), rect: rect))
    for i in 1 ..< numberOfPoints {
        let x = CGFloat(i) / CGFloat(numberOfPoints - 1)
        path.addLineToPoint(convert(point: CGPoint(x: x, y: function(x)), rect: rect))
    }
    return path
}

/// Convert point with x and y values between 0 and 1 within the `CGRect`.
///
/// - parameter point:  A `CGPoint` value with x and y values between 0 and 1.
/// - parameter rect:   The `CGRect` within which that point should be converted.

private func convert(point point: CGPoint, rect: CGRect) -> CGPoint {
    return CGPoint(
        x: rect.origin.x + point.x * rect.size.width,
        y: rect.origin.y + rect.size.height - point.y * rect.size.height
    )
}

func sinePath(in rect: CGRect, count: Int? = nil) -> UIBezierPath {
    // note, since sine returns values between -1 and 1, let's add 1 and divide by two to get it between 0 and 1
    return path(in: rect, count: count) { (sin($0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0 }
}

/// Build path within rectangle
///
/// Given a `function` that converts values between zero and one to another values between zero and one, this method will create `UIBezierPath` within `rect` using that `function`.
///
/// - parameter rect:      The `CGRect` of points on the screen.
///
/// - parameter count:     How many points should be rendered. Defaults to `rect.size.width`.
///
/// - parameter function:  A closure that will be passed an floating point number between zero and one and should return a `CGPoint` with `x` and `y` values between 0 and 1.

private func parametricPath(in rect: CGRect, count: Int? = nil, function: (CGFloat) -> (CGPoint)) -> UIBezierPath {
    let numberOfPoints = count ?? max(Int(rect.size.width), Int(rect.size.height))

    let path = UIBezierPath()
    let result = function(0)
    path.moveToPoint(convert(point: CGPoint(x: result.x, y: result.y), rect: rect))
    for i in 1 ..< numberOfPoints {
        let t = CGFloat(i) / CGFloat(numberOfPoints - 1)
        let result = function(t)
        path.addLineToPoint(convert(point: CGPoint(x: result.x, y: result.y), rect: rect))
    }
    return path
}

func verticalSinePath(in rect: CGRect, count: Int? = nil) -> UIBezierPath {
    // note, since sine returns values between -1 and 1, let's add 1 and divide by two to get it between 0 and 1
    return parametricPath(in: rect, count: count) { CGPoint(
        x: (sin($0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
        y: $0
    ) }
}

func spiralPath(in rect: CGRect, count: Int? = nil) -> UIBezierPath {
    return parametricPath(in: rect, count: count) { t in
        let r = 1.0 - sin(t * CGFloat(M_PI_2))
        return CGPoint(
            x: (r * sin(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
            y: (r * cos(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0
        )
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何用 Swift 创建波浪路径 的相关文章

  • 调用 SKLabelNode 时出现延迟?

    我在从一个版本转换时遇到了轻微延迟 滞后 的问题SKScene到另一个 通过注释掉各种代码 我将其范围缩小到SKLabelNode 我的猜测是 这就是它在调用时加载 缓存字体 这会导致在声明新字体时出现小的延迟 口吃SKScene 有没有其
  • 协议类型的 inout 变量是否被禁止?

    下面的代码 protocol SomeProtocol class SomeClass SomeProtocol private func doSomethingWith inout someVar SomeProtocol private
  • 迅速关闭模态并推送到新的 VC

    我有 tableview 1 表显示一个新的模式窗口 当我按下按钮时 我想关闭模式窗口并推送到 VC 我的代码仅隐藏模式视图 但不进行推送 IBAction func registrationBtn sender AnyObject let
  • 在 Swift 中使用 Container View 进行委托

    我正在为 iPad Pro 开发一个应用程序 在这个应用程序中 containerView用于添加额外的views并与他们互动 首先 我创建了一个协议 protocol DataViewDelegate func setTouch touc
  • 创建透明渐变并将其用作 SpriteKit 中的 alpha 遮罩

    我正在尝试制作渐变并将其用作 alpha 蒙版 现在 我能够制作与此类似的图像 从黑色到透明 这是我用来实现这一切的代码 private func createImage width CGFloat height CGFloat gt CG
  • 如何在 Swift 2.0 中将结构保存到 NSUserDefaults

    我有一个名为Jar我想将它们的数组保存到 NSUserDefaults 中 这是 jar 结构代码 struct Jar let name String let amount Int init name String amount Int
  • 在二维空间中从 A 点前往 B 点?

    我正在开发一个项目 需要我计算从可变点 A 到可变点 B 的 0 360 度航向 以使 A 点的物体面向 B 点 现在 我不确定如何实现这一目标 我用谷歌搜索但没有找到任何好的解决方案 在任何情况下 如何计算二维空间中从 A 点到 B 点的
  • Swift 2 中的 segue 没有后退按钮

    我刚刚将我的项目移植到 Swift 2 一切都运行良好 除了即使是最简单的 segues 也没有后退按钮 这是我正在使用的 segue 函数的准备 override func prepareForSegue segue UIStoryboa
  • 更改 SKPhysicsBody 的身体形状

    除了定义 SKPhysicsBody 形状的主体之外 我不想更改任何其他内容 我该怎么做呢 我似乎找不到在哪里可以改变这个 甚至评论如何改变它 是的 我知道这必须小心完成 以便避免所有可能的新碰撞 重叠等 但抛开这些 我如何更改 SKPhy
  • iOS - 基于设备的不同图像或缩放相同的图像?

    似乎开发人员总是为不同的设备创建不同的图像资源 并根据设备加载它们 但是 只为最高分辨率的设备 iPad 创建图像 然后为 iPhone 6 5 等缩小该图像 有什么缺点吗 我使用 SpriteKit 因此我只需创建不同大小的 SKSpri
  • 如何以 JavaScript 编程方式获取旋转的 svg 文本边界

    我正在动态渲染 SVG 图像并创建旋转文本 如果旋转的文本与其他文本重叠 我需要删除该文本 但我无法测量旋转的文本来创建边界并检查下一个标签文本区域 我创建了 3 个 SVG 元素来解释 SVG 1 显示重叠的文本 SVG 2 显示重叠的旋
  • 如何在Sprite Kit中实现鼠标关节?

    我已经在 iOS 上用 Cocos2d Box2d 编写了拖放功能的工作实现 我需要将它移植到 Sprite Kit 逻辑非常基本 当用户触摸屏幕时 找到手指下的精灵 在找到的精灵和场景的物理体之间创建鼠标关节 将关节的目标设置为触摸位置
  • SpriteKitPhysicsBody非矩形碰撞

    pipeUp physicsBody SKPhysicsBody rectangleOfSize pipeUp size 在此编码中我使用了rectangleOfSize对于碰撞物理体 但如果我想按像素仅使用图像的形状 我应该使用什么而不是
  • 按范围迭代数组

    我有一个数组 1 2 3 4 5 6 100 我希望将此数组迭代 5 次 具体来说 取数组的前 5 个数字并获取平均值 继续处理接下来的 5 个数字并获取平均值 依此类推 我尝试过多种方法 例如Dequeue和 for 循环但未能获得所需的
  • SpriteKit - 对多个 SKNode 上运行的多个 SKAction 进行排序

    我非常了解 SKAction API 但在多个节点上运行顺序代码时我无法获得良好的代码 这是示例代码 简化 import SpriteKit class GameScene SKScene weak var node1 SKNode wea
  • 如何使用 MKOverlayPathView 创建路径?

    我一直在查看 Apple 的 iOS 类参考文档 但不幸的是我一无所知 我已经下载了他们的示例代码KMLViewer但他们把它变得过于复杂了 我真正想知道的是如何生成路径并将其添加到MKMapView 该文档谈到使用CGPathRef 但并
  • SpriteKit内存管理预加载缓存和fps问题

    我的问题非常简单 根据苹果文档 您可以在呈现场景之前将纹理预加载到 RAM 中 如下所示 SKTextureAtlas atlas SKTextureAtlas atlasNamed effect circle explode SKText
  • 如何使用 Swift 将高分游戏保存在排行榜上?

    我使用 SpriteKit 和 Xcode 7 beta 制作了一个游戏 我尝试放置 GameCenter 和 Leaderboard 但问题是排行榜中的分数不会改变 它始终保持 0 游戏的高分不会保存在 Leaderboard 中 我不知
  • 添加事件侦听器到回合制 ios 游戏时出现警告

    这是 gamekithelper m 中的代码 void authenticateLocalPlayer 1 GKLocalPlayer localPlayer GKLocalPlayer localPlayer add a weak lo
  • 将图像作为球分配给 SKShapeNode - Spritekit 游戏

    我正在尝试在 Swift 2 Sprite kit 游戏中向我的球添加图像 我有一个make ball 函数 但在游戏场景中没有错误 当调用该方法时 我不断收到此错误 无法分配 SKShapeNode 来输入 Ball 我不知道如何修复 并

随机推荐

  • 如何获取显示引用的 C# 库的 XML 文档?

    假设您有一个包含多个函数的 C 库 所有函数都使用通常的文档记录
  • ghci 未从文件加载函数

    在 test hs 中 我有 doubleMe x x x 在 ghci 中 我输入 Prelude gt l test 1 of 1 Compiling Main test hs interpreted Ok modules loaded
  • 预处理 SHA256 Python 实现

    我正在维基百科上完成 SHA256 的实现 但遇到了困难 我刚刚尝试编写消息预处理的代码 最终消息的长度是 504 位 而不是所需的 512 位 维基百科 SHA256 http en wikipedia org wiki SHA 2 预处
  • 从 Google Play 删除未发布的应用

    我在我的 Google Play 帐户中创建了一个新应用程序 我没有发表还没完成 它刚刚准备好发布 由于它尚未发布 有什么方法可以将其从我的帐户中永久删除吗 我找不到任何删除或删除按钮 我读here https stackoverflow
  • 在 iOS 中集成 Google 和 Facebook 登录 - AppDelegate openURL

    我正在尝试将 facebook 和 google 登录集成到我的应用程序中 但遇到了问题 两者都需要将以下内容添加到 Appdelegate 中的 openURL 方法中 return GIDSignIn sharedInstance ha
  • 为什么 `print(object)` 显示 `<__main__.对象位于 0x02C08790>`?

    我不断得到 lt main Camera object at 0x02C08790 gt 我不知道为什么 我希望代码基本上在一个循环中从 Calc Speed 转到 Counter 然后返回到 Calc Speed class Camera
  • MSBuild:如何为 Web 部署项目(VS2010)构建 Web 部署包?

    我将一个网站项目 带有 Web 部署项目 从 VS2008 迁移到 VS2010 现在我可以在 VS2010 中为 Web 部署项目制作 构建部署包 效果非常好 但我找不到通过 MSBuild 执行相同操作的方法 我回答我的一个问题 经过大
  • COM 字符串 (BSTR) 和 .NET 字符串有什么区别?

    这只是字节组合来 编码 数据的方式吗 我很好奇 因为我想知道 RCW 如何自动获取 NET 字符串并将其转换为 COM BSTR 我猜测它只是形成了从 NET 字符串转换而来的有效 COM BSTR 相关 我可以使用 NET 中的字节类型构
  • 从上下文资产中的 Uri 加载 MediaPlayer

    我的资产目录中有一个音频文件 资产 音频 dance mp3 如果我运行 context getAssets list audio 它出现了 但是当我尝试使用 MediaPlayer create context uri 时它总是失败并返回
  • 安装适用于 Python 的 TextBlob 时遇到问题

    我是编程新手 我正在尝试安装 Python 的 TextBlob 库来帮助我做一些事情 遗憾的是 我在安装 TextBlob 时遇到了麻烦 更不用说使用它了 我使用的是Windows 这似乎让事情变得更加困难 我希望我可以只运行 Linux
  • StructureMap 和嵌套泛型

    我想知道是否有一种方法可以在其中连接嵌套泛型StructureMap无需指定内部类型或创建特定于类型的接口 我意识到这有点令人困惑 因此编码示例可能是对我正在寻找的功能的更好解释 public interface IParser
  • 使用 jQuery 切换元素的属性?

    使用 jQuery 构建树形菜单 并且我希望它可以访问 因此我使用 aria 属性 我想要做的是在单击 输入时将 aria expanded 属性从 true 切换为 false 我已经尝试过 但显然不正确 this closest ul
  • 下拉列表中的地图位置名称

    我的应用程序必须使用文本框集成搜索位置名称 Map kit有什么方法可以实现这种功能吗 下图显示了我真正需要的 No MapKit没有任何方法来实现这种类型的属性 为此 您必须实现自己的代码 即使用 UISearchbarCantrolle
  • 为什么鱼绑定在 mac os 中不起作用?

    我正在尝试使用一些鱼绑定 但无法让它们在我的 Apple sierra 中同时使用 iterm2 和终端工作 例如 当我使用Alt d它应该删除一个单词 它插入了字母 我在这里错过了什么吗 您需要将终端配置为将 option alt 键视为
  • 不能在赋值中使用类型 interface {} 作为类型 person:需要类型断言

    我尝试转换interface 构造person package main import encoding json fmt func FromJson jsonSrc string interface var obj interface j
  • 更新后Android资源编译失败

    更新 android studio 后 我的项目崩溃并出现以下错误 Android resource compilation failed Output C Users aliya Desktop EventsToday app build
  • 为一个名称 urllib2 发送多个值

    我正在尝试提交一个包含复选框的网页 并且我最多需要选中其中 10 个复选框 问题是当我尝试将它们分配给字典中的一个名称时 它只分配最后一个而不是全部 10 个 那么我该如何做到这一点 这里是请求代码 forms ref ck ref typ
  • 将日期和时间输入字符串组合为日期对象

    我有两个输入标签用于从用户处选择日期和时间 p Start Date p p p
  • 为 CMake 引入新的编译器

    我们使用一个特定的编译器 称为 Cadul 它有自己的库 目标等 问题是 与 GNU Intel Clang 等 标准 编译器相比 CMake 不支持它 首先我想使用交叉编译 但它不起作用 因为主机和目标平台是相同的 然后我查看了模块 在其
  • 如何用 Swift 创建波浪路径

    我希望我的节点以正弦曲线波行进 我尝试将其用于 CGPath 如何创建遵循正弦曲线的 CGPath 除了手动查找曲线上的点之外 还有其他方法吗 或者我可以只传递正弦函数吗 let action SKAction followPath