Throw ball using cocos2d but without any physic engine - iphone

I want to throw a ball with swipe speed but do not want to use any physic engine. so please can any one suggest me how i do this.
thanks

A simple yet effective approach without having to explicitly use any physics engine is to step the velocity and position of the ball sprite manually in your update loop, Euler-style.
In the typical case (with downward gravity), you will have non-constant velocity in the y-direction and constant velocity in the x-direction, hence the following code:
-(void) update: (ccTime) dt
{
// Step only the y-velocity
velocity_y += GRAVITY * dt;
// Step the position values and update the ball sprite position accordingly
ball.position.x += velocity_x * dt;
ball.position.y += velocity_y * dt;
}
Then when a swipe event is detected,
Capture the swipe velocity (you will have to compute the change in position of the finger touch in the current and last frame)
Multiply the velocity with a scaling factor if necessary.
Set *velocity_x* and *velocity_y* to these initial values.

I am using projectile motion formulas to do this, http://en.wikipedia.org/wiki/Projectile_motion, along with cocos actions. Here you have a possible approach:
First
Implement a CCActionInterval subclass that receives the projectile formula parameters and updates the projectile position. In this case, ProjectileAction. These are the key methods you need to over-ride:
-(void) startWithTarget:(id)target
{
self.initialPosition = [target position];
self.elapsedTime = 0;
[super startWithTarget:target];
}
-(void) update: (ccTime) tt
{
self.elapsedTime += tt;
float t = self.elapsedTime;
float theta = CC_DEGREES_TO_RADIANS(self.angle);
float v0 = self.velocity;
float g = self.gravitationalAcceleration;
double x = v0 * cos(theta) * t;
double y = v0 * sin(theta) * t - 0.5 * g * t * t ;
[self.target setPosition: ccp(self.initialPosition.x + (float)x, self.initialPosition.y + (float)y)];
}
Second
Use your swipe gesture to recognize the speed, that will translate to the ball's initial velocity in the equation above and to the theVelocity parameter bellow. I leave that part to you.
Third
Run the action. i.e.
ProjectileLaunch* action = [ProjectileLaunch actionWithDuration:10
angle:45
initialVelocity:theVelocity
g:9.8];
[sprite runAction:action];
I hope this helps you.
Regards.

Related

Math: How to spin a wheel by drag&drop (Canvas, 2D)?

I'm struggling with probably simple math to spin/rotate a wheel using drag&drop.
There is a Radial Layout in a Canvas (Unity UI) and it can already be rotated by setting a property called StartAngle that is in a range from 0-360. In this Radial there are items, so the StartAngle is for the first item and places all the child elements around the layout radius.
I want to implement drag & drop for the items so that you can drag a child around and the Radial will spin accordingly (infinitely).
Right now, I have this as a starting point:
public void OnDrag(PointerEventData eventData)
{
var delta = eventData.delta.x * Time.deltaTime;
var newAngle = radialLayout.StartAngle + delta;
if (newAngle >= 360)
newAngle = newAngle - 360;
else if (newAngle < 0)
newAngle = Mathf.Abs(360 - newAngle);
radialLayout.StartAngle = newAngle;
}
It kind of works but doesn't feel very smooth. This is for mobile/touch, so I want both the X and Y delta of the drag operation to be taken into account. Apparently, the y delta is not considered in my example and I have no idea how to incorporate this correctly. The user might do a linear drag & drop on either axis or he/she might also do like a circular drag movement.
So how can I map mouse movement to a rotation angle from 0-360 so that it feels good?
Edit: Thanks for the help, I did it like this now:
public void OnDrag(PointerEventData eventData)
{
// Note the "Head-Minus-Tale rule for Vector subtraction, see http://www.maths.usyd.edu.au/u/MOW/vectors/vectors-3/v-3-7.html
// vSourceToDestination = vDestination - vSource;
// First, we draw a vector from the center point of the radial to the point where we started dragging
var from = dragStartPoint - (Vector2)radialLayout.transform.position;
// Next, we draw a vector from the center point of the radial to the point we are currently dragging on
var to = eventData.position - (Vector2)radialLayout.transform.position;
// Now, we calculate the angle between these two:
var dragAngle = Vector2.SignedAngle(from, to);
// Lerping makes movement fast at the beginning slow at the end
var lerpedAngle = Mathf.Round(Mathf.LerpAngle(radialLayout.StartAngle, dragAngle, 0.5f));
radialLayout.StartAngle = lerpedAngle;
}
I don't know all of your code and types but I would have an idea. I can't test this right now and can not garant that it even works like this but I hope the idea gets clear.
I would probably rather use something like
// This is the vector from the center of the object to the mouse/touch position
// (in screen pixel space)
var touchDirection = eventData.position - Camera.main.WorldToScreenPoint(transform.position);
// angle between the Up (Y) axis and this touchDirection
// for the angle the length of the up vector doesn't matter so there is
// no need to convert it to pixel space
var targetAngle = Vector2.SignedAngle(Vector2.up, touchDirection);
// since the returned angle might be negative wrap it to get values 0-360
if(targetAngle < 0) targetAngle += 360;
// Now either simply use Lerp
// this would simply interpolate each frame to the middle of both values
// the result is a fast movement at the beginning and a very slow at the end
radialLayout.StartAngle = Mathf.Lerp(radialLayout.StartAngle, targetAngle, 0.5f);
// or maybe use a fixed speed like 30°/second
var difference = targetAngle - radialLayout.StartAngle;
radialLayout.StartAngle += Mathf.Sign(difference) * Mathf.Min(30f * Time.deltaTime, Mathf.Abs(difference));
Typed on smartphone but I hope the idea gets clear

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.

What is happening in the following code?

This code is used in the accelerometer
method.
It uses a CGPoint variable called playerVelocity.
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
//controls how quickly the velocity decelerates
float deceleration = 0.4f;
//determines how sensitive the accelerometer reacts
float sensitivity = 6.0f;
//how fast the velocity can be at most
float maxVelocity = 100;
playerVelocity.x = playerVelocity.x *deceleration + acceleration.x *sensitivity;
if (playerVelocity.x < -maxVelocity)
{
playerVelocity.x = -maxVelocity;
}
else if (playerVelocity.x > maxVelocity)
{
playerVelocity.x = maxVelocity;
}
}
Now I know that the playerVelocity variable is a CGPoint so I imagine it as a X,Y Graph.
I'm assuming that wherever the playerVelocity variable is resting (let's say 150,0), it first multiplies whatever coordinates by 0.4 whenever the accelerometer input is received (which is by the iPhone being tilted)and it then add's the accelerometer.x multiplied by 6.0 to the playerVelocity variable. Is this correct?
Later on in another method, this is added to my other objects position via
CGPoint pos = playerObject.position;
pos.x+= playerVelocity.x;
playerObject.position = pos;
What I'm confused about is what exactly is happening behind the scenes here. Is my assumption above correct?
When the playerVelocity is at 150,0 and is multiplied by 0.4, does the X coordinate of the playerVelocity variable gradually reduce, i.e. 150,0 , 145,0 , 130,0 etc.. ?
If I figure this out I'll then know how my playerObject is moving.
It looks like you have a constant deceleration (.4) that is opposing motion in whatever direction you are currently traveling subtracted from the acceleration as received via the accelerometer, which is multiplied by a constant. This value is then added to your current velocity. So you are essentially adding the difference of (acceleration from accelerometer - constant deceleration) to your current velocity for each calculation.

Box2d:apply velocity in a direction

I apply impulse in an object in box2d iPhone app and now want to increase its speed in particuler direction....i mean i need two thing
1.through the object in a direction
2.increase speed
plz help..
b2Vec2 force = b2Vec2(xAcceleration, yAcceleration);
force *= dt; // Use this if your game engine uses an explicit time step
b2Vec2 p = myObjectBody->GetWorldPoint(b2Vec2(0.0f, 0.0f));
body->ApplyForce(force, p);
By modifying xAcceleration and yAcceleration, you can make the object move with various speeds in different directions. (If you calculate angles, you might want to use force.Normalize(); and then multiply by a velocity.)
b2Vec2 vector = self.speed * b2Vec2(cos(angle), sin(angle));
self.yourbodyBody->SetLinearVelocity(vector);
[self schedule:#selector(increaseSpeed) interval:0.1];
- (void)increaseSpeed
{
self.speed += 0.01;
float angle = self.yourbodyBody->GetAngle();
b2Vec2 vector = self.speed * b2Vec2(cos(angle), sin(angle));
self.yourbodyBody->SetLinearVelocity(vector);
}

How to get colliding effect or bouncy when ball hits the track

** STILL NOT WORKING **
I am using below formula to move the ball circular, where accelX and accelY are the values from accelerometer, it is working fine.
But the problem in this code is mRadius (I fixed its value to 50), i need to change mRadius according to accelerometer values and also i need bouncing effect when it touches the track. Currently i am developing code by assuming only one ball is on the board.
float degrees = -atan2(accelX, accelY);
int x = cCentrePoint.x + mRadius * cos(degrees);
int y = cCentrePoint.y + mRadius * sin(degrees);
Here is the snap of the game i want to develop:
Balls Game http://iphront.com/wp-content/uploads/2009/12/bdece528ea334033.jpg.jpg
Updated: I am sending the updated code...
mRadius = 5;
mRange = NSMakeRange(0,60);
-(void) updateBall: (UIAccelerationValue) accelX
withY:(UIAccelerationValue)accelY
{
float degrees = -atan2(accelX, accelY);
int x = cCentrePoint.x + mRadius * cos(degrees);
int y = cCentrePoint.y + mRadius * sin(degrees);
//self.targetRect is rect of ball Object
self.targetRect = CGRectMake(newX, newY, 8, 9);
self.currentRect = self.targetRect;
static NSDate *lastDrawTime;
if(lastDrawTime!=nil)
{
NSTimeInterval secondsSinceLastDraw =
-([lastDrawTime timeIntervalSinceNow]);
ballXVelocity = ballXVelocity + (accelX * secondsSinceLastDraw)
* [self isTouchedTrack:mRadius andRange:mRange];
ballYVelocity = ballYVelocity + -(accelY * secondsSinceLastDraw)
* [self isTouchedTrack:mRadius andRange:mRange];
distXTravelled = distXTravelled + secondsSinceLastDraw
* ballXVelocity * 50;
distYTravelled = distYTravelled + secondsSinceLastDraw
* ballYVelocity * 50;
//Updating the ball rect
CGRect temp = self.targetRect;
temp.origin.x += distXTravelled;
temp.origin.y += distYTravelled;
//calculating new radius after updating ball position
int radius = (temp.origin.x - cCentrePoint.x) /
cos(degreesToRadians(degrees));
if( !NSLocationInRange(abs(radius),mRange))
{
//Colided with the tracks...Need a better logic here
ballXVelocity = -ballXVelocity;
}
else
{
// Need a better logic here
self.targetRect = temp;
}
}
[lastDrawTime release];
lastDrawTime = [ [NSDate alloc] init];
}
In the above code i have initialized mRadius and mRange(indicate track) to some constant for testing, i am not getting the moving of the ball as i expected( bouncing effect when Collided with track ) with respect to accelerometer. Help me to recognize where i went wrong or send some code snippets or links which does the similar job.
I am searching for better logic than my code, if you found share with me.
If I understand your code correctly, then the ball's position is directly controlled by the iPhone's orientation (tilt). So, tilting the iPhone to the right will place the ball at the right side of the track (3 o'clock). I believe you may want the balls acceleration (or, at least, its velocity) to be controlled. Then, you integrate the acceleration to velocity and the velocity to place, taking into account the constraints (the track walls).
The way it is set now, I don't see how you'd control more than one ball (as per the image you posted).
Then, for the bouncing effect: if you mean bouncing by the track's wall, then this will be a small modulation of the mRadius. If you mean bounce by other ball, then you'd modulate the angular position (by means of angular velocity) of the two balls to reflect the reaction.
EDIT: for integration of acceleration to velocity and then to position, for the purpose of this game, you can do with 1st order rectangular integration. Also, it will be more realistic to make the acceleration proportional to the tilt angle. Given the accel values from the iPhone itself, you can assign a 1:1 relation between the balls accel and the device reading. So, you'd like something like:
BallAccX = AccelX * Am_I_NOT_touching_a_wall_in_X_direction() * Ka
BallVelX = BallVelX + BallAccX * dT * Kv
BallPosX = BallPosX + BallVelX * dT * Kp
Note: the above formulae for velocity and position are 1st order approximation but should be sufficient for the purpose of this game.
Ka, Kv, Kp are some proportion coefficients. Choose them to make the relation between the sensed acceleration and the ball movement as you like. dT is the time difference between updates of the state of the ball. The function Am_I_NOT_touching_a_wall_in_X_direction() returns a 1 if the ball is free to move horizontally (in the direction of the tilt) and 0 otherwise.
Calculations for Y movement is symmetrical.
After trying alot I thought it is not easy to produce real time effect without using any physics engine. So its better to use BOX2d or Chipmunks or any other physics engines.