Menu 精灵套件中的UIScrollView水平滚动菜单

Menu 精灵套件中的UIScrollView水平滚动菜单,menu,uiscrollview,horizontal-scrolling,sprite-kit,horizontalscrollview,Menu,Uiscrollview,Horizontal Scrolling,Sprite Kit,Horizontalscrollview,我正在尝试在我的新精灵套件游戏中制作一个水平滚动菜单。由于Sprite工具包是相当新的,所以没有太多关于Sprite工具包的好教程。UIScrollView是否与Sprite套件兼容?我尝试过以下几种方法: UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; scroll.pagi

我正在尝试在我的新精灵套件游戏中制作一个水平滚动菜单。由于Sprite工具包是相当新的,所以没有太多关于Sprite工具包的好教程。UIScrollView是否与Sprite套件兼容?我尝试过以下几种方法:

UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scroll.pagingEnabled = YES;
NSInteger numberOfViews = 3;
for (int i = 0; i < numberOfViews; i++) {
    CGFloat xOrigin = i * self.view.frame.size.width;
    UIView *awesomeView = [[UIView alloc] initWithFrame:CGRectMake(xOrigin, 0,      self.view.frame.size.width, self.view.frame.size.height)];
    awesomeView.backgroundColor = [UIColor colorWithRed:0.5/i green:0.5 blue:0.5 alpha:1];
    [scroll addSubview:awesomeView];
}
UIScrollView*scroll=[[UIScrollView alloc]initWithFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height)];
scroll.paginEnabled=是;
NSInteger numberOfViews=3;
对于(int i=0;i

这不管用。我以前从未与UIScrollView合作过。有人能给出一种使用UIScrollView制作水平滚动菜单的方法吗?我尝试做的一个例子是在Bloons TD 5中使用他们的菜单。

您完全可以将UIKit控件与SpriteKit结合起来。从要使用UIScrollView的场景中,将滚动视图添加到self.view,如下所示:[self.view addSubview:scroll]。您可能希望在SKScene上的-(void)didMoveToView:(SKView*)视图方法中执行此操作。当您从使用滚动视图的SKView场景中过渡出来时,请记住从SKView中删除滚动视图。您可以在-(void)willMoveFromView:(SKView*)视图方法中执行此操作。不要忘记在UIScrollView上设置contentSize

注意:如果希望在UIKit控件上具有SpriteKit节点,则需要编写自己的行为类似于UIScrollView的SKSpriteNode


按说明展开:如果您的滚动视图需要包含精灵套件节点,而不仅仅是UIKit视图,则您将无法使用UIScrollView,除非您按照此问题答案中的建议做一些聪明的事情

我知道此问题已经提出了几个月,但我也在寻找一个滚动菜单滑块来选择我的SpriteKit游戏中的关卡。我找不到任何已经存在的代码,而强制将UIScrollView安装到我的SpriteKit游戏中的想法对我没有吸引力。所以我写了自己的水平选择滑动菜单

我已经模拟了UIScrollView的所有运动,因此它看起来很自然,并且可以配置为向左-向右或向上-向下滚动

作为奖励,我在菜单上创建了一个视差背景,它可以很容易地与新图像交换,以获得定制外观

滚动菜单的代码有很好的注释,所以不应该有太多的集成问题


github项目有一个完整的演示,其中包含世界、水平和视差图像。如果您喜欢,请将我的答案标记为有用,这样我可以获得一些声誉:)

有很多方法可以获得它,通过
SKCameraNode
,使用
UIKit
元素,如
UIScrollView
或其他方式。。 但是我想向您展示如何使用
SpriteKit
仅使用实现简单。 从概念上讲,您应该构建一个更大的
SKNode
,它包含菜单中的每个声音,其中每个元素彼此之间的距离相等。 您可以使用
SKAction
模拟滚动,将节点移动到最近可见元素的中心

GameViewController
游戏场景
class游戏场景:SKScene{
var lastX:CGFloat=0.0
var moveableArea=SKNode()//较大的SKNode
var worlds:[String]!=[“world1”、“world2”、“world3”]//菜单上的声音
var currentWorld:Int=0//包含当前可见菜单语音索引
var worldsPos=[CGPoint]()//用于存储菜单位置的CGPoints数组
覆盖func didMove(到视图:SKView){
//做一个通用的标题
让topLabel=SKLabelNode.init(文本:“选择世界”)
topLabel.fontSize=40.0
self.addChild(topLabel)
topLabel.zPosition=1
topLabel.position=CGPoint(x:frame.width/2,y:frame.height*0.80)
//准备活动区域
self.addChild(可移动区域)
moveableArea.position=CGPoint(x:self.frame.midX,y:self.frame.midY)
//准备世界:
对于0中的i..self.size.width*rightLimit{
moveableArea.position=CGPoint(x:self.size.width*rightLimit,y:moveableArea.position.y)
}
否则{
moveableArea.position=CGPoint(x:newX,y:moveableArea.position.y)
}
//探测当前可见世界
worldsPos=[CGPoint]()
对于0..0中的i,moveableArea.action(forKey:“moveAction”)==nil{
让moveAction=SKAction.move(到:worldsPos[currentWorld],持续时间:0.5)
moveAction.timingMode=.easeInEaseOut
self.moveableArea.run(moveAction,带键:“moveAction”)
}
}
}
如您所见,通过
touchsbegind
我们可以检测并选择触摸世界,使用
touchsmoved
我们可以将可移动节点移动到正确的位置并检测最近的可见世界,使用
touchseended
我们可以创建平滑滚动,以便在触摸后自动移动到当前最近的可见语音

输出


否,UISCrollView与SpriteKit不兼容。不过,你可以在菜单中使用带有滚动视图的viewController,也可以自己为SpriteKit创建滚动视图。你能在此说明上展开吗?@Bokoskos?没有详细介绍,但看起来很有希望!很好的工作,谢谢分享!很好的演示,谢谢。顺便问一下,如何关闭寻呼,以及当使用两个手指时,它试图跳出。。你能帮我吗?你打算做一个教程吗:-)b也很好。谢谢你sharing@A.亚当给我发了封电子邮件。该信息可在GitHub上获得
class GameViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        guard let view = self.view as! SKView? else { return }
        view.ignoresSiblingOrder = true
        view.showsFPS = true
        view.showsNodeCount = true
        view.showsPhysics = false
        view.showsDrawCount = true
        let scene = GameScene(size:view.bounds.size)
        scene.scaleMode = .aspectFill
        view.presentScene(scene)
    }
}
class GameScene: SKScene {
    var lastX: CGFloat = 0.0
    var moveableArea = SKNode() // the larger SKNode
    var worlds: [String]! = ["world1","world2","world3"] // the menu voices
    var currentWorld:Int = 0 // contain the current visible menu voice index
    var worldsPos = [CGPoint]() // an array of CGPoints to store the menu voices positions
    override func didMove(to view: SKView) {
        //Make a generic title
        let topLabel = SKLabelNode.init(text: "select world")
        topLabel.fontSize = 40.0
        self.addChild(topLabel)
        topLabel.zPosition = 1
        topLabel.position = CGPoint(x:frame.width / 2, y:frame.height*0.80)
        // Prepare movable area
        self.addChild(moveableArea)
        moveableArea.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
        // Prepare worlds:
        for i in 0..<worlds.count {
            // add a title for i^ world
            let worldLabel = SKLabelNode.init(text: worlds[i])
            self.moveableArea.addChild(worldLabel)
            worldLabel.position = CGPoint(x:CGFloat(i)*self.frame.width ,y:moveableArea.frame.height*0.60)
            // add a sprite for i^ world
            let randomRed = CGFloat(drand48())
            let randomGreen = CGFloat(drand48())
            let randomBlue = CGFloat(drand48())
            let randomColor = UIColor(red: randomRed, green: randomGreen, blue: randomBlue, alpha: 1.0)
            let worldSprite = SKSpriteNode.init(color: randomColor, size: CGSize.init(width: 100.0, height: 100.0))
            worldSprite.name = worlds[i]
            self.moveableArea.addChild(worldSprite)
            worldSprite.position = CGPoint(x:CGFloat(i)*self.frame.width ,y:0.0)
        }
    }
    func tapNode(node:SKNode,action:SKAction) {
        if node.action(forKey: "tap") == nil {
            node.run(action, withKey: "tap")
        }
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first!
        let location = touch.location(in: self)
        let touchedNode = self.atPoint(location)
        lastX = location.x
        let sequence = SKAction.sequence([SKAction.scale(to: 1.5, duration: 0.2),SKAction.scale(to: 1.0, duration: 0.1)]) // a little action to show the selection of the world
        switch touchedNode.name {
        case "world1"?:
            print("world1 was touched..")
            tapNode(node:touchedNode,action:sequence)
        case "world2"?:
            print("world2 was touched..")
            tapNode(node:touchedNode,action:sequence)
        case "world3"?:
            print("world3 was touched..")
            tapNode(node:touchedNode,action:sequence)
        default:break
        }
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first!
        let location = touch.location(in: self)
        let currentX = location.x
        let leftLimit:CGFloat = CGFloat(worlds.count-1)
        let rightLimit:CGFloat = 1.0
        let scrollSpeed:CGFloat = 1.0
        let newX = moveableArea.position.x + ((currentX - lastX)*scrollSpeed)
        if newX < self.size.width*(-leftLimit) {
            moveableArea.position = CGPoint(x:self.size.width*(-leftLimit), y:moveableArea.position.y)
        }
        else if newX > self.size.width*rightLimit {
            moveableArea.position = CGPoint(x:self.size.width*rightLimit, y:moveableArea.position.y)
        }
        else {
            moveableArea.position = CGPoint(x:newX, y:moveableArea.position.y)
        }
        // detect current visible world
        worldsPos = [CGPoint]()
        for i in 0..<worlds.count {
            let leftLimit = self.size.width-(self.size.width*CGFloat(i))
            let rightLimit = self.size.width-(self.size.width*CGFloat(i+1))
            if rightLimit ... leftLimit ~= moveableArea.position.x {
                currentWorld = i
            }
            worldsPos.append(CGPoint(x: (rightLimit + (leftLimit - rightLimit)/2), y:moveableArea.position.y))
        }
        lastX = currentX
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if worldsPos.count>0, moveableArea.action(forKey: "moveAction") == nil {
            let moveAction = SKAction.move(to: worldsPos[currentWorld], duration: 0.5)
            moveAction.timingMode = .easeInEaseOut
            self.moveableArea.run(moveAction, withKey: "moveAction")
        }
    }
}