If with CGPointEqualToPoint do not work - ios

Im trying to figure out why this function do not execute theGameEnd function, when ball position is exactly the same as block position and when anchorpoints are the same.
if (CGPointEqualToPoint(ball.position,block.position)) {
if (CGPointEqualToPoint(ball.anchorPoint,monster1.anchorPoint)) {
[self theGameEnd];
}
}

The implementation of CGPointEqualToPoint is
CG_INLINE bool __CGPointEqualToPoint(CGPoint point1, CGPoint point2)
{
return point1.x == point2.x && point1.y == point2.y;
}
... so coordinates have to be absolutely equal to return true.
This is not always the case with CGFloat types, even if pixels seem to be aligned. There might be tiny errors resulting from the way you calculate them in your animation or game simulation code.
You could try to round the values before comparing them or allow for a small deviation.

Related

Comparing two values and returning the greatest of the two

I have two CGPoints that are the locations of two corners of a frame's rectangle.
I need to give separate instructions to them — one set of instructions for the one on top (on a vertical plane), and another set for the bottom one.
How would I go about comparing them and then giving them separate instructions?
If you have two CGPoints, if one is above the other, then it has a lower y value than the other.
For example: take two points:
CGPoint point1 = CGPointMake(100.0, 120.0);
CGPoint point2 = CGPointMake(100.0, 80.0);
You could write a method:
- (NSComparisonResult)compareYValueOfPoint:(CGPoint)point1 toPoint:(CGPoint)point2
{
CGFloat y1 = point1.y;
CGFloat y2 = point2.y;
if (y1 == y2) {
return NSOrderedSame;
} else if (y1 < y2) {
return NSOrderedAscending;
} else {
return NSOrderedDescending;
}
}
and call it with:
NSComparisonResult result = [self compareYValueOfPoint:point1 toPoint:point2];
And depending on the result, use the relevant point for further actions.
A CGPoint is a composite value (struct) containing two fields, x & y.
If you have two arbitrary points then one is "above" the other if its y-coordinate is greater than the other's y-coord. One is to the right of the other if its x-coordinate is greater.
CPPoint one, two;
if (one.y > two.y) { // one is above two }
if (two.x > one.x) { // two is to the right of one }
use ternary operators to initialise new variables into a known order...
CGPoint upperPoint = ((one.y < two.y) ? one : two);
CGPoint lowerPoint = ((one.y < two.y) ? two : one);
or maybe use fMax / fMin type macros...
CGFloat lesserYvalue = ((CGFloat) fMinf(one.y , two.y) );
CGFloat greaterYvalue = ((CGFloat) fMaxf(one.y , two.y) );

Moving and rotating a sprite with Accelerometer in SpriteKit

I'm trying to make my first game using Spritekit, so i have a sprite that i need to move around using my accelerometer. Well, no problem doing that; movement are really smooth and responsive, the problem is that when i try to rotate my sprite in order to get it facing its own movement often i got it "shaking" like he has parkinson. (:D)
i did realize that this happens when accelerometer data are too close to 0 on one of x, y axes.
So the question: Is there a fix for my pet parkinson?? :D
Here is some code:
-(void) update:(NSTimeInterval)currentTime{
static CGPoint oldVelocity;
//static CGFloat oldAngle;
if(_lastUpdatedTime) {
_dt = currentTime - _lastUpdatedTime;
} else {
_dt = 0;
}
_lastUpdatedTime = currentTime;
CGFloat updatedAccelX = self.motionManager.accelerometerData.acceleration.y;
CGFloat updatedAccelY = -self.motionManager.accelerometerData.acceleration.x+sinf(M_PI/4.0);
CGFloat angle = vectorAngle(CGPointMake(updatedAccelX, updatedAccelY));
_velocity = cartesianFromPolarCoordinate(MAX_MOVE_PER_SEC, angle);
if(oldVelocity.x != _velocity.x || oldVelocity.y != _velocity.y){
_sprite.physicsBody.velocity = CGVectorMake(0, 0);
[_sprite.physicsBody applyImpulse:CGVectorMake(_velocity.x*_sprite.physicsBody.mass, _velocity.y*_sprite.physicsBody.mass)];
_sprite.zRotation = vectorAngle(_velocity);
oldVelocity = _velocity;
}
}
static inline CGFloat vectorAngle(CGPoint v){
return atan2f(v.y, v.x);
}
i did try to launch the update of the _velocity vector only when updatedAccelX or updatedAccelY are, in absolute value >= of some values, but the result was that i got the movement not smooth, when changing direction if the value is between 0.1 and 0.2, and the problem wasn't disappearing when the value was under 0.1.
i would like to maintain direction responsive, but i also would like to fix this "shake" of the sprite rotation.
I'm sorry for my bad english, and thanks in advance for any advice.
You can try a low pass filter (cf. to isolate effect of gravity) or high pass filter (to isolate effects of user acceleration).
#define filteringFactor 0.1
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
//low pass
accelerX = (acceleration.x * filteringFactor) + (accelerX * (1.0 - filteringFactor));
//idem … accelerY
//idem … accelerZ
//or high pass
accelerX = acceleration.x - ( (acceleration.x * filteringFactor) + (accelerX * (1.0 - filteringFactor)) );
//idem … accelerY
//idem … accelerZ
}

How to simulate Gravity in z-axis in a 2D game with Sprite Kit

I'm writing a 2D ball game with sprite kit on iOS 7 and currently struggling on one physic simulation.
To explain the expected behavior: if a ball is dropped into a tea cup, it will circle around, loosing speed and finally stand still in the center of the cup.
I've tried to archive this with gravity, but gravity in sprite kit only applies to vertical X and Y axis, not Z-axis. I also tried to use level gravity by switching gravity values with small physic bodies on beginContact depending on the current ball position in the tea cup. But some contacts are dropped and the result is far away to look realistic.
I think I need to solve this in the update: method, but I have no idea which way to go.
Any advice greatly welcome and I need to mention that I'm not an expert on math, please explain your path to go. :-)
Since there's no built-in support for this kind of behavior in SpriteKit, rather than trying to hack existing functions to get what you want, you're probably better off integrating some published 2D physics formulas in your x,y 2D world. I would think that something like simulating magnetic or a homing behavior might be right for this.
A simple example would be something like (in the scene's -update: method):
CGFloat strength = 0.5; //(some scaling value)
CGPoint ballLocation = ball.position;
CGPoint cupLocation = cup.position;
[ball.physicsBody applyForce:CGVectorMake((cupLocation.x - ballLocation.x) * strength,
(cupLocation.y - ballLocation.y) * strength)];
following Joshd great idea, I have created an NSArray with like explained in my comment above. Hope this snippets does help some others...
The result could be found on youtube: http://youtu.be/Uephg94UH30
Sorry for the bad Airplay frame rate, it runs perfectly smooth on my iPad
The -update: functions does the work but only triggered if _meditationIsActive. This bool is set in -didBeginContact: when any ball gets in contact with a hole.
if (_lastCheck > 0.005)
{
if (_meditationIsActive)
{
CGFloat strength = 0.1; //(some scaling value)
CGPoint ballLocation;
CGPoint holeLocation;
for (MeditationHole * holeObj in _meditationHoles)
{
if (holeObj.connectedMeditationBall != nil)
{
ballLocation = holeObj.connectedMeditationBall.position;
holeLocation = holeObj.position;
[holeObj.connectedMeditationBall.physicsBody applyForce:CGVectorMake(
(holeLocation.x - ballLocation.x) * strength, (holeLocation.y - ballLocation.y) * strength)];
}
}
_meditationIsActive = [self doesMeditationApplies];
}
_lastCheck = 0;
}
At the end I'm checking if there is a valid ball out of the array in contact with a hole to avoid checking during every update. This is done with the following function where position check +/- 48 detects a ball close to a hole and +/-1 ball stands still
- (bool)doesMeditationApplies
{
bool isInArea = NO;
int perfectMatchCount = 0;
for (MeditationHole * holeObj in _meditationHoles)
{
if (holeObj)
{
if (holeObj.connectedMeditationBall != nil)
{
MeditationBall * ballObj = holeObj.connectedMeditationBall;
if ((ballObj.position.x >= holeObj.position.x - 48) &&
(ballObj.position.x <= holeObj.position.x + 48) &&
(ballObj.position.y >= holeObj.position.y - 48) &&
(ballObj.position.y <= holeObj.position.y + 48))
{
isInArea = YES;
}
else
{
holeObj.connectedMeditationBall = nil;
}
if ((ballObj.position.x >= holeObj.position.x - 1) &&
(ballObj.position.x <= holeObj.position.x + 1) &&
(ballObj.position.y >= holeObj.position.y - 1) &&
(ballObj.position.y <= holeObj.position.y + 1))
{
perfectMatchCount++;
isInArea = YES;
}
}
}
}
if (perfectMatchCount == _oxydStonesMax)
{
if (_sound)
{
self.pauseMusicPlaybackBlock(YES);
NSLog(#"PlaySound Meditation");
[OxydScene PlaySystemSound:#"Win2"];
}
isInArea = NO;
[self showPauseScreenWithWin:YES andPauseOnly:NO];
}
return isInArea;
}

ios - Spritekit - How to calculate the distance between two nodes?

I have two sknodes on the screen. What is the best way to calculate the distance ('as the crow flies' type of distance, I don't need a vector etc)?
I've had a google and search on here and can't find something that covers this (there aren't too many threads on stackoverflow about sprite kit)
Here's a function that will do it for you. This is from an Apple's Adventure example code:
CGFloat SDistanceBetweenPoints(CGPoint first, CGPoint second) {
return hypotf(second.x - first.x, second.y - first.y);
}
To call this function from your code:
CGFloat distance = SDistanceBetweenPoints(nodeA.position, nodeB.position);
Another swift method, also since we are dealing with distance, I added abs() so that the result would always be positive.
extension CGPoint {
func distance(point: CGPoint) -> CGFloat {
return abs(CGFloat(hypotf(Float(point.x - x), Float(point.y - y))))
}
}
Ain't swift grand?
joshd and Andrey Gordeev are both correct, with Gordeev's solution spelling out what the hypotf function does.
But the square root function is an expensive function. You'll have to use it if you need to know the actual distance, but if you only need relative distance, you can skip the square root. You may want to know which sprite is closest, or furtherest, or just if any sprites are within a radius. In these cases just compare distance squared.
- (float)getDistanceSquared:(CGPoint)p1 and:(CGPoint)p2 {
return pow(p2.x - p1.x, 2) + pow(p2.y - p1.y, 2);
}
To use this for calculating if any sprites are within a radius from the center of the view in the update: method of an SKScene subclass:
-(void)update:(CFTimeInterval)currentTime {
CGFloat radiusSquared = pow (self.closeDistance, 2);
CGPoint center = self.view.center;
for (SKNode *node in self.children) {
if (radiusSquared > [self getDistanceSquared:center and:node.position]) {
// This node is close to the center.
};
}
}
Swift:
extension CGPoint {
/**
Calculates a distance to the given point.
:param: point - the point to calculate a distance to
:returns: distance between current and the given points
*/
func distance(point: CGPoint) -> CGFloat {
let dx = self.x - point.x
let dy = self.y - point.y
return sqrt(dx * dx + dy * dy);
}
}
Pythagorean theorem:
- (float)getDistanceBetween:(CGPoint)p1 and:(CGPoint)p2 {
return sqrt(pow(p2.x-p1.x,2)+pow(p2.y-p1.y,2));
}

Rectangle and Circle collision detection

I am trying to do collision detection between a rectangle and a circle. I came up with this method:
-(BOOL) isCollidingRect:(CCSprite *) spriteOne WithSphere:(CCSprite *) spriteTwo {
float diff = ccpDistance(spriteOne.position, spriteTwo.position);
float obj1Radii = [spriteOne boundingBox].size.width/2;
float obj2Radii = [spriteTwo boundingBox].size.width/2;
if (diff < obj1Radii + obj2Radii) {
return YES;
} else {
return NO;
}
}
and this is how I check it:
if ([self isCollidingRect:player WithSphere:blocker] == true) {
[self playerdeathstart];
}
This seems to work properly on the side of the rectangle but it doesn't above or below it. On the top and bottom, the collision occurs too early.
Is there a way I can get this collision to detected properly? Thank you for your help.
You can use CGRectIntersectsRect to achieve this.
-(BOOL) isCollidingRect:(CCSprite *) spriteOne WithSphere:(CCSprite *) spriteTwo {
return CGRectIntersectsRect([spriteOne boundingBox],[spriteTwo boundingBox]);
}
It is not pixel perfect but as i understand that is not necessary in this case.
This is not a solution for those who use Cocos2d-ObjC, but will help for Cocos2d-x devs (for instance, personally I found this topic because was searching for the same for my c++ game).
Cocos2d-x has method "intersectsCircle" for Rect class.
Here is how I solved in my c++ project almost the same problem as one described by you:
bool ObstacleEntity::hasCollisionAgainst(cocos2d::Sprite *spr)
{
cocos2d::Rect rect = cocos2d::Rect( spr->getPositionX(), spr->getPositionY(), spr->getBoundingBox().size.width, spr->getBoundingBox().size.height);
float rw = this->getBoundingBox().size.width / 2;
float rh = this->getBoundingBox().size.height / 2;
float radius = ( rw > rh ) ? rw : rh;
cocos2d::Vec2 center( this->getPositionX() + rw, this->getPositionY() + rh );
return rect.intersectsCircle( center, radius );
}
Passed Sprite here is rectangle, while ObstacleEntity always is almost ideally round.
Note that anchor points for all entities are set to lower left corner in my case.

Resources