我是SpriteKit的新手。我需要通过UIImageView或SpriteNode显示图像(它是游戏的背景图像)。但是,我需要用户能够放大背景并平移。我在不使用SpriteKit的情况下轻松完成了这项工作,但无法弄清楚如何让节点接受缩放和平移。如果我在故事板中使用UIScrollView,我场景中添加的所有精灵都不会成为子项,也不会缩放或平移。
有可能,你能指出我正确的方向吗?
编辑:
我对你的回答感到有些困惑,但这就是我的所作所为:
在我的根视图控制器中.m:
- (void)viewDidLoad
{
[super viewDidLoad];
SKView * showDesigner = (SKView *)self.view;
SKScene * scene = [iMarchMyScene sceneWithSize:showDesigner.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[showDesigner presentScene:scene];
}
在我的场景中.m:(您的步骤已被评论)
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
//create SKView (step 1)
SKView *skview_field = [[SKView alloc]initWithFrame:(CGRectMake(0, 0, size.width, size.height))];
//create UIScrollView with same dimensions as your SpriteKit view (step 2)
UIScrollView* uiscrollview_field = [[UIScrollView alloc]initWithFrame:skview_field.frame];
//initialize the field (field is the game's background node)
SKSpriteNode *field = [SKSpriteNode spriteNodeWithImageNamed:@"Field"];
field.position = CGPointMake(CGRectGetMidX(self.frame), (CGRectGetMidY(self.frame)));
field.size = CGSizeMake(self.size.width, self.size.height / 3);
//create a UIView (called scrollViewContent) with dimensions of background node (step 3)
UIView* scrollViewContent = [[UIView alloc]initWithFrame:field.frame];
//set UIScrollView contentSize with same dimensions as your scrollViewContent and add a scrollContentview as your UISCrollView subview (step 4)
[uiscrollview_field setContentSize:(CGSizeMake(scrollViewContent.frame.size.width, scrollViewContent.frame.size.height))];
scrollViewContent.frame = field.frame;
[uiscrollview_field addSubview:scrollViewContent];
//[self addChild:field]; -- my original code
//.....does a bunch of other inits
return self;
}
这就是我迷路的地方: 第5步:现在,在您的根视图中,在SKView上添加SKView和UIScrollView。
如果我理解正确,我需要转到myRootViewController.m并在viewDidLoad方法中,将SKView和UIScrollView(在myScene.m中初始化)作为子视图添加到viewDidLoad方法中初始化的SKView中?我不知道该怎么做。
答案 0 :(得分:15)
这是我对滚动问题的解决方案。它围绕着“窃取”UIScrollView中的行为。我从2012年的WWDC视频中了解到这一点,将UIKit与OpenGL混合在一起。
示例项目: https://github.com/bobmoff/ScrollKit
就像我在上面的评论中提到的那样,我在运行应用程序的时间中经历了一些微小的延迟。 FPS仍然是60,但似乎有一些轻微的冲突或与委托方法被调用的频率有关,因为它有时会感觉有点滞后。如果有人设法解决这个问题,我很乐意听到它。似乎只有当我握住我的手指时,它才会在减速发生时永远滞后。
答案 1 :(得分:4)
贾斯汀,
你可以使用一个小技巧,我正在使用它,它对我很有用。这是设置:
现在,在您的根视图(UIView)中,在SKView上添加SKView和UIScrollView。 它是这样的(视图控制器):
self.scrollView = [[UIScrollView alloc] initWithFrame:[UIScreen mainScreen].bounds.size];
self.scrollContentView = [[UIView alloc] init];
self.scrollView.delegate = self;
self.spriteKitView = [[SKView alloc] initWithFrame:[UIScreen mainScreen].bounds.size];
self.scrollContentView.frame = self.scene.bacgroundNode.frame;
self.scrollView.contentSize = self.scrollContentView.frame.size;
[self.scrollView addSubview:self.scrollContentView];
[self.view addSubview:self.spriteKitView];
[self.view addSubview:self.scrollView];
[self.spriteKitView presentScene:self.scene];
最后一部分技巧是实现UIScrollViewDelegate:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
//here you set your background node position based on scrollView contentoffset
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
//here you set background node scale based on scrollView zoomScale
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
//just return scrollContentView
}
这样您就可以在UISCrollView中模拟SKView。希望这会有所帮助。
编辑2014-04-20
我已经开源我的组件用于在SpriteKit中平移和滚动场景,请查看:https://github.com/pzbyszynski/PIOSpriteKit
答案 2 :(得分:1)
您可以从这个Ray W教程SpriteKit tutorial how to drag and drop开始,其中包括您要求的一些内容,包括手势识别器。
这很好:Apple gesture Recognizer reference
Ray W的另一个人:uigesturerecognizer-tutorial-in-ios-5-pinches-pans-and-more
以上是好的开始。
答案 3 :(得分:1)
我创建了自己的缩放特定节点的方法,而不必缩放整个场景,这是它的基础,但它并不完美(事实上我在这里创建了自己的帮助请求:{{3 }})
此if语句位于场景的touchesMoved方法中:
if (touches.count == 2) {
// this means there are two fingers on the screen
NSArray *fingers = [touches allObjects];
CGPoint fingOneCurr = [fingers[0] locationInNode:self];
CGPoint fingOnePrev = [fingers[0] previousLocationInNode:self];
CGPoint fingTwoCurr = [fingers[1] locationInNode:self];
CGPoint fingTwoPrev = [fingers[1] previousLocationInNode:self];
BOOL yPinch = fingOneCurr.y > fingOnePrev.y && fingTwoCurr.y < fingTwoPrev.y;
BOOL yUnpinch = fingOneCurr.y < fingOnePrev.y && fingTwoCurr.y > fingTwoPrev.y;
BOOL xPinch = fingOneCurr.x > fingOnePrev.x && fingTwoCurr.x < fingTwoPrev.x;
BOOL xUnpinch = fingOneCurr.x < fingOnePrev.x && fingTwoCurr.x > fingTwoPrev.x;
if (xUnpinch | yUnpinch) {
if (YES) NSLog(@"This means an unpinch is happening");
mapScale = mapScale +.02;
[map setScale:mapScale];
}
if (xPinch | yPinch) {
if (YES) NSLog(@"This means a pinch is happening");
mapScale = mapScale - .02;
[map setScale:mapScale];
}
}
我遇到的唯一问题是行为不一致和滚动不顺畅。我在这个意义上使用“唯一”一词,非常自由。
答案 4 :(得分:1)
如果您使用的是SKCameraNode
,则可以计算两次触摸之间的差异,以便一次定义缩放和平移。
SKCameraNode
结果应该是这样的。请注意,我使用了event?.allTouches
而不是收到的设置,如果一个手指在触摸之间不移动,则它不在touches
集合中,这会导致平移用户会期望缩放。
let cameraNode = SKCameraNode()
override func didMove(to view: SKView) {
cameraNode.position = CGPoint(x: size.width / 2, y: size.height / 2)
addChild(cameraNode)
camera = cameraNode
}
override func touchesMoved(_ touch: Set<UITouch>, with event: UIEvent?) {
guard let touches = event?.allTouches else {
return
}
let arr = Array(touches)
guard let touch = arr.first else {
return
}
var positionInScene = touch.location(in: self)
var previousPosition = touch.previousLocation(in: self)
if touches.count > 1 {
let touch2 = arr[1]
let positionInScene2 = touch2.location(in: self)
let previousPosition2 = touch2.previousLocation(in: self)
let oldDistance = distance(previousPosition, previousPosition2)
let newDistance = distance(positionInScene, positionInScene2)
let diff = (oldDistance / newDistance)
if diff.isNormal && diff != 1 {
let scaleAction = SKAction.scale(by: diff, duration: 0)
cameraNode.run(scaleAction)
}
previousPosition = average(previousPosition, previousPosition2)
positionInScene = average(positionInScene, positionInScene2)
}
let translation = CGPoint(x: positionInScene.x - previousPosition.x, y: positionInScene.y - previousPosition.y)
let panAction = SKAction.moveBy(x: -translation.x, y: -translation.y, duration: 0)
cameraNode.run(panAction)
}
func average(_ a: CGPoint, _ b: CGPoint) -> CGPoint {
return CGPoint(x: (a.x + b.x) / 2, y: (a.y + b.y) / 2)
}
func distance(_ a: CGPoint, _ b: CGPoint) -> CGFloat {
let xDist = a.x - b.x
let yDist = a.y - b.y
return CGFloat(sqrt((xDist * xDist) + (yDist * yDist)))
}