I am working on a SpriteKit game in which a sprite is thrown from the upper right portion of the screen and lands in about the middle. In order to propel the sprite, I am using the applyForce method. Currently, I am explicitly setting the values of the dx and dy of the vector.
Frequently, the sprite lands where I expect it to based on set dx and dy values. However, sometimes the sprite travels farther than intended.
Essentially the issue is that the sprite travels inconsistent distances when applied the same force vector. I am wondering if there is any way to counter this issue and maintain consistent results with the same applied vector.
At the moment, my code loads in a 3D model, creates a node using that model, and displays the node in the scene. Setting the scale/rotation (euler angles) of the node works fine. However, I'm trying to set the position of the node relative to the world origin, and I don't want the node to be attached to a plane.
I've tried setting node.position and node.worldPosition to no avail; although the position of the node changes, when the camera moves, the node doesn't stay static, but moves about with the camera. I'm new to using ARKit, so I'm probably doing something stupid, but I can't figure out what it is that I need to do, so any help would be much appreciated.
Edit:
The weird thing is that if I set the coordinates to say SCNVector3(0, 3, 0) it's fine, but if I go over a certain number of meters away it seems to fail. Is this expected
Firstly, poor world tracking can be caused by these common issues.
Poor ligthing. Causes low number of feature points available for tracking
Lack of texture Causes low number of feature points available for tracking
Fast Movement Causes blurry images which causes tracking to fail
However, what I believe is happening in your case (which is a little more tricky to debug)... is you are most likely placing the loaded model underneath the detected horizontal plane in the scene.
In other words, you may have positioned the SCNNode using a negative Y coordinate which places the node below the horizontal detected plane and causes the model to drift around as you change the cameraView
try setting the Y position of the node to either 0 or a small positive value like 0.1 metres
node.position = SCNVector3(0, 0, -1) // SceneKit/AR coordinates are in meters
sceneView.scene.rootNode.addChildNode(node)
z = -1 places the SCNNode 1 metre in front of your cameraView.
Note: I verified this issue myself using a playground I use for testing purposes.
I'm trying to perform a spring animation on a view which is released by the user's pan gesture and may have a non-zero velocity. I'm basically trying to recreate the animation of this WWDC video where they use UISpringTimingParameters(dampingRatio:initialVelocity:). However, the documentation seems to contradict itself:
velocity
The initial velocity and direction of the animation, specified as a unit vector.
[...]
For example, if the total animation distance is 200 points and the view’s initial velocity is 100 points per second, specify a vector with a magnitude of 0.5.
If 0.5 is an example value, then apparently it doesn't need to be a unit vector after all. And it's not possible to encode a velocity in a unit vector in the first place.
Not being able to rely on the documentation, I tried plugging in several different values, but nothing lead to even remotely satisfactory results.
How do I use this API?
Good question.
TL;DR: If you are trying to animate something to a position in 2D, you need to animated each coordinate separately, each with the respective x / y velocity.
If you combine them by taking the scalar projection of the velocity onto your offset, you get a weird artifact where assuming the context of flicking a view around the screen, where the target is the center of the screen, and you are flicking the view up the right side, since the animation is to return to center, and since the combined velocity is going away from the center, the animation can only assume that the subject is moving in a straight line away from the center, and it will jag out to the right, before animating back to the center.
https://github.com/chrisco314/SpringAnimationTest
Here is my setup:
SKScene with a node called world
to this world, I attach another node: vehicle
to this vehicle, I attach three nodes that make up the vehicle; a body and two wheels
the wheels are attached to the body via SKPhysicsJointPin specifying their anchors
Now, everything is fine until I zoom out of my world:
[_world runAction:[SKAction scaleTo:0.5 duration:0.75]];
My vehicle suddenly lifts off the wheels. It appears as if the same distances as in the not-zoomed-in-world are kept. All parts of the vehicle are properly scaled- except the distances to its parts.
Do I have to apply the zoom to my joints as well? Or do I need to reset the anchor of my joints?
Thanks for your help!
Physics don't scale. Changing a node's scale is a purely visual effect, it does not alter physics in any way.
Even if you manually update physics positions synchronized with a node's scale you'll find that you can't scale each body's shape without removing the previous body and replacing it with a corresponding body of the same shape, just scaled. During a scale action you would have to through away and create new bodies every frame, which will probably cause a serious framerate issue.
I'm implementing a 2D game with ships in space.
In order to do it, I'm using LÖVE, which wraps Box2D with Lua. But I believe that my question can be answered by anyone with a greater understanding of physics than myself - so pseudo code is accepted as a response.
My problem is that I don't know how to move my spaceships properly on a 2D physics-enabled world. More concretely:
A ship of mass m is located at an initial position {x, y}. It has an initial velocity vector of {vx, vy} (can be {0,0}).
The objective is a point in {xo,yo}. The ship has to reach the objective having a velocity of {vxo, vyo} (or near it), following the shortest trajectory.
There's a function called update(dt) that is called frequently (i.e. 30 times per second). On this function, the ship can modify its position and trajectory, by applying "impulses" to itself. The magnitude of the impulses is binary: you can either apply it in a given direction, or not to apply it at all). In code, it looks like this:
function Ship:update(dt)
m = self:getMass()
x,y = self:getPosition()
vx,vy = self:getLinearVelocity()
xo,yo = self:getTargetPosition()
vxo,vyo = self:getTargetVelocity()
thrust = self:getThrust()
if(???)
angle = ???
self:applyImpulse(math.sin(angle)*thrust, math.cos(angle)*thrust))
end
end
The first ??? is there to indicate that in some occasions (I guess) it would be better to "not to impulse" and leave the ship "drift". The second ??? part consists on how to calculate the impulse angle on a given dt.
We are in space, so we can ignore things like air friction.
Although it would be very nice, I'm not looking for someone to code this for me; I put the code there so my problem is clearly understood.
What I need is an strategy - a way of attacking this. I know some basic physics, but I'm no expert. For example, does this problem have a name? That sort of thing.
Thanks a lot.
EDIT: Beta provided a valid strategy for this and Judge kindly implemented it directly in LÖVE, in the comments.
EDIT2: After more googling I also found openSteer. It's on C++, but it does what I pretended. It will probably be helpful to anyone reaching this question.
It's called motion planning, and it's not trivial.
Here's a simple way to get a non-optimal trajectory:
Stop. Apply thrust opposite to the direction of velocity until velocity is zero.
Calculate the last leg, which will be the opposite of the first, a steady thrust from a standing start that gets the ship to x0 and v0. The starting point will be at a distance of |v0|^2/(2*thrust) from x0.
Get to that starting point (and then make the last leg). Getting from one standing point to another is easy: thrust toward it until you're halfway there, then thrust backward until you stop.
If you want a quick and dirty approach to an optimal trajectory, you could use an iterative approach: Start with the non-optimal approach, above; that's just a time sequence of thrust angles. Now try doing little variations of that sequence, keeping a population of sequences that get close to the goal. reject the worst, experiment with the best -- if you're feeling bold you could make this a genetic algorithm -- and with luck it will start to round the corners.
If you want the exact answer, use the calculus of variations. I'll take a crack at that, and if I succeed I'll post the answer here.
EDIT: Here's the exact solution to a simpler problem.
Suppose instead of a thrust that we can point in any direction, we have four fixed thrusters pointing in the {+X, +Y, -X, -Y} directions. At any given time we will firing at most one of the +/-X and at most one of the +/-Y (there's no point in firing +x and -X at the same time). So now the X and Y problems are independent (they aren't in the original problem because thrust must be shared between X and Y). We must now solve the 1-D problem -- and apply it twice.
It turns out the best trajectory involves thrusting in one direction, then the other, and not going back to the first one again. (Coasting is useful only if the other axis's solution will take longer than yours so you have time to kill.) Solve the velocity problem first: suppose (WLOG) that your target velocity is greater than your initial velocity. To reach the target velocity you will need a period of thrust (+) of duration
T = (Vf - Vi)/a
(I'm using Vf: final velocity, Vi: initial velocity, a: magnitude of thrust.)
We notice that if that's all we do, the location won't come out right. The actual final location will be
X = (Vi + Vf)T/2
So we have to add a correction of
D = Xf - X = Xf -(Vi+Vf)T/2
Now to make the location come out right, we add a period of thrust in one direction before that, and an equal period in the opposite direction after. This will leave the final velocity undisturbed, but give us some displacement. If the duration of this first period (and the third) is t, then the displacement we get from it is
d = +/-(at^2 + atT)
The +/- depends on whether we thrust + then -, or - then +. Suppose it's +.
We solve the quadratic:
t = (-aT + sqrt(a^2 T^2 + 4 a D))/2a
And we're done.
In the absence of additional info, we can assume there are 3 forces acting upon the spaceship and eventually dictating its trajectory:
"impulses" : [user/program-controlled] force.
The user (or program) appear to have full control over this, i.e. it controls the direction of the impulse and its thrust (probably within a 0-to-max range)
some external force: call it gravity, whatever...
Such force could be driven by several sources but we're just interested in the resulting combined force: at a given time and space this external force acts upon the ship with a given strengh and direction. The user/program has no control over these.
inertia: this is related to the ship's current velocity and direction. This force generally causes the ship to continue in its current direction at its current speed. There may be other [space-age] parameters controlling the inertia but generally, it is proportional to both velocity and to the ship's mass (Intuitively, it will be easier to bring a ship to a stop if its current velocity is smaller and/or if its mass is smaller)
Apparently the user/program only controls (within limits) the first force.
It is unclear, from the question, whether the problem at hand is:
[Problem A] to write a program which discovers the dynamics of the system (and/or adapts to changes these dynamics).
or..
[Problem B] to suggest a model -a formula- which can be used to compute the combined force eventually applied to the ship: the "weighed" sum of the user-controlled impulse and the other two system/physics-driven forces.
The latter question, Problem B, is more readily and succinctly explained, so let's suggest the following model:
Constant Parameters:
ExternalForceX = strength of the external force in the X direction
ExternalForceY = id. Y direction
MassOfShip = coeficient controlling
Variable Parameters:
ImpulseAngle = direction of impulse
ImpulseThrust = force of thrust
Formula:
Vx[new] = (cos(ImpulseAngle) * ImpulseThrust) + ExternalForceX + (MassOfShip * Vx[current])
Vy[new] = (sin(ImpulseAngle) * ImpulseThrust) + ExternalForceY + (MassOfShip * Vy[current])
Note that the above model assumes a constant External force (constant both in terms of its strength and direction); that is: akin to that of a gravitational field relatively distant from the area displayed (just like say the Earth gravity, considered within the span of a football field). If the scale of the displayed area is big relative to the source(s) of external forces, the middle term of the formulas above should then be modified to include: a trigonometric factor based on the angle between the center of the source and the current position and/or a [reversely] proportional factor based on the distance between the center of the source and the current position.
Similarly, the Ship's mass is assumed to remain constant, it could well be a variable, based say on the mass of the Ship when empty, to which the weight of fuel is removed/added as the game progresses.
Now... All the above assume that the dynamics of the system are controlled by the game designer: essentially choosing a set of values for the parameter mentioned and possibly adding a bit of complexity in the math of the formula (and also ensuring proper scaling to generally "keep" the ship within the display area).
What if instead, the system dynamics were readily programmed into the game (and assumed to be hidden/random), and the task at hand is to write a program which will progressively decide the direction and thrust value of the impulses to drive the ship to its targeted destination, in a way that its velocity at the target be as close as possible to getTargetVelocity()? This is the "Problem A".
This type of problem can be tackled with a PID Controller. In a nuthell, such a controller "decides" which amount of action (in this game's case = which impulse angle and amount of thrust to apply), based on three, weighed, factors, loosely defined below:
how far-off we are the current values from "set point": this is the P=Proportional part of PID
how fast are we approaching the "set point": this is the D=Derivative part of PID
how long and how much have we been away from the "set point": this is the I=Intergral part of PID
A less sophisticated controller could for example only use the proportional factor. This would result in oscillating, sometimes with much amplitude on either side of the set point ("I'm X units away from where I'm supposed to be: let me yank the steering wheel and press on gas"). Such overshooting of the set point are tempered by the Derivative factor ("Yeah, I'm still not where I'm supposed to be but the progress I made since the last time I check is very big: better slow down a bit"). Finally the Integral part takes into account the fact that all things being equal with regards to the combined Proportional and Derivative part, a smaller or bigger action would be appropriate depending on whether we've been "off-track" for a long time or not and of much off track we've been all this time (eg. "Lately we've been tracking rather close to where we're supposed to be, no point in making rash moves")
We can discuss the details implementing PID controllers for the specific needs of the space ship game, if that is effectively what is required. The idea was to provide a flavor of what can be done.
To just get from the current position to the destination with an initial velocity, then apply thrust along the normalized difference between the shortest path and the current velocity. You don't actually need the angle.
-- shortest path minus initial velocity
dx,dy = x0 - x - vx, y0 - y - vy
-- normalize the direction vector
magnitude = sqrt(dx*dx + dy*dy)
dx,dy = dx/magnitude, dy/mangitude
-- apply the thrust in the direction we just calculated
self:applyImpulse(thrust*dx, thrust*dy)
Note that this does not take the target velocity into account because that gets extremely complicated.
I have a very small Lua module for handling 2D vectors in this paste bin. You are welcome to use it. The code above would reduce to:
d = destination - position - velocity
d:normalize()
d = d * thrust
self:applyImpulse(d.x, d.y)
Are you expelling fuel? Your mass will change with time if you are.
Thrust is a reactive force. It's the rate of change of mass, times the speed of the exhaust relative to the spaceship.
Do you have external forces? If you do, these need to enter into your impulse calculation.
Let's assume a magical thrust with no mass being expelled, and no external forces.
Impulse has units of momentum. It's the integral of a force over time.
First off, you'll need to figure out exactly what the API calls "thrust" and impulse. If you're feeding it a thrust multiplied by a scalar (number), then applyImpulse has to do something else to your input to be able to use it as an impulse, because the units don't match up.
Assuming your "thrust" is a force, then you multiply that thrust by the time interval (1/30 second) to get the impulse, and break out the components.
Don't know if I'm answering your question, but hopefully that helps you to understand the physics a bit.
It's easier to think about if you separate the ship's velocity into components, parallel and perpendicular to the target velocity vector.
Considering along the perpendicular axis, the ship wants to come in line with the target position as soon as possible, and then stay there.
Along the parallel axis, it should be accelerating in whatever direction will bring it close to the target velocity. (Obviously if that acceleration takes it away from the target point, you'll need to decide what to do. Fly past the point and then double-back?)
I would deal with the two of them separately, and probably perpendicular first. Once it's working, and if that doesn't prove nice enough, you can start to think about if there are ways to get the ship to fire intelligent angles between perpendicular and parallel.
(EDIT: also, I forgot to mention, this will take some adjustment to deal with the scenario where you are offset a lot in the perpendicular direction but not much in the parallel direction. The important lesson here is to take the components, which gives you useful numbers on which to base a decision.)
Your angle is the Inverse Tangent the Opposite/Adjacent
So angle = InvTan(VY/VX)
No sure what your are talking about concerning wanting to drift??