SpriteKit游戏开发点滴[5]旋转 & Anchorpoint

最近在做关于旋转的动画效果,遇到了些问题,在解决问题的过程中对SpriteKit中的旋转有所更加深入的了解,在此进行个总结。

我想实现下面的这个效果:一个水管绕着白色星球的中心进行旋转。

最自然的想法是直接使用SpriteKit的SKAction.rotateByAngle方法直接进行旋转即可。

那么问题来了,一个SKSpriteNode元素如何绕一个指定的点旋转呢?

默认情况下,每个SKSpriteNode节点都有一个锚点(Anchorpoint),而rotateByAngle方法则是以锚点为中心进行旋转。

比如当锚点为屏幕中心时:

比如锚点为屏幕左下角时:

那么,就将水管的Anchorpoint设置为白色星球的圆心位置即可。(修改Anchorpoint不是好办法)

但是,Anchorpoint默认是(0.5,0.5),为水管元素的中心点,它是代表相对于SKSpriteNode的比例的位置。

为什么Anchorpoint不能直接设置为固定的像素点位置呢?这样不是更简单更方便易用?

因为锚点实际上是元素的“抽象点”,而元素的位置(position)是该锚点的位置,往往该抽象点位于元素的内部。

在用rotateByAngle方法进行旋转时,物体虽然绕着锚点进行旋转,但是因为锚点并没有移动,所以物体的位置(Position)始终没有发生改变,改变的是ZRotation

举个栗子:

图中蓝色的边框代表物理引擎计算得到的碰撞形状,白色边框代表SKSpriteNode的frame,蓝色小人的中心为汽车锚点的位置。

很显然的,这里汽车的锚点被为(0,0)。

但是对于物理碰撞形状,它的锚点并没有随汽车的锚点改变而改变(也就是说如果修改了SKSpriteNode的锚点,在使用物理引擎时就会出现偏差,或许这是当前版本SpriteKit的bug吧)。

那么,如果既想使用默认的物理引擎进行碰撞检测并对物体施力,又想让物体绕着给定的一点进行旋转?该如何做呢?

也就是说如何在不修改Anchorpoint的情况下,让物体绕给定的点进行旋转?

很简单,手工修改物体的position和ZRotation即可。

假设物体为element,绕点point旋转rad弧度每帧,则可以在每次更新时调用方法:

(具体的点A绕点B旋转rad的计算参看点击打开链接

    func rotateByPoint(element:SKNode,point:CGPoint,rad:CGFloat)
    {
        let tempPos = element.position
        let resultX = point.x + (tempPos.x - point.x) * cos(rad) - (tempPos.y - point.y) * sin(rad)
        let resultY = point.y + (tempPos.x - point.x) * sin(rad) + (tempPos.y - point.y) * cos(rad)
        //修改角度
        element.zRotation += rad
        //修改位置
        element.position.x = resultX
        element.position.y = resultY
    }

如果简单些,绕给定点旋转的效果仅仅是为了好看,没有和其他元素进行什么交互的话(或者仅仅是粗略地通过frame是否重叠进行碰撞判断)

可以考虑修改Anchorpoint,进行实现。

具体做法是:

添加一个父亲节点,将其position设置为旋转被绕的点的位置;

然后将物体的位置设为相对父节点的新坐标;

直接对父亲节点进行rotateByAngle即可。

总的来说,Anchorpoint是为了“固定”物体到固定的position上而存在,如果想要让物体绕某任意一点旋转,并且不影响物理引擎的使用的话,应该考虑修改物体的position和ZRotation的方案。

这个方案应该是可以写成扩展的SKAction的,不过目前我对SKAction的机制还没有深入的掌握,争取在后面将其封装到SKAction中。

[目前我刚刚开始接触SpriteKit,经验还不够丰富,如果有错误还请大家及时指出。

时间: 2024-10-10 01:22:41

SpriteKit游戏开发点滴[5]旋转 & Anchorpoint的相关文章

SpriteKit游戏开发点滴[4] 适配屏幕的技巧

适配屏幕的技巧 多屏幕分辨率可真是开发者的死对头啊!常言道:你若屏幕分辨多,我就自挂东南枝- 不过对于游戏开发而言,一旦理解了适配屏幕的原理,便可无敌于众多的屏幕分辨率了. 在开始游戏开发时,我们预设一个"原始屏幕",在原始屏幕上绘制各种游戏元素: 当实际将游戏部署到不同分辨率的设备上时,再将"原始屏幕"绘(ying)制(she)到实际屏幕上去. 在映射到实际屏幕的过程中,如果"实际屏幕"的长宽比和"原始屏幕"的不同,就要考虑

Swift - 多层无缝循环滚动背景(SpriteKit游戏开发)

在游戏开发中,比如跑酷游戏.我们需要实现背景的无限循环滚动,来营造运动的效果.除了单层的背景滚动,还有视差滚动. 视差滚动是指让多层背景以不同的速度移动,形成立体的效果,从而带来非常出色的视觉体验. 样例说明: 1,本样例背景分为两层.第一层更靠近游戏窗口的色彩更鲜艳,移动速度也更快一些.第二层由于要模拟远处的场景,所以颜色也更淡一些,对比度更弱一些,移动速度也更慢一些. 2,要实现循环滚动.我们准备的背景图首尾是要可以无缝衔接的. 3,判断需要多少张无缝衔接图来组成背景?判断标准是:当第一张图

SpriteKit游戏开发适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全区域

未适配前:Ball球超过屏幕的上下方 适配后:Ball球就在屏幕的可视范围内运动了 一.那么如何适配不同的iPhone.iPhoneX及iPad的屏幕尺寸呢? 我们开发一个App的时候, 通常希望它在 iPhone, iPad, Mac上同时能运行, 尤其是游戏. 这样就需要我们考虑不同设备不同的分辨率,但处理起来比较麻烦,比如说,按照官方的做法,我们需要提供诸如 [email protected],[email protected],[email protected], 这样不同尺寸的图片,那

Watch OS 2.0 健身宠物app开发心得[1]-Healthkit的sdk接入

Watch OS2 - Healthkit的sdk接入 博主于今年7月底开始接触watch os2.0系统,听闻在os2.0上已经支持了原生app的开发,便兴致冲冲的开始了一段漫长的爬坑之旅! 博主主要开发的项目是在watch上研发一款健身宠物养成类游戏,如下图: 主要的功能就是利用watch os2.0 上的healkit sdk,依据watch收集的个人健康数据,以及完成这款原生app(即健身宠物,后文如此称呼)所指定的锻炼任务后,可以获得锻炼宠物的活力,以及捕捉相应各种种类的宠物等.而你所

Swift - 跳跃吃苹果游戏开发(SpriteKit游戏开发)

下面通过一个样例演示如何实现飞行道具的生成,以及道具碰撞拾取. 样例说明: 1,屏幕从右到左不断地生成苹果飞过来(苹果高度随机) 2,点击屏幕可以让熊猫跳跃 3,熊猫碰到苹果,苹果消失 运行效果: 样例代码: 苹果工厂类 AppleFactory.swift 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Swift - 给游戏添加背景音乐和音效(SpriteKit游戏开发)

游戏少不了背景音乐和音效.下面我们通过创建一个管理音效的类,来实现背景音乐的播放,同时点击屏幕可以播放相应的音效. 声音管理类 SoundManager.swift 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import SpriteKit //引入多媒体框架 import AVFoundation class SoundManager :SKNode{     //申明一个播放器

Swift - 使用atlas图集实现动画效果(SpriteKit游戏开发)

我们通常继承SKSpriteNode来实现游戏中的元素,除了可以使用图片作为纹理皮肤外.我们还可以使用动画纹理集来实现动画播放. 动画纹理集的制作也很简单,首先要有一套动画序列图,然后把它们放到一个文件夹下,最后把文件夹改名为*.atlas后缀就行了. 下面通过一个“神经猫”动画元件来演示: --- 神经猫类 Cat.swift --- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Swift - 获取屏幕点击坐标下所有对象(SpriteKit游戏开发)

对于场景内对象元件的点击响应,我们可以在场景的touchesBegan()方法中内统一处理. SKScene中touchesBegan()是响应屏幕点击的方法,在这里面我们可以先获取点击位置下所有的对象,然后筛选出需要的对象再调用该对象的方法. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import SpriteKit class GameScene: SKScene {          //

Swift - 创建并设置背景(SpriteKit游戏开发)

1,先把背景图片bg.jpg,[email protected]直接拖进Images.xcassets中 2,设置如下代码(背景图直接铺满整个屏幕) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import SpriteKit class GameScene: SKScene {     //当切换到这个场景视图后     override func didMoveToView(view: SKView) {         //将Images.xcassets