I am building a game with swift where I have sprites moving around the screen that you have to avoid. When I test the game on say iphone 5, the objects are harder to avoid than on the 6 or 6+. I think this is because I had the velocity the same across the board (I am adjusting the sizes based on screen size). I changed the original impulse to try and vary based on the screen size with matching the numbers I originally had for the CGVectors with this
let gOneX = screenWidth/6
let gOneY = screenHeight/9
let gTwoX = screenWidth/6
let gTwoY = screenHeight/9
ghostOne.physicsBody?.applyImpulse(CGVectorMake(gOneX, -gOneY))
ghostTwo.physicsBody?.applyImpulse(CGVectorMake(-gTwoX, gTwoY))
I did this, and it helped enough to notice a difference between devices, but it was still not acceptable. The objects were still harder or easier to avoid based on device.
Is there any other way I can vary the impulse?
Related
Note: I have tried this answer: Gap between SKSpriteNodes in SpriteKit collision detection
I am getting gaps in between my SKSpriteNodes, after 5 minutes of letting my game run. Here is my code to make the node:
let tileNode = SKSpriteNode(imageNamed: "world1Tile\(tileNumber).png")
tileNode.position.x = x
tileNode.position.y = y
tileNode.size.width = 128
tileNode.size.height = 128
tileNode.zPosition = 10
tileNode.physicsBody = SKPhysicsBody(rectangleOf: tileNode.size)
tileNode.physicsBody!.isDynamic = false
tileNode.physicsBody!.restitution = 0
tileNode.physicsBody!.allowsRotation = false
tileNode.name = "Tile"
row.append(tileNode)
When I remove the physics body, it is running fine. Here is are some images to show you what I mean:
This image has a physics body, and was taken after immediately after running the app.
This image was taken 5 minutes after running the app.
Why is this happening? I assume it has something to do with the physics body, because my app looks exactly like the first picture, even an hour after running the app if there is no physics body. What physics body property should I change to stop this from happening? Any help would be appreciated.
I had a similar issue not too long ago, where gaps were appearing between nodes that were tiled (although I didn't use physics). Based on this answer, I found that if you want perfect alignment between nodes, it is best to ensure that the positions of nodes as well as the nodes' width and height are whole numbers.
I would suggest to round-off the x and y values of the position of tileNode and see if it will make any difference .
I'm guessing there is no gap. you probably have 'showPhysics' to true in your gameviewcontroller, and the line appears as a gap to me.
compare position with and without the pb to verify.
I had similar problem where gaps between sprites started appearing after around 5 minutes of scrolling with constant speed (game with infinite scroll). I did not use physics and I even had all positions, widths, heights rounded to integer value. I was scrolling the camera and adding new sprites one right after another and everything was working fine except after around 5 minutes of that infinite scrolling gaps begin to appear just as in your case. I spent some time in looking for a solution and it turned out that the problem was that when positions of my objects were becoming big that is in my case X position in the scene was around 150000 then those gaps started to appear and also I noticed that this problem occurred only on devices which had to scale the scene. I was using aspect fill with default scene size for iPhone 6 resolution and those gaps only appeared on iPhone 5 but on iPhone 6 I did not notice them. I was able to fix that issue by subtracting some constant value from X position of all objects (including camera position) from time to time so that everything on the scene relatively did not change position to the camera and look the same but actually absolute positions were changed to keep them low. I guess that larger position values like 150000 and scene scaling cause some floating point rounding issue in SpriteKit and that is why gaps are then becoming visible.
So based on my experience if you have similar gaps I recommend using integer values for all positions, widths, heights and additionally keep values of objects positions of all objects low.
For future reference in case someone is still searching for this, here are my experiences:
If tiles have PhysicsBodies, they are prone to making gaps. A solution for me was making a blank SKNode as a child of the tile, and assigning the PhysicsBody to that.
If possible, make sure bit masks are set in a way that tiles can't collide with each other.
As stated in a previous answer, make sure all measurements are integers and rounded in a way that doesn't leave a one unit gap between them.
A related problem is also SpriteKit's PhysicsBody drifting. There are some threads about this (e.g. https://forums.developer.apple.com/thread/27057 ), and it seems to be abug. In my case, the problem was a combination of PhysicsBodies causing random small gaps, and the drifting making some of them larger. The steps above removed the small gaps. Unfortunately the only workaround for the drifting problem in my case was to only generate PhysicsBodies for nodes that are within a certain distance from the player and destroying them after they are left behind.
For future reference for anyone who needs, I found an different answer specific to my problem. As JohnV said, I may need to round of values when setting the position, but when running the code, I found out that I also need to do that when running SKActions.
I'm extremely new to SpriteKit, and have been following some great tutorials by someone online. They all do one thing which I think might be a red flag, but wanted to ask the community about.
Prerequisite: all his demos are done using iPad (it's set in the app settings to only target iPad, so no intention of iPhone).
So what i'm seeing is the developer creates labels and graphics by using hard-coded points.
For example to make the text "game over" appear:
let gameOver = SKSpriteNode(imageNamed: "gameOver")
gameOver.position = CGPoint(x: 512, y: 384)
gameOver.zPosition = 1
addChild(gameOver)
So the thing about this code is it's hard-coded to be at a specific point. So this means that in theory, it's going to be slightly wrong on the iPad mini vs. the iPad pro, correct (since he intended this to be on the iPad air)? Or do the devices translate where that should be every time?
I feel like you'd want to do some fancy magic like calculate the width/height of the screen and divide by some number to calculate the center, rather than specify points.
In fact, all of his code more or less uses hard-coded points for example look at this to render sprites:
for i in 0 ..< 5 { drawSpriteAt(CGPoint(x: 100 + (i * 170), y: 410)) }
for i in 0 ..< 4 { drawSpriteAt(CGPoint(x: 180 + (i * 170), y: 320)) }
for i in 0 ..< 5 { drawSpriteAt(CGPoint(x: 100 + (i * 170), y: 230)) }
Is this not a major problem if I were targeting iPad mini and iPad pro as well?
For some reason, however, I ran this on the simulator in iPad pro and it actually looked pretty good.
So my question, ultimately then, is:
Is this just fine to do it this way? Do the different iPads somehow magically work out what the point (512, 384) is such that that point is different on an iPad mini vs. iPad pro?
Thanks and apologies if this is a basic question, I just wanted to see that if I were only writing an app to target iPhones, or iPads (i'm doing both actually) that I would make two separate apps with hard-coded coordinates specific for one device.
For example i'd say "on all iPads, regardless, use point (512,384)" and on an iPhone i'd say "on all iPhones of all sizes, use point (300, 150) or something like that.
Thanks so much for your help!
Sprite Kit is designed to have a scaling system so you don't have to worry as much about coordinates. The coordinates don't represent pixel or point coordinates on the screen - but are coordinates in the game scene. Basically if you setup a scaling mode for you game, your coordinates will be taken care of for multiple screen sizes.
(You would be correct in your assumption if you were just talking about iOS button/view coordinates.)
See the documentation here: https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Nodes/Nodes.html
After a scene is rendered, its contents are copied into the presenting
view. If the view and the scene are the same size, then the content
can be directly copied into the view. If the two differ, then the
scene is scaled to fit in the view. The scaleMode property determines
how the content is scaled.
When you design your game, you should decide on a strategy for
handling the scene’s size and scaleMode properties. Here are the most
common strategies:
Instantiate the scene with a constant size and never change it.
Pick a scaling mode that lets the view scale the scene’s content. This gives
the scene a predictable coordinate system and frame. You can then base
your art assets and gameplay logic on this coordinate system.
Adjust
the size of the scene in your game. Where necessary, adjust your game
logic and art assets to match the scene’s size.
Set the scaleMode
property to SKSceneScaleModeResizeFill. SpriteKit automatically
resizes the scene so that it always matches the view’s size. Where
necessary, adjust your game logic and art assets to match the scene’s
size.
I would like the scenes of my game in SpriteKit to appear differently sized depending on the size of the device. Right now I am manually resizing and positioning some of my nodes with an 'if' statement checking for frame size, but unfortunately I cannot do this for all of my sprites due to the mechanics of my game (I am detecting collisions based off of the positions of my nodes, not by using PhysicsBodies. If I were to change the size of the nodes, these collisions would not be detected).
Is there a way to scale the appearance of the view according to the device size instead of actually scaling the sprites themselves (i.e. the view would stretch out to fit frame size but in reality the sprites would actually be the same size)? Is this something I would achieve by changing the SKSceneScaleModes from .ResizeFill (the one I am currently using)?
I don't believe there is an easy way to fix my problem, nor do I believe that the solution I was looking for exists. This is how I fixed my problem:
First, I changed my game mechanics. I've learned that when you are going about designing and initially planning out your game, you have to really focus on making your game both easily expandable and universal. The way that I had my game first set up was quite limited.
I figured out how I wanted to scale my game and set up my own little system (not really my 'own', its probably a pretty common setup):
var scene = GameScene(size: self.size)
var skView = self.view! as SKView
scene.size = skView.frame.size
var scale = self.frame.size.height / 736
Then I just set the scale to my nodes like so:
self.titleText.setScale(scale)
First, I am setting the size of the current scene as the size of the frame size of the skView. With that, I am creating a scale factor by dividing the size of the scene by the frame size of an iPhone 6 plus. The sprites will now appear at a scale factor of 1 on the iPhone 6 plus and downscale from there.
Anyways, I know this explanation wasn't perfect and that there is probably a more efficient way of doing this. I am relatively new to SpriteKit and have a lot to learn, but I didn't want to leave this question unanswered on the off chance that somebody stops by here. Thanks, and feel free to message me if you have any questions or I messed up somewhere.
I get feedback from my users, that "from time to time" my Game-App has a bug were the ship gets completely uncontrollable. After investigating into this, it looks like the attitude, reported by CoreMotion drift away very fast (below a second) and it does that suddenly. You can play for up to five minutes, then it happens suddenly that the ship moves to one of the screen borders and does not move away from that point any more.
My question: Has anybody made the same experience with CoreMotion attitude and what are your ways or ideas to get control over this sudden, massive drifts?
The code I'm using to get the attitude in the update() of SpriteKit is:
if let motion = motionManager.deviceMotion {
let x = CGFloat(motion.attitude.yaw - basePosition.x)
let y = CGFloat(motion.attitude.roll - basePosition.y)
ship.physicsBody?.applyImpulse(CGVectorMake(X_SENSITITVITY * x, Y_SENSITITVITY * y))
}
where basePosition, X_SENSITITVITY, Y_SENSITITVITY are constant values in the game.
motionManager is defined by private var motionManager = CMMotionManager() at the top of the class.
As far as I understand the documentation, deviceMotion uses a combination of gravity and attitude measure to minimise the long term drift somehow.
Maybe also important to notice: When the Game runs in a silent environment without the vibrations of cars etc, it works perfectly fine.
I would like to have people to play my game whenever they need a rest - like on long train rides or flights - or kids in the backseat of the car.
I figured out the same drift problem. I compared the CMDeviceMotion's attitude with the CLLocation's magneticHeading. Therefor, I walked 10 times around a small table and put the device after every round on the exact same place.
I figured out, that the DeviceMotion's attitude drifts around 30 degrees every round. Thus, after 10 rounds the attitude is around 300 degrees off.
According to Apple's WWDC 2012 talk "Session 524: Understanding core motion" the used sensor fusion depends on the specified reference frame. Phil Adam mentions, that the sensor fusion algorithm also uses the magnetometer if the xArbitraryCorrected reference frame is specified. I did the same test with xArbitrary, xArbitraryCorrected and xMagneticNorth, but there is no difference. The compass's uncertainty is around 2 - 3 degree (with a heading filter of 1.0 degree).
Maybe it's a bug, I don't know. But I expected at least a difference between xArbitrary and xArbitraryCorrected.
ok, I've found a way to handle this. And as I see a number of views on this question there might be some interest in the answer and some people dealing with the same issue.
From my understanding, there're two things you can rely on:
The change of devices in motion. Specifically CMDeviceMotion.rotationRate
The attitude of a device towards earth. Specifically CMDeviceMotion.gravity
It looks like the first uses changes in current position by reading some kind of current forces. This is a current value and there's no need to sum up the values - and therefore no errors are summed up.
The second one (gravity) measures the current forces against earth. Again: current values, no sum up, no sum up of errors, no drift.
Anything else, especially CMDeviceMotion.attitude, takes measures and adds them up. Leading to adding up the small errors in each measure, leading to a drift in the result.
I've tried to use rotation rate and calculate the attitude myself by adding up. Well, Apple is not perfect in doing that, but way better then any of my solutions :-)
Talk is cheap. Where's the code? Here it is. This method is called during update() in SpriteKit (for every frame)
private func update(ship: SKSpriteNode) {
// Orientation can be landscape left or right
let orientation = UIApplication.sharedApplication().statusBarOrientation == UIInterfaceOrientation.LandscapeLeft ? -1.0 : 1.0
// Get rotation rate
let x = orientation*motionManager.deviceMotion.rotationRate.x
let y = orientation*motionManager.deviceMotion.rotationRate.y
// If user tilts device very slow it does not affect the ship
let xf = CGFloat(abs(x) >= X_RESPONSIVNESS ? X_SENSITITVITY*x : 0.0)
let yf = CGFloat(abs(y) >= Y_RESPONSIVNESS ? Y_SENSITITVITY*y : 0.0)
// Apply as impulse
ship.physicsBody?.applyImpulse(CGVectorMake(xf, yf))
}
As my game is more about "how does the user tilt the device to let me know where you want the ship go to" I simply used rotationRate to measure this and apply it as impulse. As an add-on you can rotate the device which means that what was a rotation towards the top of the screen is actually a rotation to the bottom after rotation. So I have to invert the impulse when the device is rotated.
You can now play the game in any direction. Landscape left, Landscape right, overhead, in a vibrating environment like cars or trains. It works like a charm. I'm even looking forward to a 2.5 hours flight next Saturday...
I am working on a iOS Game Application (Race) which requires the background to have transition coming forward.
For the above requirement I have written a code where I have to make people feel as if the objects were coming from a far distance to nearby.
Hence I am using transition to do so where I increase their y position and scaling (both xScale and yScale). While doing so, the problem I am facing is when the objects seem to come closer with their size increasing (using scaling), the distance between the objects decreases from their actual distance because of scaling and it does not perfectly look as if the objects were coming from far behind.
Please let me know what is the best way to achieve what I trying to do or else if there is any available sample code having the functionality of car/bike racing.
transition.to ( object,{ time=500, alpha=1,x = (destination x coor),y = (destination y coor),width =(to scale x),height =( to scale y), onComplete=saltCellarOnComplete} )