SpriteKit - 获取缩放场景上可见区域的实际大小/帧.AspectFill

时间:2016-02-16 10:43:24

标签: ios sprite-kit screen resolution visible

我一直在SpriteKit制作游戏,在支持所有屏幕尺寸时遇到了问题。我尝试通过将所有场景缩放模式设置为.AspectFill并为所有宽度为480且高度为800的屏幕设置固定大小来解决此问题,如下所示:

  

让scene = GameScene(大小:CGSize(宽度:480,高度:800))

我去添加一个与游戏场景边缘对齐的边框(一个SKShapeNode),我发现self.frame.width和self.frame.height不会给出设备的尺寸可见区域。经过一些研究后,我通过使用UIScreen.mainScreen()。bounds.height和UIScreen.mainScreen()。bounds.width发现了很多建议。我实现了这种获取可见屏幕尺寸的方式,它仍然给我的尺寸与玩家可见的场景的实际尺寸不匹配。

我不确定这是否与我的所有场景有关,无论设备的分辨率是否具有固定的宽度和高度,并使用.AspectFill进行缩放。我一直坚持支持所有屏幕尺寸一段时间的问题,我不确定如何去做。如果它有助于我使用矢量图形文件而不是PNG。 所以我的问题是: 是否有任何支持所有屏幕尺寸的快捷方式,或者我是否必须使用硬编码每个设备上场景中每个节点的坐标?我不明白为什么这会是解决方案,因为它似乎太乏味而且代码看起来很混乱。

我还询问如何获得一个矩形/框架,在场景缩放后给出设备上场景可见区域的尺寸?

如果我以前曾问过我的任何一个问题,我很抱歉,但我找到的每一个答案都没有特别解决我的问题,或者写得太乱了。我想我已经提供了足够的信息来解决问题,但如果我没有,请向我询问所需的信息。

非常感谢你,感谢任何帮助

4 个答案:

答案 0 :(得分:8)

以下是Aspect Fill的工作原理:

场景的尺寸将始终保持不变,因此,如果您说场景是480点乘800点,则无论设备如何,它都将保持不变。

然后会发生的事情是它会从SKView的中心开始缩放场景,直到它填满最远的墙壁。

这将反过来裁剪你的场景。

因此,在设计不同宽高比的游戏时,您需要设计游戏来处理裁剪。

现在,在您的特定情况下,您需要确定设备的宽高比,并消除与场景方面的差异。

E.G。您的场景是3x5,设备是9x16,这意味着您的设备将增长到9.6x16,以填充9x16设备的大小。我们得到这个是因为我们的高度比我们的宽度有更多的距离,所以我们需要做3/5 = a / 16,3 * 16 = a * 5,(3 * 16)/ 5 = a a a = 9.6。

这意味着你有宽度的.6裁剪场景,两边都有.3。

现在你要问,.3如何与各种屏幕尺寸相关。

我们需要弄清楚.3是9.6的百分比。我们用分区来做,.3 / 9.6 = .03125或3.125%;这意味着我们需要将3.125%的边界推向场景的宽度,即15点。这意味着.03125 * 480 = 15.然后你的边界应该以15宽度和465开始。

伪代码:

let newSceneWidth = (scene.width * view.height) / (scene.height)
let sceneDifference = (newSceneWidth - view.Width)/2
let diffPercentage = sceneDifference / (newSceneWidth)

let leftEdge = diffPercentage * scene.width;
let rightEdge = scene.width - (diffPercentage * scene.width);

现在,如果高度上的距离比宽度更大,则必须交换宽度和高度变量。

答案 1 :(得分:6)

感谢您的回答,特别感谢KnightOfDragon,他帮我解决了我的问题。我所做的是创建一个产生CGRect的函数,该函数考虑了设备的尺寸以及场景的预定宽高比。这可以用作边界,并使场景中节点的相对定位更容易,以便它们对于所有设备都是可见的。再次特别感谢KnightOfDragon回答了解决方案代码的基础,如果没有它们,那将是困难的,我将无法分享这个整体解决方案。这是Swift中的最终代码:

//Returns a CGRect that has the dimensions and position for any device with respect to any specified scene. This will result in a boundary that can be utilised for positioning nodes on a scene so that they are always visible
func getVisibleScreen(var sceneWidth: Float, var sceneHeight: Float, viewWidth: Float, viewHeight: Float) -> CGRect {
    var x: Float = 0
    var y: Float = 0

    let deviceAspectRatio = viewWidth/viewHeight
    let sceneAspectRatio = sceneWidth/sceneHeight

    //If the the device's aspect ratio is smaller than the aspect ratio of the preset scene dimensions, then that would mean that the visible width will need to be calculated
    //as the scene's height has been scaled to match the height of the device's screen. To keep the aspect ratio of the scene this will mean that the width of the scene will extend
    //out from what is visible. 
    //The opposite will happen in the device's aspect ratio is larger.
    if deviceAspectRatio < sceneAspectRatio {
        let newSceneWidth: Float = (sceneWidth * viewHeight) / sceneHeight
        let sceneWidthDifference: Float = (newSceneWidth - viewWidth)/2
        let diffPercentageWidth: Float = sceneWidthDifference / (newSceneWidth)

        //Increase the x-offset by what isn't visible from the lrft of the scene
        x = diffPercentageWidth * sceneWidth
        //Multipled by 2 because the diffPercentageHeight is only accounts for one side(e.g right or left) not both
        sceneWidth = sceneWidth - (diffPercentageWidth * 2 * sceneWidth)
    } else {
        let newSceneHeight: Float = (sceneHeight * viewWidth) / sceneWidth
        let sceneHeightDifference: Float = (newSceneHeight - viewHeight)/2
        let diffPercentageHeight: Float = fabs(sceneHeightDifference / (newSceneHeight))

        //Increase the y-offset by what isn't visible from the bottom of the scene
        y = diffPercentageHeight * sceneHeight
        //Multipled by 2 because the diffPercentageHeight is only accounts for one side(e.g top or bottom) not both
        sceneHeight = sceneHeight - (diffPercentageHeight * 2 * sceneHeight)
    }

    let visibleScreenOffset = CGRect(x: CGFloat(x), y: CGFloat(y), width: CGFloat(sceneWidth), height: CGFloat(sceneHeight))
    return visibleScreenOffset
}

答案 2 :(得分:1)

我不知道原因:

struct Constants {
    static let vcHeight = UIScreen.mainScreen().bounds.height
    static let vcWidth = UIScreen.mainScreen().bounds.width
}

没有给出适当的界限。 但我不知道你为什么要使用.aspectFill来获得合适的尺寸 当我制作我的游戏时,我使用了这个

let position.x = vcHeight/3   //to putting him on a third of the screen for all iPhone's 

这也可用于获得合适的尺寸。 我对矢量图形一无所知,所以我无法帮助你。

答案 3 :(得分:0)

实际上有一个非常简单的方法可以做到这一点。 SKScene上的函数convertPoint(fromView:)允许将点从其包含的SKView的坐标系转换为场景空间坐标。因此,您可以获取视图的原点和一个等于其最远范围的点,将它们都转换为场景的坐标空间,并按以下方式测量差异:

extension SKScene {
    func viewSizeInLocalCoordinates() -> CGSize {
        let reference = CGPoint(x: view!.bounds.maxX, y: view!.bounds.maxY)
        let bottomLeft = convertPoint(fromView: .zero)
        let topRight = convertPoint(fromView: reference)
        let d = topRight - bottomLeft
        return CGSize(width: d.x, height: d.y)
    }
}

(请注意,我还使用了CGPoint扩展名,该扩展名使我可以直接使用点进行加法和减法。请参见下文。另外请注意,只有在呈现场景之后才可以安全地调用此函数;我对强制展开view有点懒,如果尚未显示该场景,它将为nil。)

extension CGPoint {
    static func +(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
        return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
    }
    static func -(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
        return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
    }
}

重要提示:这假定场景中未分配相机节点,或者相机节点的比例为1:1。如果您添加自己的相机节点并允许对其进行缩放以创建缩放效果,请改用以下代码。还请记住,连接到摄影机节点本身的节点不会随场景的其余部分缩放。我在这里通过提供ignoreCameraScale在代码中允许这样做。如果测量结果与通过摄像机移动和缩放的HUD元素有关,则将true传递给此参数。

extension SKScene {
    func viewSizeInLocalCoordinates(ignoreCameraScale: Bool = false) -> CGSize {
        let reference = CGPoint(x: view!.bounds.maxX, y: view!.bounds.maxY)
        var bottomLeft = convertPoint(fromView: .zero)
        var topRight = convertPoint(fromView: reference)

        if ignoreCameraScale, let camera = camera {
            bottomLeft = camera.convert(bottomLeft, from: self)
            topRight = camera.convert(topRight, from: self)
        }

        let d = topRight - bottomLeft
        return CGSize(width: d.x, height: -d.y)
    }
}