ARKit plane visualization - arkit

I want to be able to visualize the planes that my ARKit app detects. How do I do that?
This is what I want to be able to do

Create a new AR project in Xcode with SceneKit and Obj-C, then add these to ViewController.m:
//as a class or global variable:
NSMapTable *planes;
//add to viewWillAppear:
configuration.planeDetection = ARPlaneDetectionHorizontal;
//to viewDidLoad:
planes = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory
valueOptions:NSMapTableWeakMemory];
//new functions:
- (void)renderer:(id<SCNSceneRenderer>)renderer didAddNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor {
if( [anchor isKindOfClass:[ARPlaneAnchor class]] ){
[planes setObject:anchor forKey:node];
ARPlaneAnchor *pa = anchor;
SCNNode *pn = [SCNNode node];
[node addChildNode:pn];
pn.geometry = [SCNPlane planeWithWidth:pa.extent.x height:pa.extent.z];
SCNMaterial *m = [SCNMaterial material];
m.emission.contents = UIColor.blueColor;
m.transparency = 0.1;
pn.geometry.materials = #[m];
pn.position = SCNVector3Make(pa.center.x, -0.002, pa.center.z);
pn.transform = SCNMatrix4MakeRotation(-M_PI / 2.0, 1, 0, 0);
}
}
- (void)renderer:(id<SCNSceneRenderer>)renderer didUpdateNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor {
if( [anchor isKindOfClass:[ARPlaneAnchor class]] ){
[planes setObject:anchor forKey:node];
ARPlaneAnchor *pa = anchor;
SCNNode *pn = [node childNodes][0];
SCNPlane *pg = pn.geometry;
pg.width = pa.extent.x;
pg.height = pa.extent.z;
pn.position = SCNVector3Make(pa.center.x, -0.002, pa.center.z);
}
}
- (void)renderer:(id<SCNSceneRenderer>)renderer didRemoveNode:(nonnull SCNNode *)node forAnchor:(nonnull ARAnchor *)anchor{
[planes removeObjectForKey:node];
}
You'll see translucent planes, give m.emission.contents a texture if you feel so.
Alternatively get the Example App from Apple in Swift

Related

Ball makes contact with player but they are not even closer

What am I missing here? Log says "Ball hits player" every time it collides with frame border or even floor objects if added.
(I´m very new to Sprite Kit and it is my first time working with collisions. This is making me crazy :D)
#import "MyScene.h"
static const int starHitCategory = 1;
static const int playerHitCategory = 2;
static const int ballHitCategory = 3;
#interface MyScene ()
#end
#implementation MyScene{
SKSpriteNode *player;
SKSpriteNode *redball;
SKSpriteNode *star;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.physicsWorld.contactDelegate = self;
self.physicsWorld.gravity = CGVectorMake(0.0f, -3.0f);
SKPhysicsBody* borderBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody = borderBody;
self.physicsBody.friction = 0.0f;
//initalizing player node
player = [SKSpriteNode spriteNodeWithImageNamed:#"player.png"];
player.physicsBody.categoryBitMask = playerHitCategory;
player.physicsBody.contactTestBitMask = playerHitCategory;
player.physicsBody.collisionBitMask = playerHitCategory;
player.position = CGPointMake(75,101);
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.size];
player.physicsBody.friction = 0.0f;
player.physicsBody.linearDamping = 0.5f;
player.physicsBody.mass = 10;
player.physicsBody.dynamic = YES;
player.physicsBody.usesPreciseCollisionDetection = YES;
player.physicsBody.allowsRotation = NO;
player.name = #"player";
[self addChild:player];
//initalizing Redball node
redball = [SKSpriteNode spriteNodeWithImageNamed:#"redbdall.png"];
redball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:redball.frame.size.width/2];
redball.position = CGPointMake(290,200);
redball.physicsBody.usesPreciseCollisionDetection = YES;
redball.physicsBody.categoryBitMask = ballHitCategory;
redball.physicsBody.contactTestBitMask = ballHitCategory;
redball.physicsBody.collisionBitMask = ballHitCategory;
redball.physicsBody.friction = 2.0f;
redball.physicsBody.restitution = 1.0f;
redball.physicsBody.linearDamping = 0.0f;
redball.physicsBody.allowsRotation = NO;
[self addChild:redball];
//initalizing Star node
star = [SKSpriteNode spriteNodeWithImageNamed:#"star.png"];
star.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:star.size];
star.physicsBody.categoryBitMask = starHitCategory;
star.physicsBody.contactTestBitMask = starHitCategory;
star.physicsBody.collisionBitMask = starHitCategory;
star.position = CGPointMake(205,125);
[self addChild:star];
}
return self;
}
-(void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *firstBody, *secondBody;
firstBody = contact.bodyA;
secondBody = contact.bodyB;
if(firstBody.categoryBitMask == playerHitCategory || secondBody.categoryBitMask == ballHitCategory)
{
NSLog(#"ball hits player");
}
}
#end
Thanks in advance
Your if statement will be satisfied if the player/ball object will collide with whatever object it can collide with since you are not also checking that the other object is of the required category.
You should change you if statement to be more strict since you also do not know which object of the two is the ball or the player or the floor:
if((firstBody.categoryBitMask == playerHitCategory && secondBody.categoryBitMask == ballHitCategory) ||
(firstBody.categoryBitMask == ballHitCategory && secondBody.categoryBitMask == playerHitCategory))
{
NSLog(#"ball hits player");
}
This way you can seperate the collision between the objects. Do the same for other object you desire to detect collision with.
Note that you are also setting the bit masks wrong for each physics body object. Read here
look for the section : "Collision and Contact Example: Rockets in Space"
It is very important to understand what each mask property is used for collisions to be detected correctly. (otherwise you indeed can go nuts about it;))

How do I get a particle effect to follow my sprite in cocos2d?

I want a snow particle effect to follow my sprite and I tried some methods but all that ends up happening is the snow will just stay still instead of following. I did this one tutorial (will post as soon as I find it) thats shows how it do it with fire but didn't work out at all. Any tutorials or suggestions will be appreciated. I believe i have to add some kind of code to the snippet part where it says create enemy off screen.
[self schedule:#selector(gameLogicboss:) interval:180 ];
[self schedule:#selector(updateboss:)];
-(void)addTarget1 {
Boss *target1 = nil;
if ((arc4random() % 2) == 0) {{
target1 = [WeakAndFastBoss boss];
}} else {
target1 = [WeakAndFastBoss boss];
}
// Determine where to spawn the target along the Y axis
CGSize winSize = [[CCDirector sharedDirector] winSize];
int minY = target1.contentSize.height/2;
int maxY = winSize.height - target1.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the target slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
target1.position = ccp(winSize.width + (target1.contentSize.width/2), actualY);
[self addChild:target1 ];
// Determine speed of the target
int minDuration = target1.minMoveDuration;
int maxDuration = target1.maxMoveDuration;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
id actionMove = [CCMoveTo actionWithDuration:actualDuration position:ccp(-target1.contentSize.width/2, actualY)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(spriteMoveFinished:)];
[target1 runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
target1.tag = 1;
[_targets addObject:target1];
}
-(void)gameLogicboss:(ccTime)dt {
[self addTarget1];
iterations_++;
}
- (void)updateboss:(ccTime)dt {
CGRect projectileRect = CGRectMake(projectile.position.x - (projectile.contentSize.width/2), projectile.position.y - (projectile.contentSize.height/2), projectile.contentSize.width, projectile.contentSize.height);
BOOL bossHit = FALSE;
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target1 in _targets) {
CGRect target1Rect = CGRectMake(target1.position.x - (target1.contentSize.width/2), target1.position.y - (target1.contentSize.height/2), target1.contentSize.width, target1.contentSize.height);
if (CGRectIntersectsRect(projectileRect, target1Rect)) {
//[targetsToDelete addObject:target];
bossHit = TRUE;
Boss *boss = (Boss *)target1;
boss.hp--;
if (boss.hp <= 0) {
_score ++;
[targetsToDelete addObject:target1];
}
break;
}
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
_projectilesDestroyed++;
if (_projectilesDestroyed > 2) {
}
}
if (bossHit) {
//[projectilesToDelete addObject:projectile];
[[SimpleAudioEngine sharedEngine] playEffect:#"explosion.caf"];
}
[targetsToDelete release];
}
-(void)spriteMoveFinishedboss:(id)sender {
CCSprite *sprite = (CCSprite *)sender;
[self removeChild:sprite cleanup:YES];
GameOverScene *gameOverScene = [GameOverScene node];
[gameOverScene.layer.label setString:#"You Lose"];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
if (sprite.tag == 1) { // target
[_targets removeObject:sprite];
} else if (sprite.tag == 2) { // projectile
[_projectiles removeObject:sprite];
}
}
I Have found this, at CCParticleSystem.h
/** #typedef tCCPositionType
possible types of particle positions
/
typedef enum {
/* Living particles are attached to the world and are unaffected by emitter repositioning. */
kCCPositionTypeFree,
/** Living particles are attached to the world but will follow the emitter repositioning.
Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite.
*/
kCCPositionTypeRelative,
/** Living particles are attached to the emitter and are translated along with it. */
kCCPositionTypeGrouped,
you should set it like
myparticleSystem.positionType=kCCPositionTypeGrouped;
Hope it helps.
You don't need to update the particle emitter's position with the sprite.
You can add a particle system to the sprite as a child.
The particle system does need to be typed as such:
CCParticleSystem * booster = [CCParticleSystem particleWithFile:#"boosterParticles.plist"];
//customize your particles' options
//assuming you have a sprite defined as _motherShip
[_motherShip addChild:booster];
/*
* now that the particles are the _motherShip's child, you must remember
* to set the position relative to the mothership's origin...
*/
particles.position = ccp(15,0);
...So now whenever _motherShip.position changes, the booster will follow. It will even rotate with the ship.
Very simple logic without getting into code:
I spawn a sprite and give it a location (x, y).
For each sprite, I also spawn a CCParticleSystem, give it the required particle type, spawn rates etc.
The CCParticleSystem location is now set to be the same (x,y) location as the sprite, and it should get updated as the sprite's (x,y) location is update.
As the sprite and the CCParticleSystem move around, this location (x, y) is getting updates constantly at random in your schedule method per the interval step time.
Hope that makes sense.
I do this
vehicleParticleSystem = [CCParticleSystemQuad particleWithFile:#"vehicleParticle.plist"];
vehicleParticleSystem.position = ccp(_ship.position.x - _ship.contentSize.width/3, _ship.position.y - _ship.contentSize.height/3);
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
vehicleParticleSystem.scale = 0.5;
}
[self addChild:vehicleParticleSystem z:-1];
and update its position with this
- (void) updateParticleSystem:(ccTime)dt {
vehicleParticleSystem.position = ccp(_ship.position.x - _ship.contentSize.width/3, _ship.position.y - _ship.contentSize.height/3);
}
which is called in the -(void) update:(ccTime)dt method.
The ship is moved by the user via a joypad.
hope this helps. The positioning for the particle is slightly behind the vehicle for an engine effect.
Did you tried to update your particle position taking advantage of the update method?
I'm doing something like the following lines in one of my games and it works as I think you expect
-(void) update:(CCTime)delta{
_sprite.position = CGPointMake(newXPosition, newYPosition);
_fire.position = CGPointMake(_sprite.position.x, _sprite.position.y);
}
I hope it helps!

How to find collision detection between sprite and bezier

I usually use box2d for collision detection between two sprites like below code
- (void)beginContact:(b2Contact *)contact {
b2Fixture *fixtureA = contact->GetFixtureA();
b2Fixture *fixtureB = contact->GetFixtureB();
b2Fixture *fixtureC = contact->GetFixtureA();
b2Body *bodyA = fixtureA->GetBody();
b2Body *bodyB = fixtureB->GetBody();
b2Body *bodyC = fixtureC->GetBody();
CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
CCSprite *spriteB = (CCSprite *) bodyB->GetUserData()
LHBezierNode* bez = (LHBezierNode *) bodyC->GetUserData();
if ((spriteB == _enemy && spriteB == _hero) ||
(spriteA == _enemy && spriteA == _hero)) {
NSLog(#"enemy touched");
}
}
But I am confused how to detect collision detection between bazier and sprite.any help is appreciated.thanks
This is my bezier
LHBezierNode* myBezier = [LH bezierNodeWithUniqueName:#"BezierName"];
note : i use level helper for bezier.
I have solved it by adding tag to brezier, thanks

Why isn't my sprite aligned with b2Body?

I recently started game programming on the iPhone using Cocos2d and Box2d. So here's my problem:
I've got a Player class which inherits from CCSprite, and within that class, there's this method:
-(void) createBox2dObject:(Player *)sender
forWorld:(b2World*)world {
b2BodyDef playerBodyDef;
playerBodyDef.type = b2_dynamicBody;
playerBodyDef.position.Set(sender.position.x/PTM_RATIO, sender.position.y/PTM_RATIO);
playerBodyDef.userData = sender;
body = world->CreateBody(&playerBodyDef);
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(sender.contentSize.width/PTM_RATIO,
sender.contentSize.height/PTM_RATIO);
b2FixtureDef polygonShapeDef;
polygonShapeDef.shape = &dynamicBox;
polygonShapeDef.density = 1.0f;
polygonShapeDef.friction = 1.0f;
polygonShapeDef.restitution = 0;
body->CreateFixture(&polygonShapeDef);
}
and here's how I call this:
self.player = [Player spriteWithSpriteFrameName:#"runningrupol-1.png"];
_player.position = ccp(_player.boundingBox.size.width/2 + 32, _player.boundingBox.size.height/2 + 32);
self.walkAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
[_player runAction:_walkAction];
[spriteSheet addChild:_player];
[_player createBox2dObject:_player forWorld:_world];
Obviously, I'm using a spritesheet which is animated.
Here's how I update the world:
- (void)tick:(ccTime) dt {
_world->Step(dt, 8, 10);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *playerData = (CCSprite *)b->GetUserData();
playerData.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
playerData.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
And here's how I call it in the init method:
[self schedule:#selector(tick:)];
This is what I see:
Please help. And if you need additional info, just tell me.
SetAsBox() uses half-height and half-width (quirky I know), so divide the parameters by 2:
dynamicBox.SetAsBox(sender.contentSize.width/PTM_RATIO/2,
sender.contentSize.height/PTM_RATIO/2);
When you try this, leave the anchor point as is (the default value if you don't explicitly set it should be ccp(0.5,0.5), the center of your sprite, and you want that).
You can change the anchorpoint for the sprite. Here is a good tutorial:
http://www.qcmat.com/understanding-anchorpoint-in-cocos2d/

Cocos2D: CCParallaxNode doesn't display until I move my map a bit

I'm using Cocos2D 0.99.5. I have a CCParallaxNode with background sprites added to it. For some reason, none of them display until I start my map starts moving around a bit. The scroll slowly with the players movement.
I have this added to init:
winSize = [CCDirector sharedDirector].winSize;
bgMountainsMax = floor(winSize.width/240)+1;
if((int)winSize.width%240 > 0){
bgMountainsBumper = ((int)winSize.width%240)/bgMountainsMax;
}else{
bgMountainsBumper = 0;
}
backgroundNode = [CCParallaxNode node];
[self addChild:backgroundNode z:-1];
CGPoint mountainSpeed = ccp(0.5, 0.5);
bgMountains = [[NSMutableArray alloc] initWithCapacity: bgMountainsMax];
for(int i=0; i<bgMountainsMax; ++i){
mountain = [CCSprite spriteWithFile:#"mountainBG1.png"];
mountain.opacity = 80;
[bgMountains insertObject:mountain atIndex:i];
[backgroundNode addChild:[bgMountains objectAtIndex:i] z:0 parallaxRatio:mountainSpeed positionOffset:ccp((240*i)+(bgMountainsBumper*i),98)];
}
And this added to update:
for (CCSprite *mountainNum in bgMountains) {
if ([backgroundNode convertToWorldSpace:mountainNum.position].x < -(240/2)) {
[backgroundNode incrementOffset:ccp(winSize.width+(240),0) forChild:mountainNum];
}
if ([backgroundNode convertToWorldSpace:mountainNum.position].x > winSize.width+(240/2)) {
[backgroundNode incrementOffset:ccp(-(winSize.width+240),0) forChild:mountainNum];
}
}
I think you should be calling the update function stuff once at the end of your init stuff
[backgroundNode incrementOffset:ccp(winSize.width+(240),0) forChild:mountainNum];
[backgroundNode incrementOffset:ccp(-(winSize.width+240),0) forChild:mountainNum];
without the conditionals, to set it up initially.