A sprite has a physics body. When the sprite moves in any direction, the physics body is displaced in that direction (see the attached image). This is bad for the contact and collision.
The physics body is displaced during the movement only. When the sprite stands still, the physics body is not displaced.
My question: why is the physics body displaced in the movement direction in sprite kit? Is there any way to prevent it?
Thanks a lot
EDIT:
OK.. I wrote a small test to demonstrate this issue. I have only one node with physics body which is not affected by gravity. The physics world also has no gravity. By touching the screen, the hero moves upwards. If you please test the code, set the SKView showsPhysics
property = YES. By touching, watch how the physics body moves from its correct place. It is then displaced in the movement direction all the time of the movement.
Thank you for any suggestions.
// header file
#import <SpriteKit/SpriteKit.h>
@interface TestScene : SKScene <SKPhysicsContactDelegate>
@end
// implementation file
#import "TestScene.h"
@implementation TestScene
{
SKNode *_world;
SKSpriteNode *_hero;
BOOL _play;
BOOL _touch;
CGFloat _startY;
}
- (instancetype)initWithSize:(CGSize)size
{
if(self = [super initWithSize:size])
{
self.backgroundColor = [SKColor whiteColor];
self.physicsWorld.contactDelegate = self;
// no gravity
//self.physicsWorld.gravity = CGVectorMake(0.0f, -9.8f);
_play = NO;
_touch = NO;
_startY = 50;
[self addWorld];
[self addHero];
}
return self;
}
- (void)addWorld
{
_world = [SKNode node];
_world.position = CGPointMake(0, 0);
[self addChild:_world];
}
- (void)addHero
{
_hero = [SKSpriteNode spriteNodeWithImageNamed:@"hero"];
_hero.size = CGSizeMake(50, 50);
_hero.position = CGPointMake(CGRectGetMidX(self.frame), _startY);
[_world addChild:_hero];
_hero.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_hero.size.width/2.0f];
_hero.physicsBody.affectedByGravity = NO;
_hero.physicsBody.dynamic = YES;
_hero.physicsBody.allowsRotation = NO;
}
- (void)applyHeroUpwardForce
{
[_hero.physicsBody applyForce:(CGVectorMake(0, 100))];
// limit velocity
CGVector vel = _hero.physicsBody.velocity;
vel.dy = vel.dy > 1000 ? 1000 : vel.dy;
_hero.physicsBody.velocity = vel;
// control the hero movement. it really moves upwards even we don’t see that, since the _world moves downwards
NSLog(@"_hero.position.y: %f", _hero.position.y);
}
- (void)updateWorld
{
_world.position = CGPointMake(_world.position.x, -(_hero.position.y - _startY));
}
- (void)didSimulatePhysics
{
if(!_play)
return;
if(_touch)
{
[self applyHeroUpwardForce];
[self updateWorld];
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if(!_play)
_play = YES;
_touch = YES;
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
_touch = NO;
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
_touch = NO;
}
@end
EDIT 2:
The same issue in the game 'Pierre Penguin Escapes The Antarctic'