问题
I'm building a universal app using Sprite Kit, Objective C. This app is aimed for OS X as well as iOS platforms.
A problem that many people will have encountered is the positioning of objects on the screen as different devices have different proportions. I have read up many answers/posts online to solve this issue and have come to the conclusion that there seem to be only a few options available to the programmer when it comes to solving this which is selecting the appropriate scaling modes which are available: Aspect Fill, Aspect Fit, Fill, Resize Fill.
I have tried all 4 out, and can see that they all have numerous advantages, but all have their cons, so none of them are what I am looking for.
I have come up with my own solution for what I am looking for (the following code is from the OS X version, but the iOS version is very similar):
First, I define sceneDimension using a macro:
#define sceneDimension 1024
Then I delete the SKScene file, and create my own scene using the following line of code:
@implementation AppDelegate
@synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
GameScene *scene = [[GameScene alloc] initWithSize:CGSizeMake(sceneDimension * (self.skView.bounds.size.width / MIN(self.skView.bounds.size.width, self.skView.bounds.size.height)), sceneDimension * (self.skView.bounds.size.height / MIN(self.skView.bounds.size.width, self.skView.bounds.size.height)))];
.....
}
.....
@end
This code ensures that whatever the size/proportions of the device the app is running in, the top right coordinate of the screen will always be treated as (x, 1024) if the width of the screen is larger, or (1024, y) if the height of the screen is larger.
In this way, I won't have to worry about repositioning objects as long as the scene always maintains the smaller coordinate of the top right corner to be 1024. (This is not the same as Aspect Fit, as I don't want to have letterboxing)
The problem I'm encountering is apparent when I run the app on OSX. Whenever the window is resized, a scaling mode still needs to be selected, and none were the ones which I was after.
Therefore, I wish to override whatever the program does when it scales the screen, by using the line of code:
scene.size = CGSizeMake(sceneDimension * (self.view.bounds.size.width / MIN(self.view.bounds.size.width, self.view.bounds.size.height)), sceneDimension * (self.view.bounds.size.height / MIN(self.view.bounds.size.width, self.view.bounds.size.height)))
However, I don't know where to add the line of code. I have tried using this line of code in the function didApplyConstraints:
in the .m file:
@implementation
.....
- (void)didApplyConstraints {
scene.size = CGSizeMake(sceneDimension * (self.view.bounds.size.width / MIN(self.view.bounds.size.width, self.view.bounds.size.height)), sceneDimension * (self.view.bounds.size.height / MIN(self.view.bounds.size.width, self.view.bounds.size.height)))
}
@end
And this gives the desired result mostly. However, during the dragging of the mouse, it can still be seen that the scene is being scaled using one of the previously mentioned scaling mode, rather than my new function. I also read that didApplyConstraints:
is called every frame, which is what I don't want to happen - I want it to be called whenever the size of the window changes.
Is there a more appropriate function instead of didApplyConstraints:
which does this? didChangeSize:
does not work either, since the program ends up in an infinite loop since I change the size inside the function.
Thanks!
回答1:
It sounds like what you are trying to attempt is .AspectFill, but with a twist. You want to fill up your screen, but keep your coordinate system the same on the x axis for all devices.
When you are doing your math, you need to take the aspect ratio into consideration.
We are only going to talk about portrait mode here.
We have an iPhone 5 that has an aspect ratio of 9:16.
We want our x to always be 1024.
This means that we want our y to be 1820 (1820.4444~ to be exact)
Now we have an iPhone 4 that has an aspect ratio of 2:3.
This means that we want our y to be 1536
So, to get these numbers, you take (1024 * height) / width
We can now again talk about both portrait and landscape.
Here is how you would apply the math:
let w = sceneDimension
let h = (w * UIScreen.mainScreen().bounds.size.height) / UIScreen.mainScreen().bounds.size.width)
scene.size = CGSizeMake(w,h)
This now means that regardless of orientation, when the scene is created, the bottom left most point is (0,0), the bottom right most point is (1024,0).
Aspect Fill will now fill up the entire screen, leaving no letter boxes, and no loss on your edges
来源:https://stackoverflow.com/questions/34499143/sprite-kit-is-there-a-way-to-disable-the-scale-mode-and-code-what-you-want-to-h