Different x and y speed (acceleration) in cocos2d? - ios

I want to create a visible object with a trajectory using standard actions (CCMoveBy and e.t.c) which is similar to:
x = sin(y)
My code:
CCMoveBy *moveAction1 = [CCMoveBy actionWithDuration:1.5 position:ccp(300, 0)];
CCEaseInOut *easeInOutAction1 = [CCEaseInOut actionWithAction:moveAction1 rate:2];
CCMoveBy *moveAction2 = [CCMoveBy actionWithDuration:1.5 position:ccp(-300, 0)];
CCEaseInOut *easeInOutAction2 = [CCEaseInOut actionWithAction:moveAction2 rate:2];
CCMoveBy *moveAction3 = [CCMoveBy actionWithDuration:1.5 position:ccp(0, -32)];
CCSpawn *moveActionRight = [CCSpawn actionOne:easeInOutAction1 two:moveAction3];
CCSpawn *moveActionLeft = [CCSpawn actionOne:easeInOutAction2 two:moveAction3];
CCSequence *sequenceOfActions = [CCSequence actionOne:moveActionRight two:moveActionLeft];
CCRepeatForever *finalMoveAction = [CCRepeatForever actionWithAction:sequenceOfActions];
[enemy runAction:finalMoveAction];
This code shows move down only. The problem is that object has a different x and y accelerations and I don't know how to combine them
UPDATED
- (void)tick:(ccTime)dt
{
CGPoint pos = self.position;
pos.y -= 50 * dt;
if (pos.y < activationDistance) {
pos.x = 240 + sin(angle) * 140;
angle += dt * 360 * 0.007;
if (angle >= 360) {
angle = ((int)angle) % 360;
}
}
self.position = pos;
}
It is my current solution. I can increase activationDistance to adjust the object trajectory. But I want to setup an initial value of the angle variable.
I use numbers instead of variables because they are used inside this function only.
SOLVED
To change the initial angle:
angle = point.x < 240 ? -asin((240 - point.x) / 140) : asin((point.x - 240) / 140);
the main problem was my tiled map has its own coordinates and cover 320x320 part of the screen only

I think it will be easier for you to just do it in your frame update method (the one I assume you schedule for updating your objects. So why not just do :
- (void)tick:(ccTime)dt {
CGPoint pos = myObject.position;
pos.x = <desired x> + sin(angle);
pos.y = pos.y - y_acceleration * dt;
angle += dt * 360 * x_acceleration;
if (angle >= 360)
angle = ((int)angle) % 360;
myObject.position = pos;
}
And you can apply the same for the y axis of the object

Related

Calculating the angle to a location

I have an image of an arrow that behaves like a compass to a specific location. Sometimes it works, and other times it's mirrored. So if I was facing east and the location is directly east of me, it should point up, but sometimes it points down.
#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)heading
{
// update direction of arrow
CGFloat degrees = [self p_calculateAngleBetween:_myLocation
and:_otherLocation];
CGFloat rads = (degrees - heading.trueHeading) * M_PI / 180;
CGAffineTransform tr = CGAffineTransformIdentity;
tr = CGAffineTransformConcat(tr, CGAffineTransformMakeRotation(rads) );
[_directionArrowView setTransform:tr];
}
-(CGFloat) p_calculateAngleBetween:(CLLocationCoordinate2D)coords0 and:(CLLocationCoordinate2D)coords1 {
double x = 0, y = 0 , deg = 0, deltaLon = 0;
deltaLon = coords1.longitude - coords0.longitude;
y = sin(deltaLon) * cos(coords1.latitude);
x = cos(coords0.latitude) * sin(coords1.latitude) - sin(coords0.latitude) * cos(coords1.latitude) * cos(deltaLon);
deg = RADIANS_TO_DEGREES(atan2(y, x));
if(deg < 0)
{
deg = -deg;
}
else
{
deg = 360 - deg;
}
return deg;
}
Is this the correct way to calculate my angle with another location? Or am I missing a step? Being the arrow points directly in the opposite direction sometimes, my assumption is it's an issue with my math.
To calculate radians from x & y:
double r = atan(y/x);
if (x<0)
r = M_PI + r;
else if (x>0 && y<0)
r = 2 * M_PI + r;
There is not issue of dividing by 0 when X is zero because the atan function handles this correctly:
If the argument is positive infinity (negative infinity), +pi/2 (-pi/2) is returned.

Triangle Gradient With Core Graphics

I'm trying to draw a triangle like this one in a view (one UIView, one NSView):
My first thought was CoreGraphics, but I couldn't find any information that would help me draw a gradient between three points of arbitrary color.
Any help?
Thanks!
Actually it's pretty simple with CoreGraphics. Below you can find code that renders given triangle, but first let's think how we can solve this problem.
Theory
Imagine equilateral triangle with side length w. All three angles are equal to 60 degrees:
Each angle will represent component of a pixel: red, green or blue.
Lets analyze intensity of a green component in a pixel near top angle:
The more closer pixel to the angle, the more component intense it'll have and vice versa. Here we can decompose our main goal to smaller ones:
Draw triangle pixel by pixel.
For each pixel calculate value for each component based on distance from corresponding angle.
To solve first task we will use CoreGraphics bitmap context. It will have four components per pixel each 8 bits long. This means that component value may vary from 0 to 255. Fourth component is alpha channel and will be always equal to max value - 255. Here is example of how values will be interpolated for the top angle:
Now we need to think how we can calculate value for component.
First, let's define main color for each angle:
Now let's choose an arbitrary point A with coordinates (x,y) on the triangle:
Next, we draw a line from an angle associated with red component and it passes through the A till it intersects with opposite side of a triangle:
If we could find d and c their quotient will equal to normalized value of component, so value can be calculated easily:
(source: sciweavers.org)
Formula for finding distance between two points is simple:
(source: sciweavers.org)
We can easily find distance for d, but not for c, because we don't have coordinates of intersection. Actually it's not that hard. We just need to build line equations for line that passes through A and line that describes opposite side of a triangle and find their intersection:
Having intersection point we can apply distance formula to find c and finally calculate component value for current point.
Same flow applies for another components.
Code
Here is the code that implements concepts above:
+ (UIImage *)triangleWithSideLength:(CGFloat)sideLength {
return [self triangleWithSideLength:sideLength scale:[UIScreen mainScreen].scale];
}
+ (UIImage *)triangleWithSideLength:(CGFloat)sideLength
scale:(CGFloat)scale {
UIImage *image = nil;
CGSize size = CGSizeApplyAffineTransform((CGSize){sideLength, sideLength * sin(M_PI / 3)}, CGAffineTransformMakeScale(scale, scale));
size_t const numberOfComponents = 4;
size_t width = ceilf(size.width);
size_t height = ceilf(size.height);
size_t realBytesPerRow = width * numberOfComponents;
size_t alignedBytesPerRow = (realBytesPerRow + 0xFF) & ~0xFF;
size_t alignedPixelsPerRow = alignedBytesPerRow / numberOfComponents;
CGContextRef ctx = CGBitmapContextCreate(NULL,
width,
height,
8,
alignedBytesPerRow,
CGColorSpaceCreateDeviceRGB(),
(CGBitmapInfo)kCGImageAlphaPremultipliedLast);
char *data = CGBitmapContextGetData(ctx);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int edge = ceilf((height - i) / sqrt(3));
if (j < edge || j > width - edge) {
continue;
}
CGFloat redNormalized = 0;
CGFloat greenNormalized = 0;
CGFloat blueNormalized = 0;
CGPoint currentTrianglePoint = (CGPoint){j / scale, (height - i) / scale};
[self calculateCurrentValuesAtGiventPoint:currentTrianglePoint
sideLength:sideLength
sideOne:&redNormalized
sideTwo:&greenNormalized
sideThree:&blueNormalized];
int32_t red = redNormalized * 0xFF;
int32_t green = greenNormalized * 0xFF;
int32_t blue = blueNormalized * 0xFF;
char *pixel = data + (j + i * alignedPixelsPerRow) * numberOfComponents;
*pixel = red;
*(pixel + 1) = green;
*(pixel + 2) = blue;
*(pixel + 3) = 0xFF;
}
}
CGImageRef cgImage = CGBitmapContextCreateImage(ctx);
image = [[UIImage alloc] initWithCGImage:cgImage];
CGContextRelease(ctx);
CGImageRelease(cgImage);
return image;
}
+ (void)calculateCurrentValuesAtGiventPoint:(CGPoint)point
sideLength:(CGFloat)length
sideOne:(out CGFloat *)sideOne
sideTwo:(out CGFloat *)sideTwo
sideThree:(out CGFloat *)sideThree {
CGFloat height = sin(M_PI / 3) * length;
if (sideOne != NULL) {
// Side one is at 0, 0
CGFloat currentDistance = sqrt(point.x * point.x + point.y * point.y);
if (currentDistance != 0) {
CGFloat a = point.y / point.x;
CGFloat b = 0;
CGFloat c = -height / (length / 2);
CGFloat d = 2 * height;
CGPoint intersection = (CGPoint){(d - b) / (a - c), (a * d - c * b) / (a - c)};
CGFloat currentH = sqrt(intersection.x * intersection.x + intersection.y * intersection.y);
*sideOne = 1 - currentDistance / currentH;
} else {
*sideOne = 1;
}
}
if (sideTwo != NULL) {
// Side two is at w, 0
CGFloat currentDistance = sqrt(pow((point.x - length), 2) + point.y * point.y);
if (currentDistance != 0) {
CGFloat a = point.y / (point.x - length);
CGFloat b = height / (length / 2);
CGFloat c = a * -point.x + point.y;
CGFloat d = b * -length / 2 + height;
CGPoint intersection = (CGPoint){(d - c) / (a - b), (a * d - b * c) / (a - b)};
CGFloat currentH = sqrt(pow(length - intersection.x, 2) + intersection.y * intersection.y);
*sideTwo = 1 - currentDistance / currentH;
} else {
*sideTwo = 1;
}
}
if (sideThree != NULL) {
// Side three is at w / 2, w * sin60 degrees
CGFloat currentDistance = sqrt(pow((point.x - length / 2), 2) + pow(point.y - height, 2));
if (currentDistance != 0) {
float dy = point.y - height;
float dx = (point.x - length / 2);
if (fabs(dx) > FLT_EPSILON) {
CGFloat a = dy / dx;
CGFloat b = 0;
CGFloat c = a * -point.x + point.y;
CGFloat d = 0;
CGPoint intersection = (CGPoint){(d - c) / (a - b), (a * d - b * c) / (a - b)};
CGFloat currentH = sqrt(pow(length / 2 - intersection.x, 2) + pow(height - intersection.y, 2));
*sideThree = 1 - currentDistance / currentH;
} else {
*sideThree = 1 - currentDistance / height;
}
} else {
*sideThree = 1;
}
}
}
Here is a triangle image produced by this code:

CGRectIntersectsRect for multiple CGRect

I have 8 UIImageView, which have to be placed randomly. I generate a random x,y pos for each imageView, then I need to check if any of the imageViews are intersecting. If they are intersecting, it goes back to calculating random x,y pos again(do..while loop). Now the only method I know of is CGRectIntersectsRect, which can only compare 2 CGRect. Is there a way I can check if all those imageViews intersect at once (inside the while condition)?
Here's what I already worked out for 3 images-
do {
xpos1 = 60 + arc4random() % (960 - 60 + 1);
ypos1 = 147 + arc4random() % (577 - 147 + 1);
xpos2 = 60 + arc4random() % (960 - 60 + 1);
ypos2 = 147 + arc4random() % (577 - 147 + 1);
xpos3 = 60 + arc4random() % (960 - 60 + 1);
ypos3 = 147 + arc4random() % (577 - 147 + 1);
} while (CGRectIntersectsRect(CGRectMake(xpos1, ypos1,120, 120), CGRectMake(xpos2, ypos2,120, 120)) || CGRectIntersectsRect(CGRectMake(xpos2, ypos2,120,120), CGRectMake(xpos3, ypos3, 120, 120)) || CGRectIntersectsRect(CGRectMake(xpos1, ypos1,120,120), CGRectMake(xpos3, ypos3, 120, 120)) );
image1.center=CGPointMake(xpos1, ypos1);
image2.center=CGPointMake(xpos2, ypos2);
image3.center=CGPointMake(xpos3, ypos3);
A simple algorithm would be to start with one rectangle, and then iteratively find new rectangles
that do not intersect with any of the previous ones:
int numRects = 8;
CGFloat xmin = 60, xmax = 960, ymin = 147, ymax = 577;
CGFloat width = 120, height = 120;
CGRect rects[numRects];
for (int i = 0; i < numRects; i++) {
bool intersects;
do {
// Create random rect:
CGFloat x = xmin + arc4random_uniform(xmax - xmin + 1);
CGFloat y = ymin + arc4random_uniform(ymax - ymin + 1);
rects[i] = CGRectMake(x, y, width, height);
// Check if it intersects with one of the previous rects:
intersects = false;
for (int j = 0; j < i; j++) {
if (CGRectIntersectsRect(rects[i], rects[j])) {
intersects = true;
break;
}
}
// repeat until new rect does not intersect with previous rects:
} while (intersects);
}
This should answer your question ("how to check for intersection with multiple rectangles"),
but note that this method is not perfect. If the rectangles would fill "much" of the
available space and the first rectangles are placed "badly" then the algorithm might not
terminate because it cannot find an admissible rectangle at some point.
I don't think that can happen with the dimensions used in your case, but you might keep that
in mind. A possible solution could be to count the number of tries that were made, and if
it takes too long than start over from the beginning.
Also, if you have to create many rectangles then the inner loop (that checks for the
intersection) can be improved by sorting the rectangles, so that less comparisons have to
be made.
Say you have generated point
CGFloat x = (CGFloat) (arc4random() % (int) self.view.bounds.size.width);
CGFloat y = (CGFloat) (arc4random() % (int) self.view.bounds.size.height);
CGPoint point=CGPointMake(x, y);
while ([self checkPointExist:point]) {
x = (CGFloat) (arc4random() % (int) self.view.bounds.size.width);
y = (CGFloat) (arc4random() % (int) self.view.bounds.size.height);
point=CGPointMake(x, y);
}
-(BOOL)checkPointExist:(CGPoint)point{
for(UIView *aView in [self.view subviews])
{
if(CGRectContainsPoint(aView.frame, point))
{
return TRUE;// There is already imageview. generate another point
}
}
return FALSE;
}

converting isometric tile map coordinates to screen coordinates

I'm trying to convert isometric tile coordinates to screen coordinates.
I seem to have problem especially with the Y coordinates, looks like the X part works just fine. here is what I got so far.
// calculate screen coordinates from tile coordinates
- (CGPoint)positionForTileCoord:(CGPoint)pos {
float halfMapWidth = _tileMap.mapSize.width*0.5;
float mapHeight = _tileMap.mapSize.height;
float tileWidth = _tileMap.tileSize.width;
float tileHeight = _tileMap.tileSize.height;
int x = halfMapWidth*tileWidth + tileWidth*pos.x*0.5-tileWidth*pos.y*0.5;
int y = ............
return ccp(x, y);
my player is added as a child to the Tile map itself and the map is added to the layer at screenSize.x/2, scrrensize.y/2 with an anchor point of 0.5
I have done the same thing successfully with an orthogonal map but seem to struggle with the isometric one.
Thank you
really its look like this:
// calculate screen coordinates from tile coordinates
- (CGPoint)positionForTileCoord:(CGPoint)pos {
float halfMapWidth = _tileMap.mapSize.width*0.5;
float mapHeight = _tileMap.mapSize.height;
float tileWidth = _tileMap.tileSize.width;
float tileHeight = _tileMap.tileSize.height;
int x = halfMapWidth*tileWidth + tileWidth*pos.x*0.5-tileWidth*pos.y*0.5;
int y = (pos.y + (mapHeight * tileWidth/2) - (tileHeight/2)) - ((pos.y + pos.x) * tileHeight/2) + tileHeight;
return ccp(x, y);
}
// calculating the tile coordinates from screen location
-(CGPoint) tilePosFromLocation:(CGPoint)location
{
CGPoint pos = location;
float halfMapWidth = _tileMap.mapSize.width*0.5;
float mapHeight = _tileMap.mapSize.height;
float tileWidth = _tileMap.tileSize.width;
float tileHeight = _tileMap.tileSize.height;
CGPoint tilePosDiv = CGPointMake(pos.x/tileWidth, pos.y/tileHeight);
float invereseTileY = mapHeight - tilePosDiv.y;
// Cast int to make sure that result is in whole numbers
float posX = (int)(invereseTileY + tilePosDiv.x - halfMapWidth);
float posY = (int)(invereseTileY - tilePosDiv.x + halfMapWidth);
return CGPointMake(posX, posY);
}
int y = (pos.y + (mapHeight * tileWidth/2) - (tileHeight/2)) - ((pos.y + pos.x) * tileHeight/2) + tileHeight;

touch object GLKIT or OpenGL any functions?

I am looking for a description to touch my OpenGL object or get an Event if I touch it.
Have the GLKit or OpenGL ES some functions to use?
Or I have to calculate the position of my Object and have to compare it with the coordination ob my Touch?
There is no built in one, but here is a ported version of the gluProject function that will put a point from your object in screen coordinates, so you can see if your touch is near that point:
GLKVector3 gluProject(GLKVector3 position,
GLKMatrix4 projMatrix,
GLKMatrix4 modelMatrix,
CGRect viewport
)
{
GLKVector4 in;
GLKVector4 out;
in = GLKVector4Make(position.x, position.y, position.z, 1.0);
out = GLKMatrix4MultiplyVector4(modelMatrix, in);
in = GLKMatrix4MultiplyVector4(projMatrix, out);
if (in.w == 0.0) NSLog(#"W = 0 in project function\n");
in.x /= in.w;
in.y /= in.w;
in.z /= in.w;
/* Map x, y and z to range 0-1 */
in.x = in.x * 0.5 + 0.5;
in.y = in.y * 0.5 + 0.5;
in.z = in.z * 0.5 + 0.5;
/* Map x,y to viewport */
in.x = in.x * (viewport.size.width) + viewport.origin.x;
in.y = in.y * (viewport.size.height) + viewport.origin.y;
return GLKVector3Make(in.x, in.y, in.z);
}
- (GLKVector2) getScreenCoordOfPoint {
GLKVector3 out = gluProject(self.point, modelMatrix, projMatrix, view.frame);
GLKVector2 point = GLKVector2Make(out.x, view.frame.size.height - out.y);
return point;
}

Resources