美文网首页
iOS SpriteKit - Scene

iOS SpriteKit - Scene

作者: FireStroy | 来源:发表于2021-02-05 11:20 被阅读0次

    关联章节
    iOS SpriteKit 文档

    SKScene

    一个组织所有活动SpriteKit内容的对象。


    总览

    SKScene对象表示SpriteKit中内容的场景。 场景是SpriteKit节点树(SKNode)
    中的根节点。 这些节点提供场景动画并渲染以显示的内容。 要显示场景,可以从 SKView, SKRenderer, or WKInterfaceSKScene呈现它。

    SKSceneSKEffectNode的子类,可将某些效果应用于整个场景。 尽管将效果应用于整个场景可能是一项昂贵的操作,但是创造力和独创性可能会帮助您找到一些有趣的方式来使用效果。

    从文件创建场景

    加载SKScene的最常见方法是通过Xcode场景编辑器中配置的.sks文件。 在编辑器中进行基本更改比编写等效的初始化代码要快,并且如果在多个位置创建场景,则可以避免重复代码。

    首先,通过Xcode的文件菜单>新建...>文件>(选择平台选项卡)> SpriteKit Scene将新的场景文件添加到项目中。

    图1

    使用编辑器配置场景

    您可以在场景编辑器中配置场景,方法是单击Xcode的文件导航器窗格中的.sks文件,然后在“实用程序”窗格中调整属性。 例如,要设置场景的背景色,请按照图2中突出显示的步骤进行操作:

    1. 在文件导航器窗格中选择.sks文件。
    2. 打开实用程序窗格。
    3. 选择“属性”检查器。
    4. 在“场景”下定义颜色。


      图2

    代码中读取场景文件

    使用nodeWithFileNamed:.在代码中加载新配置的场景文件。

    let scene = SKScene(fileNamed: "MyScene")//swift
    self.scene = [SKScene nodeWithFileNamed:@"MyScene"];//oc
    // Now present the scene in a view.
    skView.presentScene(scene)
    

    注意
    .sks文件扩展名不包含在nodeWithFileNamed:的字符串名称参数中。


    用代码创建场景

    1. 此类方法分配一个新的场景对象并调用其initWithSize:初始化方法。
    + (instancetype)sceneWithSize:(CGSize)size;
    

    2.这是该类的指定初始化方法。

    - (instancetype)initWithSize:(CGSize)size;
    
    1. 关于size

    首次初始化场景时,其大小属性由指定的初始化程序配置。 场景的大小以points为单位指定场景可见部分的大小。 这仅用于指定场景的可见部分。 树中的节点可以放置在该区域之外。 这些节点仍由场景处理,但渲染器将忽略它们。

    呈现场景时,size和anchorPoint属性确定场景坐标空间在视图中可见的部分。

    如果将size属性设置为新值,则会调用场景的didChangeSize:方法。 如果将 scaleMode属性设置为SKSceneScaleModeResizeFill并调整了显示视图的大小,则此属性也可以更改。 场景尺寸更改后,将来的更新将立即以新尺寸呈现。


    拉伸内容以适合视图

    配置缩放模式以确定场景的大小以适合其视图。

    总览

    设置场景的scaleMode属性,以根据显示它的视图确定其大小。 例如,在iOS中,scaleMode确定设备更改方向时场景的自动调整大小。 在macOS中,scaleMode会在用户更改应用程序窗口的大小或比例时影响场景的缩放比例。

    确定最佳比例模式

    在设计游戏时,您应该确定一种用于处理场景的sizescaleMode属性的策略。 以下是最常见的策略:

    • 以恒定的大小实例化场景,并且永远不要更改它。 选择一种缩放模式,使视图可以缩放场景的内容。 这为场景提供了可预测的坐标系和框架。 然后,您可以在此坐标系上建立艺术资产和游戏逻辑。

    • 调整游戏中场景的大小。 必要时,调整游戏逻辑和美术资产以匹配场景的大小。

    • scaleMode属性设置为SKSceneScaleModeResizeFillSpriteKit会自动调整场景的大小,使其始终与视图的大小匹配。 必要时,调整游戏逻辑和美术资产以匹配场景的大小。

    设置固定的宽高比

    下面例子显示了计划使用恒定大小的场景时的典型实现。 这段代码指定了第一次显示场景时要执行的方法。 它配置场景的属性(包括缩放模式),然后添加内容。 在此示例中,缩放模式设置为SKSceneScaleModeAspectFit,它将在两个维度上均等地缩放内容,并确保场景的所有内容均可见。 必要时,此模式会添加信箱。

    - (void)createSceneContent  
    {      
        self.scaleMode = SKSceneScaleModeAspectFit;      
        self.backgroundColor = [SKColor blackColor];  
        // Add additional scene contents here.  
        ...  
    } 
    

    在场景调整大小时更新图形

    如果您希望场景的大小在运行时发生变化,则应使用初始场景大小来确定要使用的美术资产以及取决于场景大小的任何游戏逻辑。 您的游戏还应该覆盖场景的didChangeSize:方法,只要场景更改大小,该方法就会被调用。 调用此方法时,您应该更新场景的内容以匹配新的大小。

    scaleMode

    定义场景如何映射到呈现它的视图的设置。

    @property(nonatomic) SKSceneScaleMode scaleMode;
    

    场景的大小可能与呈现的视图的大小不同。缩放模式确定场景的可见部分如何映射到视图。 可能的值在SKSceneScaleMode中列出。 默认值为SKSceneScaleModeFill

    • SKSceneScaleModeFill 场景的每个轴都是独立缩放的,因此场景中的每个轴都精确映射到视图中该轴的长度。

    • SKSceneScaleModeAspectFill 计算每个尺寸的比例因子,然后选择两者中较大的一个。 场景的每个轴都使用相同的缩放因子缩放。 这样可以保证整个视图区域都被填充,但是可能会导致部分场景被裁剪。

    • SKSceneScaleModeAspectFit 计算每个尺寸的比例因子,然后选择两者中较小的一个。 场景的每个轴都使用相同的缩放因子缩放。 这样可以保证整个场景都是可见的,但可能需要在视图中添加信箱。

    • SKSceneScaleModeResizeFill 场景未按比例缩放以匹配视图。 取而代之的是,场景会自动调整大小,以使其尺寸始终与视图尺寸匹配。


    配置视口

    定义在给定时间可见的场景部分

    在场景内定位场景的原点

    尝试不同的方法在其视图内配置场景的原点。

    总览

    您可以使用场景的anchorPoint来定向其节点的默认屏幕位置。 例如,将场景的anchorpoint设置为(0,0)会使位置为(0,0)的子节点显示在场景的左下角。 但是,将场景的anchorpoint设置为(0.5,0.5)会使位置为(0,0)的子节点显示在场景的中心。

    您仅将场景的anchorpoint用于没有摄像头的场景。 但是,如果设置了场景的摄像机,则摄像机将在任何给定时间驱动场景的哪个部分可见,并且anchorPoint将被忽略。

    将场景的原点设置为其视图的左下角

    默认情况下,场景的原点位于视图的左下角,如下图所示。 初始化为高度1024和宽度768的场景的原点(0,0)在左下角,而(1024,768)坐标在右上角。 frame属性保存为(0,0)-(1024,768)。

    SceneKit将忽略场景的position属性,因为场景始终是节点树的根节点。 默认值为零,您无法更改。 但是,您可以通过设置场景的anchorPoint属性来移动场景的原点。 锚点在单位坐标空间中指定,并在封闭视图中选择一个点。

    Default anchor for a scene is in the lower-left corner of the view

    锚点的默认值为零,将其放置在左下角。 场景的可见坐标空间为(0,0)至(宽度,高度)。 对于不滚动场景内容的游戏,默认锚点最有用。

    将场景的原点置于视图的中心

    第二个最常见的锚点值为(0.5,0.5),该值将场景的原点居中于视图的中央,如下图所示。 场景的可见坐标空间为(-width / 2,-height / 2)到(width / 2,height / 2)。 当您想轻松地相对于屏幕中心定位节点时(例如在滚动游戏中),将场景居中于其锚点上最有用。 但是,使用SKCameraNode.可以更好地实现此效果。

    Moving the anchor point to the center of the view

    设置anchorPoint和大小的结果是,您间接设置了场景的框架,该框架确定了用户可见的场景部分。

    相机

    场景中的摄影机节点,确定在视图中可见场景坐标空间的哪一部分。

    @property(nonatomic, weak, nullable) SKCameraNode *camera;
    

    此属性的默认值为nil,这意味着场景的anchorpoint和size属性确定场景的哪一部分可见。 如果设置为指向场景中包含的摄影机节点,则会忽略anchorPoint属性,而是使用摄影机节点的属性渲染场景。

    必须将摄像机添加到场景中才能工作。

    有关更多信息,请参见SKCameraNode.

    锚点

    视图框架中与场景原点相对应的点。

    @property(nonatomic) CGPoint anchorPoint;
    

    呈现场景且未指定相机节点时,sizeanchorPoint属性确定场景的坐标空间的哪一部分在视图中可见。

    您可以使用单位坐标空间指定值。 默认值为(0,0),它对应于视图框架矩形的左下角。


    响应加载和调整事件大小

    复写这些方法,以便在加载或呈现场景或更改大小时通知您。

    • 告诉您场景何时出现。
    - (void)sceneDidLoad;
    
    • 告诉您场景的大小已更改。
    - (void)didChangeSize:(CGSize)oldSize;
    
    • 告诉您何时将场景从视图中删除。
    - (void)willMoveFromView:(SKView *)view;
    
    • 告诉您何时通过视图呈现场景。
    - (void)didMoveToView:(SKView *)view;
    

    响应帧周期事件

    回调发生在每一帧,告诉您何时执行应用逻辑。
    实现每帧应用逻辑,例如称为每帧的场景更新功能。

    总览

    当通过presentScene:呈现场景时,如果您实现下图所示的任何功能,则SpriteKit会每帧调用一次:


    如果您未实现任何帧循环功能,则SpriteKit仅在场景中的某些内容发生变化时才渲染场景,从而提高能源效率并允许您的游戏或应用执行其他操作。

    确定要实现的事件

    每次通过渲染循环时,都会更新场景的内容,然后进行渲染。 您无法覆盖渲染行为; 相反,您可以更新场景中的节点。 但是,场景包含可以覆盖以自定义场景处理的方法,并且可以使用动作和物理方法来更改树中节点的属性。 以下是渲染循环中的步骤:

    1. 场景的 update:方法将使用模拟到目前为止的时间来调用。 这是实现自己的游戏内仿真的主要场所,包括输入处理,人工智能,游戏脚本和其他类似的游戏逻辑。 通常,您使用此方法来更改节点或在节点上运行操作。
    2. 场景处理树中所有节点上的动作。 它找到任何正在运行的动作并将这些更改应用于树。 实际上,由于自定义动作,您还可以加入动作机制来调用自己的代码。 您不能直接控制动作的处理顺序或导致场景跳过某些节点上的动作,除非从这些节点上删除动作或从树中删除这些节点。
    3. 处理完框架的所有动作后,将调用场景的didEvaluateActions方法。
    4. 场景在具有物理实体的树中的节点上模拟物理。 SKPhysicsBody中描述了向场景中的节点添加物理场,但是模拟物理场的最终结果是,可以通过物理场仿真来调整树中节点的位置和旋转。 当物理物体相互接触时,您的游戏还可以接收回调。 请参阅1. SKPhysicsContactDelegate
    5. 在模拟了框架的所有物理实体之后,将调用场景的didSimulatePhysics方法。
    6. 场景将应用与场景中的节点关联的所有约束。 约束用于在场景中建立关系。 例如,您可以应用约束来确保一个节点始终指向另一个节点,而不管其如何移动。 通过使用约束,可以避免在场景处理中编写大量自定义代码。
    7. 场景调用了didApplyConstraints方法。
    8. 场景调用其didFinishUpdate方法。 这是您更改场景的最后机会。
    9. 场景已渲染。

    使用场景委托而不是对场景进行子类化

    子类化SKScene和重写框架循环函数是实现应用程序逻辑的一种简单方法,但是您可以避免使用委托进行子类化。 SKScene定义的所有帧周期函数都有一个SKSceneDelegate协议等效函数。 因此,如果提供了场景委托,则将调用委托的框架周期方法,而不是调用场景中的那些方法。 例如,iOS应用程序可能使用视图控制器作为场景委托。 有关更多信息,请参见Subclassing Scenes Versus Assigning a Delegate

    实现Post-Processing

    场景可以按任何顺序处理场景树上的动作。 因此,如果您有需要运行每个框架的任务,并且需要精确控制它们的运行时间,则应使用didEvaluateActionsdidSimulatePhysics方法执行这些任务。 通常,您在后处理期间进行更改,这些更改需要树中某些节点的最终计算位置。 您的后期处理可以担任这些职位,并在树上执行其他有用的工作。


    配置代理

    使用场景委托在各种场景之间共享应用程序逻辑。

    总览

    通常,您的应用将SKScene子类化以提供游戏玩法。 您的子类通常:

    • 布置初始场景内容
    • 定义运行每一帧的应用逻辑
    • 实现响应器方法以处理键盘,鼠标或触摸事件

    另一种模式是分配一个delegate来代替处理Responding to Frame-Cycle Events。 例如,如果使视图控制器成为场景的委托,则它可以使用共享相同SKSceneDelegate实现的多个场景。 视图控制器参与事件处理,因此它也可以响应用户输入。

    重点
    在macOS上,您需要将窗口的nextResponder设置为应用程序的视图控制器,因为默认情况下,视图是用户输入事件的第一响应者。

    delegate

    在动画循环期间要调用的委托。

    @property(nonatomic, weak, nullable) id<SKSceneDelegate> delegate;
    

    SKSceneDelegate

    实现后允许任何类参与SpriteKit渲染循环回调的协议方法。

    SKSceneDelegate协议用于实现在对场景进行动画处理时要调用的委托。 通常,当您要使用场景而不要求将场景子类化时,可以提供委托。 该协议中的方法都对应于SKScene类实现的方法。 如果委托实现了特定方法,则将调用该方法,而不是场景对象上的相应方法。

    在处理场景时,SpriteKit运行一个循环来处理和渲染场景。 SKSceneDelegate方法允许您在循环的任何步骤添加逻辑。

    重点注意
    如果您的视图具有SKViewDelegate,并且其view:shouldRenderAtTime:方法返回NO,则跳过更新,并且不会调用任何场景委托方法。


    设置背景外观

    设置透明的背景色以显示下层视图的内容
    要将使用SpriteKit呈现的内容覆盖在另一个视图之上,请按照下列步骤操作:
    1、将场景的backgroundColor设置为clear
    2、在视图上启用allowTransparency
    3、将视图的backgroundColor设置为clear

    view

    当前呈现场景的视图。

    @property(nonatomic, weak, readonly, nullable) SKView *view;
    

    要呈现场景,请在SKView类上调用presentScene:方法或presentScene:transition:方法。 如果当前未显示场景,则此属性为nil

    backgroundColor

    场景的背景色

    @property(nonatomic, retain) UIColor *backgroundColor;
    

    默认的背景色是 gray color (RGBA 0.15, 0.15, 0.15, 1.0)

    配置场景的物理属性

    与场景关联的物理模拟。

    physicsWorld

    @property(nonatomic, readonly) SKPhysicsWorld *physicsWorld;
    

    每个场景都会自动创建一个物理世界对象,以模拟场景中节点上的物理。 您可以使用此属性访问场景的全局物理属性,例如重力。 要将物理学添加到特定节点,请参阅physicsBody.。


    添加位置音频

    通过定义侦听器来启用位置音频。

    与场景的侦听器一起使用音频节点

    将音频添加到场景中,并有选择地赋予它2D位置混合特性。

    总览

    SpriteKit场景添加音频的最简单方法是向其添加子SKAudioNode:

    let audio = SKAudioNode(fileNamed: "drums.mp3")
    spriteKitViewController.scene.addChild(audio)
    

    但是,如果您定义呈现的场景的听众,则其音频节点将通过位置声音混合进行播放。 例如,如果将场景的侦听器设置为场景的摄像机,然后将音频节点作为子节点添加到场景中的各个父节点,则父节点离屏幕中心的距离越远,其音频播放的噪音就越小 。

    listener

    一个节点,用于确定场景中位置音频的侦听器的位置。

    @property(nonatomic, weak, nullable) SKNode *listener;
    

    默认值为nil,这意味着场景的原点用作场景中SKAudioNode对象播放的音频效果的侦听器位置。 如果指定了非nil值,则它必须是场景中的节点。

    通常,您希望摄像机充当侦听器,以便屏幕上的音频节点比屏幕外的音频节点响亮。 在游戏中,定义玩家的节点可能会设置为侦听器。

    audioEngine

    AVFoundation音频引擎用于播放场景中包含的音频节点的音频。

    @property(nonatomic, retain, readonly) AVAudioEngine *audioEngine;
    

    创建场景时,会自动为您创建一个音频引擎实例。 您可以使用场景的音频引擎上的方法和属性来全面控制其所有子音频节点。 以下代码显示了如何将场景的整体音量从默认值1.0降低到0.2,然后暂停:

    let scene = SKScene()
    scene.audioEngine.mainMixerNode.outputVolume = 0.2
    scene.audioEngine.pause()
    

    坐标系的转换

    convertPointFromView:

    将点从视图坐标转换为场景坐标。
    在调用此方法之前,必须在视图中呈现场景。

    convertPointToView:

    将点从场景坐标转换为视图坐标。
    在调用此方法之前,必须在视图中呈现场景。

    继承关系

    继承自SKEffectNode

    相关文章

      网友评论

          本文标题:iOS SpriteKit - Scene

          本文链接:https://www.haomeiwen.com/subject/esiqtltx.html