当前位置: 首页 > 面试题库 >

如何在Spritekit中创建垂直滚动菜单?

濮波
2023-03-14
问题内容

我希望在游戏中(SpriteKit)中创建带有按钮和图像的商店,但我需要使这些物品能够滚动,以便玩家可以上下滚动商店(就像UITableView一样,但每个商店中都有多个SKSpriteNodes和SKLabelNodes细胞)。知道如何在SpriteKit中做到这一点吗?


问题答案:

正如所答应的第二个答案,我只是想出了问题。

我建议始终从gitHub项目中获取此代码的最新版本,以防由于此答案以来我进行了更改,链接位于底部。

第1步:创建一个新的swift文件并粘贴此代码

import SpriteKit

/// Scroll direction
enum ScrollDirection {
    case vertical // cases start with small letters as I am following Swift 3 guildlines.
    case horizontal
}

class CustomScrollView: UIScrollView {

// MARK: - Static Properties

/// Touches allowed
static var disabledTouches = false

/// Scroll view
private static var scrollView: UIScrollView!

// MARK: - Properties

/// Current scene
private let currentScene: SKScene

/// Moveable node
private let moveableNode: SKNode

/// Scroll direction
private let scrollDirection: ScrollDirection

/// Touched nodes
private var nodesTouched = [AnyObject]()

// MARK: - Init
init(frame: CGRect, scene: SKScene, moveableNode: SKNode) {
    self.currentScene = scene
    self.moveableNode = moveableNode
    self.scrollDirection = scrollDirection
    super.init(frame: frame)

    CustomScrollView.scrollView = self
    self.frame = frame
    delegate = self
    indicatorStyle = .White
    scrollEnabled = true
    userInteractionEnabled = true
    //canCancelContentTouches = false
    //self.minimumZoomScale = 1
    //self.maximumZoomScale = 3

    if scrollDirection == .horizontal {
        let flip = CGAffineTransformMakeScale(-1,-1)
        transform = flip
    }
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
   }
}

// MARK: - Touches
extension CustomScrollView {

/// Began
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch in touches {
        let location = touch.locationInNode(currentScene)

        guard !CustomScrollView.disabledTouches else { return }

        /// Call touches began in current scene
        currentScene.touchesBegan(touches, withEvent: event)

        /// Call touches began in all touched nodes in the current scene
        nodesTouched = currentScene.nodesAtPoint(location)
        for node in nodesTouched {
            node.touchesBegan(touches, withEvent: event)
        }
    }
}

/// Moved
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch in touches {
        let location = touch.locationInNode(currentScene)

        guard !CustomScrollView.disabledTouches else { return }

        /// Call touches moved in current scene
        currentScene.touchesMoved(touches, withEvent: event)

        /// Call touches moved in all touched nodes in the current scene
        nodesTouched = currentScene.nodesAtPoint(location)
        for node in nodesTouched {
            node.touchesMoved(touches, withEvent: event)
        }
    }
}

/// Ended
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch in touches {
        let location = touch.locationInNode(currentScene)

        guard !CustomScrollView.disabledTouches else { return }

        /// Call touches ended in current scene
        currentScene.touchesEnded(touches, withEvent: event)

        /// Call touches ended in all touched nodes in the current scene
        nodesTouched = currentScene.nodesAtPoint(location)
        for node in nodesTouched {
            node.touchesEnded(touches, withEvent: event)
        }
    }
}

/// Cancelled
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {

    for touch in touches! {
        let location = touch.locationInNode(currentScene)

        guard !CustomScrollView.disabledTouches else { return }

        /// Call touches cancelled in current scene
        currentScene.touchesCancelled(touches, withEvent: event)

        /// Call touches cancelled in all touched nodes in the current scene
        nodesTouched = currentScene.nodesAtPoint(location)
        for node in nodesTouched {
            node.touchesCancelled(touches, withEvent: event)
        }
     }
   }
}

// MARK: - Touch Controls
extension CustomScrollView {

     /// Disable
    class func disable() {
        CustomScrollView.scrollView?.userInteractionEnabled = false
        CustomScrollView.disabledTouches = true
    }

    /// Enable
    class func enable() {
        CustomScrollView.scrollView?.userInteractionEnabled = true
        CustomScrollView.disabledTouches = false
    }
}

// MARK: - Delegates
extension CustomScrollView: UIScrollViewDelegate {

    func scrollViewDidScroll(scrollView: UIScrollView) {

        if scrollDirection == .horizontal {
            moveableNode.position.x = scrollView.contentOffset.x
        } else {
            moveableNode.position.y = scrollView.contentOffset.y
        }
    }
}

这是UIScrollView的子类,并设置了它的基本属性。然后它具有自己的触摸方法,该方法会传递到相关场景。

步骤2:在您要使用的相关场景中,创建一个滚动视图和可移动节点属性,如下所示

weak var scrollView: CustomScrollView!
let moveableNode = SKNode()

并将它们添加到didMoveToView中的场景中

scrollView = CustomScrollView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height), scene: self, moveableNode: moveableNode, scrollDirection: .vertical)
scrollView.contentSize = CGSizeMake(self.frame.size.width, self.frame.size.height * 2)
view?.addSubview(scrollView)


addChild(moveableNode)

您在第1行中所做的就是使用场景尺寸初始化滚动视图帮助器。您还将传递场景作为参考,并传递在步骤2中创建的moveableNode。第2行是您设置scrollView内容大小的地方,在这种情况下,它是屏幕高度的两倍。

第3步:-添加标签或节点等并放置它们。

label1.posithtml" target="_blank">ion.y = CGRectGetMidY(self.frame) - self.frame.size.height
moveableNode.addChild(label1)

在此示例中,标签将位于scrollView的第二页上。这是您必须摆弄标签和位置的地方。

我建议如果滚动视图中有很多页面,并且有很多标签,请执行以下操作。为滚动视图中的每个页面创建一个SKSpriteNode,并使每个页面的大小与屏幕大小相同。称它们为page1Node,page2Node等。然后将您想要的所有标签(例如,第二页上的所有标签)添加到page2Node。这样做的好处是,您基本上可以像往常一样将所有内容放置在page2Node中,而不仅仅是将page2Node放置在scrollView中。

您也很幸运,因为垂直使用scrollView(您说您想要的)不需要进行任何翻转和反向定位。

我做了一些类功能,所以如果您需要禁用scrollView的话,以防您在scrollView顶部覆盖了另一个菜单。

CustomScrollView.enable()
CustomScrollView.disable()

最后,不要忘记在过渡到新场景之前从场景中删除滚动视图。在spritekit中处理UIKit时的痛苦之一。

scrollView?.removeFromSuperView()

对于水平滚动,只需将init方法上的滚动方向更改为.horizo​​ntal(步骤2)。

而现在最大的痛苦是,在放置东西时一切都是相反的。因此,滚动视图从右到左。因此,您需要使用scrollView“
contentOffset”方法重新定位它,并且基本上将所有标签从右到左以相反的顺序放置。一旦了解发生了什么,再次使用SkNodes将使此操作变得更加容易。

希望这会有所帮助,并为大量的帖子感到抱歉,但是正如我所说,spritekit有点痛苦。让我知道进展如何,如果我错过了任何事情。

项目在gitHub上

https://github.com/crashoverride777/SwiftySKScrollView



 类似资料:
  • 我希望能够在RichTextFX中将垂直滚动设置为InlineStyleTextArea的顶部或底部。从这个线程的外观来看,<代码>移动到(…) 应该起作用。但这对我不起作用。我还尝试了选择范围(…) 和位置插入符号(…) 。下面是我的测试程序,我是否误解了上面链接的线程中提到的“重新定位插入符号的解决方法”?

  • 在我的HTML页面中,我有很多宽度:100VW的东西占据了整个页面。有一个垂直滚动条,它导致一个水平滚动条(因为垂直滚动条占用了20像素)。 这导致的更大问题是我的东西似乎偏离了中心。虽然只是轻微的,但一旦你注意到它(这需要大约3秒的凝视),它不会消失,而且是非常令人沮丧的。我贴了一张超级小浏览器窗口的截图。我还把代码贴出来了。 图像 null null 文字偏离了中心。我怎么解决这个?

  • 即使SWT表格为空,是否可以始终在表格中显示垂直滚动条?通过始终显示(可能已禁用)垂直滚动条,可以避免最后一列在使用列权重数据(ColumnWeightData)进行布局时部分隐藏。 我试图用SWT初始化表。V\u滚动或使用表格。getVerticalBar()。setVisible(true)-两者均未成功。 在ScrollableComposite中有一个方法设置总是显示滚动条。我要找的是表中

  • 问题内容: 是否可以使用CSS将DIV的垂直滚动条放在div的左侧?那jscript呢? 问题答案: 您可以使用JQuery和此插件在任意位置添加伪滚动条:JScrollPane

  • 问题内容: 我想始终在网页中显示垂直滚动条。是否可以使用javascript?我认为可以使用javascript或jQuery。我要垂直滚动条是否有足够的内容来显示或不显示。 谢谢。 问题答案: 不需要jQuery。您可以尝试添加CSS: 这适用于最新的浏览器,甚至IE6。

  • 我想添加一种在中滚动菜单项的方法,就像在中滚动项列表一样。 假设我有10个菜单项。我希望一次只显示5个菜单项,我将使用底部或顶部的垂直滚动按钮来显示未列出的菜单项,并隐藏刚才看到的菜单项。 有可能吗?我使用的是JIDE软件的,点击它时会显示。我试图保持放置的命令栏的外观,因此除非真的有必要,否则我不想用替换它。