Sprite has a jigging effect because of tracking - iphone

I have a sprite that tracks and follows objects on the screen, moving towards them.
The method runs on a schedule and basically looks like this:
- (void) nextFrame:(ccTime)dt {
//calculate distance between the bubble and the fish
float dx = bubbleToChase.position.x - fish.position.x;
float dy = bubbleToChase.position.y - fish.position.y;
float d = sqrt(dx*dx + dy*dy);
float v = 400;
if (d > 190){
NSLog(#"moving the fish!");
fish.position = ccp( fish.position.x + dx/d * v *dt,
fish.position.y + dy/d * v *dt);
}
}
The code works pretty well, when the distance is greater than 190 the fish will swim towards it.
The issue is that the objects have physics, so they are sliding around the screen. This produces a jigging / staggering effect on the fish sprite, because the fish will stop once it reaches the bubble, but then jiggle and stop rapidly as the bubble drifts away as (d > 190) incrementally.
How can I get rid of this jigging effect? I'd like to just stop the fish from moving once it has reached the bubble's position. Or any alternative that smooths it out. Any help appreciated, thanks.

if (d > 190 && !fish.parked){
NSLog(#"moving the fish!");
fish.position = ccp( fish.position.x + dx/d * v *dt,
fish.position.y + dy/d * v *dt);
}else{
if( fish.parked ){
// what you want to do while parked
// just sit there, wander randomly,
// then unpark the fish...
if(unpark)
fish.parked=FALSE;
}else{
fish.parked=TRUE;
// set variables for parked state.
}
}

Related

Is there a better way to write this top down car mdoel

I Am writing a top down car drift game, where i want to make the car move in a circle and user controls the radius of the circle with the steering, basically straight steering is a straight line and turned left is a small circle to the left of the car which it will follow. as the car turns more (either side) i try to make the cars front turn more and more towards the centre, as if its drifting.
Am using unity and this is how i though i should design the model.
This is for a mobile game. so i have written a steering controller for the car, to control its left and right, the speed is constant.
There are two rigid bodies.
The front white coloured box and the big grey coloured box both are rigid bodies. connected with a hinge joint.
The front box on every frame rotate a certain amount of degrees on it own z axis and moves a little forward. Thus follows a circle shape. how much is rotates is determined my the steering.
I Can make both the bodies kinematic and make sure they follow a circle shape and move that way, but i also want appropriate behaviour during collisions, In the final plan there can be all kinds of collisions. So i made them kinematic and added velocities using add force methods. On it's own the front box is perfect, It rotates in circle as i change the steering the circle gets bigger everything is fine, But when i add the Other chassis box, the forces are all messed up. centrifugal forces, and the inertia messes everything.
Basically i need the car to drift is perfect circles and user should be able to control the radius of the circle. What is the best way to model this.
Here is the code for both the rigid bodies.
the front box code. This is just the fixed update method. Please ignore the controls related code. It'e unnecessary so i left it out.
{
//-------------------------
// I N I T.
//-------------------------
current_steering_angle = controls_i.ToSignedRotation(controls_i.getSteeringAngle());
current_steering_angle = (current_steering_angle < 0) ? (current_steering_angle + 90): current_steering_angle;
current_steering_angle -= 45;
//-------------------------
// S P E E D.
//-------------------------
current_speed = Utils.curve_map_linear(0, 45, min_speed, max_speed, Mathf.Abs(current_steering_angle), -1);
_rigid_body.AddRelativeForce(acceleration * Vector3.up);
velocity = transform.InverseTransformVector(_rigid_body.velocity);
if(velocity.y > current_speed){
velocity.y = current_speed;
}
// to prevent reverse movement due to centrifugal force.
velocity.x = 0;
//-------------------------
// R O T A T I O N.
//-------------------------
current_radius = Mathf.Sign(current_steering_angle) * Utils.exp_range_3(0, 45, min_radius, max_radius, Mathf.Abs(current_steering_angle), steering_tension, -1);
current_rot_rate = (velocity.y / (2 * Mathf.PI * current_radius)) * 360;
Vector3 angle = transform.localEulerAngles;
angle.z += (current_rot_rate * Time.fixedDeltaTime);
transform.localEulerAngles = angle;
//-------------------------
// A P P L Y.
//-------------------------
_rigid_body.velocity = transform.TransformVector(velocity);
}
The Utils.exp_linear and exp_range functions are just range to range mappers with some tension, to control the sensitivity of the steering on the controls.
Code for the chassis.
{
//-------------------------
// I N I T.
//-------------------------
current_steering_angle = controls_i.ToSignedRotation(controls_i.getSteeringAngle());
current_steering_angle = (current_steering_angle < 0) ? (current_steering_angle + 90): current_steering_angle;
current_steering_angle = current_steering_angle - 45;
current_steering_angle = ((float)((int)(current_steering_angle * Mathf.Pow(10, 5))))/Mathf.Pow(10,5);
//-------------------------
// R O T A T I O N.
//-------------------------
current_angle = front_transform.eulerAngles.z - _rigid_body.transform.eulerAngles.z;
current_angle = (Mathf.Abs(current_angle) > 180) ? ((Mathf.Abs(current_angle) - 360) * Mathf.Sign(current_angle)) : current_angle;
current_angle += Mathf.Sign(current_steering_angle) * Utils.curve_map_linear(0, 45, min_angle, max_angle, Mathf.Abs(current_steering_angle), 1);
_rigid_body.transform.RotateAround(front_transform.position, Vector3.forward, current_angle);
//-------------------------
// S P E E D.
//-------------------------
Vector3 velocity = _rigid_body.transform.InverseTransformVector(_rigid_body.velocity);
if (velocity.y < 0){
velocity.y = 0;
}
_rigid_body.velocity = _rigid_body.transform.TransformVector(velocity);
}
I would like to know how to actually implement something like this in unity. I am new to this unity stuff. I looked all over and there was a lot of stuff for 3d cars but not much on top down ones. Appreciate any kind of feedback.
Make it non kinematic, remove the rigidbody of the front tires and make the front tires a child of the chassis.
Handling position:
Make a method that looks at the car's current position, how much the player is turning, and returns the tangential velocity the car needs to go to drive in the appropriate circle:
Vector2 GetTangentialVelocity(...) { }
Then, find the difference between that velocity and the current velocity of the chassis:
Vector2 velDiff = GetTangentialVelocity(...) - chassis_rigidbody.velocity;
Then, apply that difference using AddForce with ForceType.VelocityChange:
chassis_rigidbody.AddForce(velDiff, ForceType.VelocityChange);
Handling rotation:
Move the center of mass forward. You can do this by making the rigidbody long and put the collider at the rear of the object, or by setting RigidBody.centerOfMass:
chassis_rigidbody.centerOfMass = Vector2.up * 0.5;
Make a function similar to GetTangentialVelocity that returns the desired angular velocity, find the difference from chassis_rigidbody.angularVelocity, then use AddTorque with ForceType.VelocityChange:
Vector2 angVelDiff = GetAngularVelocity(...) - chassis_rigidbody.angularVelocity;
chassis_rigidbody.AddTorque(angVelDiff , ForceType.VelocityChange);

make object move from 1 point to another at a custom speed

I made an app which there is an object that moves towards a moving point all the time - that is why I didn't use any animated function. The problem is that I made this function:
CGPoint center = self.im.center; // "i" is a CGPoint, im is an imageview.
if (!CGPointEqualToPoint(self.im.center, i))
{
a = (i.y-center.y)/(i.x-center.x);
//Y = a*X+b - this is a linear function in math
b = (center.y-(a*center.x));
if (i.y>center.y) {
self.im.center = CGPointMake(((center.y+1)-b)/a, center.y+1);
}
else
{
self.im.center = CGPointMake(((center.y-1)-b)/a, center.y-1);
}
}
The problem is that the closer the functions is becoming a straight horizontal line its faster because the change is mostly to the X axis which means that if I add 1 to Y the change to X is bigger which means it will move faster..
If there is another way to do this i will be glad to try it so if you know other ways tell me!
Managed to find a different solution
CGPoint center = self.im.center;//im = the image view
x = center.x;//starting point
y = center.y;//starting point
double distance = sqrtf(powf(i.x - x, 2) + powf(i.y - y, 2));// i = cgpoint (ending point)
float speedX = (2 * (i.x - x)) / distance;//(the 2 is the speed)
float speedY = (2 * (i.y - y)) / distance;//(the 2 is the speed)
self.im.center = CGPointMake(center.x+speedX, center.y+speedY);//im = the image view

Projectile Motion in Cocos2d iphone

I want to throw a ball that has a projectile motion. I have a monkey on centre of screen and onTouchBegin I am taking the starting point of the touch and onTouchEnded I am taking the ending points. From the starting and ending points I am taking the angle value between them. Like 30 degrees, 45 or 90 degree.
This is my code by which I have calculated angle of start to endpoint
float angleRadians = atan2(startTouchPoint.x - touchPoint.x, startTouchPoint.y - touchPoint.y);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleDegrees;
Now i am using Projectile motion formula to throw ball with angle i have calculated from above formula .
inside init method
gravity = 9.8; // metres per second square
X = 0;
Y = 0;
V0 = 50; // meters per second -- elevation
VX0 = V0 * cos(angle); // meters per second
VY0 = V0 * sin(angle); // meters per second
gameTime = 0;
and onTouchEnded i have called fire method which will throw ball .
-(void)fire:(ccTime) dt
{
CCLOG(#"Angle 1: %.2f",angle);
gameTime += dt*6;
// x = v0 * t * cos(angle)
X = (V0 * gameTime * cos(angle))/2+120;
// y = v0 * t * sin(angle) - 0.5 * g * t^2
Y = (V0 * gameTime * sin(angle) - 0.5 * gravity * pow(gameTime, 2))/2+255;
if (Y > 50)
{
sprite_webfire.position = ccp(X,Y);
flag = true;
}
else
{
//angleValue += 15;
angleValue = angle;
angle = [self DegreesToRadians:angleValue];
gravity = 9.8; // metres per second square
X = 0;
Y = 0;
V0 = 50; // meters per second -- elevation
VX0 = V0 * cos(angle); // meters per second
VY0 = V0 * sin(angle); // meters per second
gameTime = 0;
// [self pauseSchedulerAndActions];
}
if (Y < 50)
{
[self unschedule:#selector(fire:)];
}
NSLog(#"ball (%lf,%lf), dt = %lf angle value %d", X, Y, dt,angleValue);
}
this code is working . by this code i can throw ball in projectile motion but i cant throw it where i want to. i cant throw wrt to given angle from start to end point.
i can throw it like red mark but i want to throw it blue mark with swipe . but its not throwing like i am swiping screen.
I am not certain on what math you are using to do this, I find your documentation a bit confusing.
Generally, for project tile motion this is what you need to do:
Find out what the take off angle is relative to the horizontal. Then depending on whatever initial velocity you want the object to have, use that and you trig equations to put your initial velocities into rectangular components.
For example:
If initial velocity was 10, the initial velocity in the y direction would be 10sin(angle), and in the x direction it would be 10cos(angle).
Then in to update the position of the sprite you should use kinematics equations: http://www.physicsclassroom.com/class/1dkin/u1l6c.cfm
First update velocities:
Velocity in the Y direction: V = v(initial) + gravity*(Delta-time)
Velocity in the X direction is constant unless you want to factor in some sort of resistance to make things a lot more complicated.
then position y = oldPositionY + velocity(in Y direction)*(Delta-time) + 1/2(gravity)(delta-time)^2.
and position x = oldPositionX + Xvelocity*delta-time
I have done some projectile motion stuff, and I have found you need to make gravity a large constant, something around 500 to make it look life-like. Let me know if this is confusing or you don't know how to implement it.
I would suggest that you take a look at the following tutorial: http://www.raywenderlich.com/4756/how-to-make-a-catapult-shooting-game-with-cocos2d-and-box2d-part-1.
It shows you how to use a physics engine, so you don't need to do much of the math. All the 'bullets' in the tutorial are also moving with projectile motion.
I'll add a bit to what was already said (which was good). Firstly, you should not be wasting time computing any angles. Stick with vectors for your velocity. In other words, get the initial velocity vector from the touch start and end location, and that will be your (v0x, v0y). For example:
CGPoint initialVelocity = ccpSub(touchPoint, startTouchPoint);
float v0x = initialVelocity.x;
float v0y = initialVelocity.y;
If you wish to assign a different magnitude to the initial velocity vector, simply normalize it and then multiply it by a new magnitude.
CGPoint unitVelocity = ccpNormalize(initialVelocity);
float magnitude = 200; // or whatever you want it to be
CGPoint velocity = ccpMult(unitVelocity, magnitude);
Anyway, with this velocity set properly you can then use it in your position calculations as before, but without the added complexity of calculating the angles.
-(void) fire:(ccTime)dt
{
.
.
gameTime += dt;
// if x(t) = x0 + v0x*t, then dx = v0x*dt
x += v0x*dt;
// if y(t) = y0 + v0y*t - 0.5t^2, then dy = v0y*dt - g*t*dt
y += (v0y * dt - g*gameTime*dt);
.
.
}
Also you should not set v0 = 50. Calculate the velocity from the vector as I suggested.
Something important to consider is that you are calculating what the movement should be in a physical world based upon units of meters. The screen is operating in points, not meters, so you will probably have to apply a scaling factor to the new position (x,y) to get the look that you are going for.
Edit: my bad, I had to revisit my math in the position calculation. My differentials was a bit rusty.

How do I move forward in the direction I am pointing in a 3d world?

I am using Cocos3D. I have a camera (which acts as the first-person viewed player in a world with only a spinning "hello, world" and a spinning earth. I have made it possible for the camera to point in any direction, and I have got it to move, but how do I get the camera/player to move forward in the direction he is pointing? (He does not go up or down, i.e. his y position does not change).
I note this is quite an old question - hopefully this answer helps someone!
You need to get the rotation angle of your camera, convert that to radians and use trigonometry to get the new X-Z coordinates. Tell your camera to move to those coordinates and presto, the player has moved forward!
CC3Camera *cam = self.activeCamera;
CC3Rotator *rotator = cam.rotator;
CC3Vector ro = rotatoooor.rotation;
CC3Vector loc = cam.globalLocation;
// If the -90 is left off, you go left/right and not forward
float roA = rotator.rotationAngle-90;
// Bug in rotationAngle? Need this as 315 angle reports as 45
int roI = ro.y;
int diff = roA+90 - roI;
if (diff == 0 && roI == 45)
roA = 315-90;
double theta = roA * M_PI/180; // Convert to radians
/*
x = d cos a
z = d sin a
*/
double sinA = sin(theta);
double cosA = cos(theta);
double newX = distance*cosA + loc.x;
double newZ = distance*sinA + loc.z;
CC3Vector newTo = cc3v(newX, loc.y, newZ); // Pass this to your camera

Mouse movement angle in openFrameworks

I am currently in the process of creating a sort of drawing program in openFrameworks that needs to calculate the angle of mouse movement. The reason for this is that the program needs to be able to draw brush strokes similar to the way photoshop does it.
I've been able to get it to work in a very jaggy way. I've placed my code in the MouseDragged event in openFrameworks, but the calculated angle is extremely jaggy and not smooth in anyway. It needs to be smooth in order for the drawing part to look good.
void testApp::mouseMoved(int x, int y ){
dxX = x - oldX;
dxY = y - oldY;
movementAngle = (atan2(dxY, dxX) * 180.0 / PI);
double movementAngleRad;
movementAngleRad = movementAngle * TO_RADIANS;
if (movementAngle < 0) {
movementAngle += 360;
}
testString = "X: " + ofToString(dxX) + " ,";
testString += "Y: " + ofToString(dxY) + " ,";
testString += "movementAngle: " + ofToString(movementAngle);
oldX = x;
oldY = y;
}
I've tried different ways of optimizing the code to work smooth but alas without results.
If you sit with a brilliant idea on how this could be fixed or optimized, I will be very grateful.
I solved it to some degree by using an ofPolyline object.
The following code shows how it works.
void testApp::mouseMoved(int x, int y ){
float angleRad;
if (movement.size() > 4)
{ angleRad = atan2(movement[movement.size()-4].y - y, movement[movement.size()-4].x -x);}
movementAngle = (angleRad * 180 / PI) + 180;
movement.addVertex(x,y,0);
}
As seen in the code I'm using the point recorded 4 steps back to increase the smoothness of the angle. This works if the mouse is moved in stroke like movements. If the mouse is moved slow, jaggyness will still occur.