I need to move a SpriteNode across the frame. I am currently having the issue of it having glitches while doing so (losing a couple of frames? not really sure). What I need is for the object to travel horizontally without a fixed direction x destination so that if x is offset by some impact the object does not attempt to return to its initialized x coordinate.
Here is how that part of the code looks like right now:
`spaceRock.physicsBody?.affectedByGravity = false
spaceRock.physicsBody = SKPhysicsBody(texture: (spaceRock?.texture)!,
size:(spaceRock.size))
spaceRock.zPosition = 1
spaceRock.position=CGPoint(x: xSpawnPosition, y:
Double(self.size.height/2+(spaceRock.size.height)))
spaceRock.physicsBody!.isDynamic = true
spaceRock.physicsBody!.allowsRotation = true
spaceRock.physicsBody!.categoryBitMask = 00000001
spaceRock.physicsBody!.contactTestBitMask = 00000010
addChild(spaceRock)
spaceRock.physicsBody?.applyTorque(CGFloat(randTorque))
//spaceRock.run(SKAction.moveTo(y: -self.size.height-
spaceRock.size.height, duration: rockTravelTime))`
The comment is what I have been using up until this point.
Thank you for the help!
You are mixing physics simulation (SKPhysicsBody) and direct movement of the Sprite (SKAction.moveTo) - although you may be able to do that to achieve special effects, in general they will fight each other and cause problems.
If you need your objects to move realistically, then use an SKPhysicsBody and apply forces (Torque, thrust etc.) to move it. This will be quite complex to program and has a significant processing overhead.
If you prefer to move your sprites directly then get rid of the SKPhysicsBody and your moveTo should then work fine.
Related
I'm trying to create an application in which the user stacks different geometric shapes. In a .scn file, which is loaded inside the ARSCNView, I insert a static plane and then at each tap of the user, the app inserts a dynamic SCNNode.
The first node is being inserted a few inches above the plane, to replicate a falling object. And then, each other node is being dropped on top of another.
This is the main idea of the application; the problem appears after adding 3 or 4 nodes, they appear to slide of each other, almost jiggle, and the whole structure collapses.
This is my node I'm inserting:
let dimension: CGFloat = 0.075
let cube = SCNBox(width: dimension, height: dimension, length: dimension, chamferRadius: 0.0)
let node = SCNNode(geometry: cube)
node.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.dynamic, shape: nil)
node.physicsBody?.mass = 2.0
node.physicsBody?.friction = 1.0
node.physicsBody?.restitution = 0.01
node.physicsBody?.damping = 0.0
node.physicsBody?.angularDamping = 0.0
node.physicsBody?.rollingFriction = 1.0
node.physicsBody?.allowsResting = true
let insertionYOffset = 0.3
node.position = SCNVector3(hitResult.worldCoordinates.x, hitResult.worldCoordinates.y + Float(insertionYOffset), hitResult.worldCoordinates.z)
I've tried to play with the values and these are the best ones, but they aren't enough to create a stable structure of blocks.
As a requirement, I need to keep the blocks dynamic, they need to be affected by gravity, wind, etc.
The problem most likely has something to do with a factor called Dynamic which will allow it to continuously move or may have to do with the objects hitting each other to fix that problem all you have to do is change the collision mask to two different numbers.
I see two points that may be the flaws of your simulation:
Your objects are stacked. When two objects collides there's a small amount of error added in order to keep the physics in a stable phase and prevent weird behaviors. So when you stack objects you add error amounts and the simulation becomes inaccurate. I suggest making objects static over time or depending of the position, or reduce gravity by a bit.
Most of the physics engines works better with objects sized with the unit size (most of the cases, it's 1 like in Box2D or PhysX). Objects that are very small or very big tend to act less natural. 0.075 sounds a bit small for a simulation. I don't see a obvious solution, maybe look for a way to change the reference size.
I'm fairly new to swift, and have been working on a game for fun, and i'm running into something I can't quite get my head around.
When the run button is pressed, the character moves forward with the following function
func move(dt: CGFloat) {
position.x += moveRate * dt
}
And when the jump button is pressed, the character jumps with the following function
func jump() {
physicsBody?.applyImpulse(CGVector(dx: 0, dy: jumpRate))
run(jumpAnimation!)
}
both work fine, but consider this senario. The player is running, and then they jump while still moving. While in the air, the player releases the move button and the player's x position stops dead. This obviously feels very unnatural, and i would like the player's x position to ease out.
Now i have also played with moving the character with physicsBody?.applyForce(CGVector(dx: 1000, dy: 0)) which would give that effect, but he seems to just gain more and more speed and you don't get a constant rate or "max speed" so to speak.
Could anybody share some insight with me? I'd love to learn anything I can about spritekit and game development in general. Thanks!
You should try to set the velocity instead of setting the X position. When setting the position you bypass all the physics behaviors.
You should also try to set it only when you actually press a button.
func move(dt: CGFloat) {
if Math.abs(moveRate) > 0.1 { // If player initiates movement. You can increase the value 0.1 if you want to filter move values
velocity = CGVector(dx: moveRate, dy: veloxity.dy)
}
}
It your character moves indefinitely like in space, linearDamping will be useful. it's used to simulate air friction, so values closer to 1 means more friction and values closer to 0 means less friction.
linearDamping = 0.85
Also, this way, moveRate isn't dt dependent but it should be lowered.
Try it, I haven't tested it yet, but that's basically how I would do it.
There are two schools of thought on platformer game "physics".
Don't use physics, do everything with positional incrementation.
Do everything with physics, since positional changes mess up physics
Since you're using physics for jumping, and physics jumping is fun:
There are three ways to create movement in a physics system:
Set the velocity as and when required. This is what Crazyrems is suggesting
Apply impulses as needed to increase and decrease rates of movement
Apply forces over time that increase or decrease rates of movement
Use fields to induce motion (too complex for this, and messy, but fun)
What you're attempting, with your physicsBody?.applyForce(CGVector(dx: 1000, dy: 0)) is the application of force over time. Number 3 in the list above. The longer you continue applying this force the faster the character moves.
Each of these techniques can be made to work, but they all need compensation for their various limitations and methodologies of simulation.
In the case of your approach, you need monitor speed and to set a maximum speed. Having reached maximum speed, if the player is still holding the button, only provide enough force to maintain speed (assuming you're using some form of constant resistance to slow the character).
Monitoring speed combined with force-over-time creates interesting acceleration trait possibilities - like very strong initial acceleration and then taper off acceleration as the player nears their maximum speed.
Slowing down when the player releases the button is the next focus. In all these approaches you need something that slows the player. This can be the application of opposing forces, or the use of friction or damping, as provided by the physics engine.
I am developing a game with swift Sprite kit. But I've got a problem, as you can see in the picture I have a number of physical blocks with the same size aligned. When I slide this block above the others sometimes he gets stuck or do small jumps.
It seems that the physical bodies sometimes overlap.
Anyone know how I can fix it to have a continuous and without inprecision movement?
Some physics characteristics:
player.physicsBody?.friction = 0.0
player.physicsBody?.restitution = 0.00
player.physicsBody?.linearDamping = 0.1
player.physicsBody?.angularDamping = 0.0
player.physicsBody?.allowsRotation = false
player.physicsBody?.velocity.dx = 0
player.physicsBody?.velocity.dy = 0
player.physicsBody?.categoryBitMask = heroCategory
player.physicsBody?.contactTestBitMask = enemyCategory
player.physicsBody?.density = 2.3
The problem appears to be just a slight imperfection of physics engine (and hey, it's a simulation, and not completely accurate, I've run into this kind of thing before). I see that you are preventing rotation of the player, so you can change the physics body of the square player into a circle. This should be something like:
player.physicsBody = SKPhysicsBody(circleOfRadius: 10)
Replace 10 with the proper radius of your player. This should smooth out the bumps you are encountering.
How are you sliding the block?
I've had the same problem and I was able to solve it sliding my hero using SKAction to run a code block that changes the hero's velocity or by just simple running an SKAction.moveBy. Your SKAction should'nt be attempting to push your block against the ground. An action to move the block only in the x direction.
You can also smooth the surface by making sure your physicsBody(s) of ground blocks are not overlapping. Introduce a gap of 1-2 points. Or maybe group tiles with a single physicsBody. This may help as well.
I really hope someone understands what the effect is that I am asking for. Have you ever played the games where a character is sliding one way and when you try and change the characters direction it is not immediate as they need to slow down in the initial direction before they can start sliding the other way? The new game on the App Store 'Swing Copters' by the maker of Flappy Bird is exactly the effect I am talking about. Can someone please help me create this effect in SpriteKit. I have already tried achieving it by applying different forces but I am either not doing it correctly or the effect isn't possible with forces.
Thanks in advance!
Maybe you want to try working with some acceleration-stuff.
Let's think about the gravity on the earth (a = 9.81 metres/s²). If you throw a ball straight to the sky, the Ball is starting with a velocity of: lets say 5metres per second(positive velocity).
After a short time, the gravity is pulling the velocity of the ball down to 0, so the ball can't get any higher. Right after this, the gravity pulls the ball down until it hits the ground. (Negative velocity)
If we're talking about this in a game, where the ball doesn't move up or down but from left to right, you can use something like this. The moment when you throw the ball, is the moment in the game where you send the command to change the direction. The ball keeps going in the direction where it used to go, gets slower, stops, changes the direction and finally gets faster and faster until you send another command to change the direction again(Or it hits the Wall/the ground). In that case you have to inverse the acceleration you want to use, so the whole thing repeats in the other way.
If the ball should move to the right, positive acceleration,
if the ball should move to the left, negative acceleration.
As formula you can use something like
v = (int) (a * t + v0);
v0 = v;
v is the next velocity, a is the acceleration you want to use, t is the spent time and v0 is the current velocity. t should count the nano-time since the last direction-change. (int) casts the whole thing to an integer, so you can use this directly to move the ball/graphics on the screen.
Repeat this each frame.
For the direction change you can use
t = 0;
a = a * (-1);
t has to be 0 again, otherwise it gets buggy.
I hope this was helpful.
I have tried many different techniques of applying a realistic looking gravity feature in my game but have had no luck so far. I plan on offering a 100 point bounty on this for someone who can show me or (share) some code that applies gravity to a CCSprite in Cocos2D.
What I have done so far has just been ugly or unrealistic and I have asked in many different places on what the best approach is but I just have not found any good looking gravity techniques yet.
Anyway, can anyone offer some tips/ideas or their approach only applying gravity to a CCSprite in Cocos2D without using a physics engine?
Thanks!
A effective approach without having to explicitly use any physics engine is to step the velocity and position of your sprite manually in your update loop. This is essentially Euler Integration.
// define your gravity value
#define GRAVITY -0.1
// define a velocity variable in the header of your Game class/CCSprite Subclass (neater)
float velocity_y;
-(void) update: (ccTime) dt
{
// Step the y-velocity by your acceleration value (gravity value in this case)
velocity_y += GRAVITY *dt; // drop the dt if you don't want to use it
// Step the position values and update the sprite position accordingly
sprite.position.y += velocity_y* dt; // same here
}
In the code snippet above, I defined a velocity_y variable to keep track of my sprite's current velocity along the y-direction. Remember to initialize this value to 0 in your init method.
Next comes the crux of Euler. At every time step:
Advance your velocity by your acceleration (which is your gravity) multiplied by dt to find your new velocity.
Advance your position by your newly computed velocity value multiplied by dt to find your new position.
You can experiment whether using delta-time or not (see LearnCocos2D's excellent comment on the cons of using it) works for your game. While multiplying by delta-time allows your object motion to more accurately take into account varying framerates, as LearnCocos2d pointed out, it might be wise to avoid using it in a real-time game where system interrupts (new mail, low battery, ads pop-out) can occur and subsequently cause the game simulation to jump forward in an attempt to make up.
So if you are dropping the dt, remember to tweak (scale down) your GRAVITY value accordingly to retain the right feel, since this value is no longer multiplied by the value of delta-time (which is ~ 1/60).
Aditional Tip: To apply an impulse to move the sprite (say via a swipe), you can affect the velocities directly by changing the values of velocity_x (if you have this) and velocity_y.
I have used this approach in my games, and it works very well. hope it helps.
This isn't trivial matter, you should try to see other posts. I'm sure other poeple already had this issue. Try to look at :
How to simulate a gravity for one sprite in cocos2d without a physics engine?
Cocos2D Gravity?
Or try our good friend google :
http://www.gamedev.net/page/resources/ -> got to Math and Physics and then A Verlet based approach for 2D game physics
http://www.rodedev.com/tutorials/gamephysics/
In any case here are some tips :
Step 1, calculate the effective direction vectors
Step 2, calculate velocity
Step 3, project this velocity onto the two effective directions.
Step 4, generate an equal and opposite force for the two direction and call this the “response force”.