I’m trying to support both landscape and portrait orientations in my iPhone Cocos2D game, but I’m having trouble getting the coordinates to translate properly.
Here’s what I’m doing so far.
I have a GameWorld layer that I always keep in portrait, regardless of the device orientation. The following code is in my DeviceRotated event for UIDeviceOrientationLandscapeLeft. (‘self’ is my GameWorld layer)
[self runAction:[CCMoveTo actionWithDuration: 0.25f position:ccp(80, 0)]];
[self runAction:[CCRotateTo actionWithDuration:0.25f angle:90]];
So that I don’t have to write different code for each orientation I was hoping to use the following in my Sprite class to translate Sprite coordinates.
CGPoint spriteLoc = ccp(0,0);
CGPoint translatedSpriteLoc = [self.parent convertToNodeSpace:spriteLoc];
self.position = translatedSpriteLoc;
However, this doesn’t work.
If the device is in portrait mode with the sprite in the lower left corner and I rotate the device to the left, the sprite appears in the lower right. I want the sprite to be in the lower left in landscape just like it is in portrait.
Am I missing something or is there a better way to translate coordinates?
Well, if you don't mind a "jump cut" when you switch orientations, you can just use the built-in orientation support within Cocos2d. See this post at the Cocos2d forums.
If, however, you need pretty orientation, you may have to do something along the lines of what you were showing above, orienting things manually via rotation using actions.
Without more detail, it's hard to say why your approach doesn't work, but my guess is that you are seeing the sprite positioning you describe as a result of the fact that if you don't change orientation, the lower left in portrait IS the lower right in landscape when rotated left, i.e., it's the same point in GL space: (0,0). You're going to have to move the "origin point" of your GameWorld Layer as well as rotating it.
Try adding a full-screen image to your layer to see what's actually happening when rotating it. That should help you narrow down what you need to do.
Related
I'm new to Swift SpriteKit programming and the coordinate system is driving me crazy. I create a sprite and I want to move it to the four corners of the screen. So, I set the position to (0,0). That's off the bottom left corner of the screen. Through some manual testing I've developed the chart below. The lower left and upper right are what the iOS simulator report when I touch the screen.
I have 2 questions:
1: Is there a method of determining the coordinates of the lower left hand corner of the view? Maybe I could build a dictionary with the coordinate values and the determine the machine type and then set the offsets. But, that's a lot of work and might not be accurate for new devices. It just seems that there should be a scene or frame property that I can use to put an object at the bottom left of the window.
2: The math doesn't work. In the iPhone5, 300 (lower left x) + 320 (width) = 620, not the reported 727. Same issue is true with the y coordinates. How does this work?
I set as few parameters as possible. I have not changed the anchorPoint or position of the scene.
Device Size LL UR
iPhone4s (320,480) (260,0) (766,764)
iPhone5 (320,568) (300,0) (727,764)
iPhone5s (320,568) (298,0) (727,764)
iPhone6 (375,667) (297,1) (728,765)
iPhone6plus (414,736) (298,0) (728,766)
iPad2 (768,1024) (226,0) (800,768)
iPad Air (768,1024) (224,0) (800,767)
iPad Retina (768,1024) (225,0) (800,768)
Ok, I think I figured this out. Setting scene!.scaleMode=SKSceneScaleMode.ResizeFill allow me to identify the four corners of the screen. So, now I can determine when a sprite crosses the edge of the screen. This doesn't seem to distort my images. I haven't been able to test it on a read device yet, but it leaves a blank area around the iPad2.
Applause for the hard work! haha
If I was going about getting values for the lower coordinates, I would use CGRectGetMinX to get the x-coordinate and CGRectGetMinY to get the the y-coordinate likewise:
CGPoint minimum = CGPointMake(CGRectGetMinX(self.frame),CGRectGetMinY(self.frame));
Then, if you wanted to get the top coordinates just use the same things but say MaxX or MaxY. Yeah, the coordinates are a bit confusing but if you use those then it will be a breeze.
EDIT: If you need to find if a body has exited outside visible space, so far what has worked for me is making a physics body to detect contact with it on the edge
[SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame]
possibly another option you could try is to see the bounds of a UIScreen object.
I'm making a game which uses multiple UIViews for its displaying of content.
There are 2 UIViews. One of which is a map; another is a plane.
The plane's view is static. It doesn't move, rotate, scale etc.
I'd like to have the map translating under the plane, rotating at the same time. The map's origin (or center point) needs to be set as the plane's center point every frame.
How do I achieve this?
I'm using CGAffineTransform for this, and it works okay, until I want to turn round back on the map once I've left it.
Here's what I'm doing now:
CGAffineTransform oldTransformation = CGAffineTransformTranslate(CGAffineTransformIdentity, 0, frames);
oldTransformation = CGAffineTransformRotate(oldTransformation, rotation);
cityView.transform = oldTransformation;
Any help appreciated.
This blog here talks about using CAAnimationGroup to apply multiple animations (center point, rotation, and bounds) at the same time. It includes a sample application which you can get on github here. (Note: run the app in iPad simulator).
The animation used in that project combines the simultaneous change of center point and rotation of a view.
Hope this helps.
I have an open GL ES (1.1) scene with many 3d objects and a "player" model. I'd like the player to have the same pixel size, regardless of the screen orientation on an Android phone or Iphone.
I'm not using glOrtho or billboards. That's a perspective 3d scene, but I just want the objects to have the same size in both screen orientation. Currently, if I rotate the phone, I keep the same aspect ratio but the scene "zooms out" in landscape mode.
I suspect that I have to play with parameters to glFrustrum to get this; but can't figure out yet how to do it.
So any ideas are welcome!
Thanks
You will need to change the aspect ratio when the device is turned to go from a the otherwise the size of the objects are going to change. THink of yourself looking out through a window, the objects on the other side of the window are only going to be the same size if you don't change your distance from the window (i.e. zooom in and out), when you "turn" the window sidewayse, the aspect ratio of the window changes (the metaphor is starting to not work).
If you draw a square in the view with the side length being the short side of the screen, then you should still have a square when you turn the phone sideways, still covering the same area on the screen.
Things will probably be easier to calculate if you use the code from gluPerspective. You set the aspect ratio to the actual aspect ratio, fix the fovy for the first aspect ratio. You can then use what would be fovx for this aspect ratio as the fovy for your rotated view.
On an iPhone 3Gs, if you click the little "show my location" symbol on the lower left of the window twice, it switches to a mode that causes the map to rotate so that north on the map faces towards north according to the compass. I don't have a 3Gs, so I just found out about this from a buddy who does have one.
I tried applying a rotation transformation to a MKMapView's layer, like this:
CATransform3D rotationTransform = CATransform3DIdentity;
rotationTransform = CATransform3DRotate(rotationTransform, degreesToRadians(-20), 0.0, 0.0, 1.0);
theMapView.layer.transform = rotationTransform;
That sort of works, but not really. The contents of the map do rotate, but the frame rotates and stretches. The map view ends up in a strip that stretches diagonally across the screen, and it ends up under the buttons in my view.
I tried enclosing the map in another view to isolate it, but that doesn't work either. Next I'll try rotating the enclosing view, but I'm hoping somebody else has figured this out. Getting it to work by trial and error is likely to be difficult at best.
Regards,
Duncan C
I have the same problem. I was able to solve the stretching by placing the MkMapView in a UIView container.
Looking for clues about orienting an OpenGL ES app in landscape, most information I found dates back from 2008, most of it refering to the early versions of the SDK. Apparently, back in the days, in the case of GL it was recommended to not rotate the view, but instead to apply the rotation as a GL transformation. Is it still the case with the current SDKs? It would be so much simpler to simply rotate the window: all the touch events would be in sync with the rotation.
In other words: how to set up an OpenGL view in landscape mode?
(I'll answer my own question with the solution I found. I'll be happy to consider other answers though.)
In the CAEAGLLayer docs, Apple states (a bit clumsily) that you should make the rotation within GL itself: "When drawing landscape content on a portrait display, you should rotate the content yourself rather than using the CAEAGLLayer transform to rotate it." They don't explain why, but I've read in multiple places about a noticeable drop in performance.
Luckily I solved it with the addition of just a few lines. This is for landscape orientation right, where the home button is on the right.
glPushMatrix();
glRotatef(90, 0.0, 0.0, 1.0);
glTranslatef(0.0f, -320.0f, 0.0f );
// *** ALL RENDERING GOES HERE ***
glPopMatrix();
If you're targeting the iPad, replace -320 by -768.
I also convert the coordinates from the incoming UITouches:
int touchx = touch.y;
int touchy = viewWidth - touch.x;
Maybe, it's changed now. If you look into the latest OpenGL ES programming guide you can find the below sentence:
"In iOS 4.2 and later, the performance of Core Animation rotations of renderbuffers have been significantly improved, and are now the preferred way to rotate content between landscape and portrait mode. For best performance, ensure the renderbuffer’s height and width are each a multiple of 32 pixels."
As like this way:
[eaglLayer setAffineTransform:CGAffineTransformMakeRotation( -90 * M_PI / 180)];
But, CAEAGLLayer Class Reference mentioned "When drawing landscape content on a portrait display, you should rotate the content yourself rather than using the CAEAGLLayer transform to rotate it.". Maybe, documentation is not updated yet. Last updated time is 2008-05-19.
Just FYI who're visited this Q&A as like me.
You need to set up you're camera's matrix with the up vector on the X axis as opposed to the Y axis, which is what you would normally do. Rotating the world by 90 degrees works, but makes working with everything else difficult.
Use somthing like:
up.x = 1; // instead of up.y
up.y = 0;
up.z = 0;
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, position.x, position.y, position.z, lookAt.x, lookAt.y, lookAt.z, up.x, up.y, up.z);