PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0
Showing posts with label scenekit. Show all posts
Showing posts with label scenekit. Show all posts

Thursday, September 29, 2022

[FIXED] How to select an individual SceneKit SCNNode using the remote on tvOS

 September 29, 2022     focus-engine, scenekit, scnnode, tvos     No comments   

Issue

Is there a way to get the focus engine on SceneKit? I am attempting to build a 3d game, in which players must select from many SceneKit Nodes, but I cannot find a way to give the SCNNodes focus.


Solution

An SCNNode is a model object, not a UIView descendant (or more precisely doesn't conform to UIFocusEnvironment), so I wouldn't expect it to be able to take focus.

So how to select a particular SCNNode in an SCNView? The Apple tvOS SceneKit template implements hit testing, but I don't see how the user can choose what point on the screen they're selecting; there's no visual feedback. The template/demo seems poorly thought out. So here's an approach some colleagues and I discussed the other day, but didn't try to implement.

The SCNView can have a SpriteKit overlay scene, overlaySKScene. Use some gesture (maybe a long press, or the Play button) to switch into "I'm about to pick a node" mode. That means a cursor appears on the overlaySKScene, and can be moved around by finger movement on the remote. User moves the cursor over the correct node and then...clicks? Program grabs the cursor's SpriteKit coordinates, translates that back to a SceneKit hit test input, and performs the hit test on the scene graph.

@vigneshv points out that Apple has discouraged the use of cursors. And that's also what I heard from people who attended the Tech Talks this week. So a modified approach could be to use an invisible cursor on the SKScene. With each movement on the remote, perform a hit test. Highlight the node that's under the invisible cursor, but don't take action until you get a trackpad click. When you first switch into node-select mode, you could even put the invisible cursor over the largest or most central node, to provide some preliminary visual feedback.

Depending on your node graph, this could get complex. I could imagine generating a Voronoi diagram based on the SCNNode centers, and using remote gestures to move from polygon to polygon.

One more idea: instead of the hidden, implied Voronoi diagram, use a simple rectangular (or hex?) grid to track the cursor. The hit testing becomes more complex: you could have multiple nodes under each grid cell. But the grid becomes easier to construct, and easier to navigate.



Answered By - Hal Mueller
Answer Checked By - Marie Seifert (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Wednesday, September 28, 2022

[FIXED] Why SCNPhysicsBody resets position when set eulerAngles?

 September 28, 2022     apple-tv, objective-c, scenekit, scnnode, tvos     No comments   

Issue

I'm trying to use SceneKit to develop a game for tvOS, and I'm having an issue. When I set the node's eulerAngle before apply an impulse to the physicsBody the node is reset to his original position.

I was expecting to see the nodes moving around on the floor's plane, but on each tap the nodes are moved to the origin position before the impulse is applied.

I'm new at the use of this framework, so I wonder where is the mistake. I'm using the new AppleTV with tvOS 9.0 and XCode 7.1.1

To reproduce it, you can create a new xcode project (Game for tvOS) and replace the GameViewController.m with this code:

#import "GameViewController.h"

SCNNode *ship;
SCNNode *node;
SCNNode *ground;

@implementation GameViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // create a new scene
    SCNScene *scene = [[SCNScene alloc] init];
    scene.physicsWorld.gravity = SCNVector3Make(0, -800, 0);

    // create and add a camera to the scene
    SCNNode *cameraNode    = [SCNNode node];
    cameraNode.camera      = [SCNCamera camera];
    cameraNode.camera.zFar = 10000;
    [scene.rootNode addChildNode:cameraNode];

    // place the camera
    cameraNode.position = SCNVector3Make(0, 64, 64);

    // create and add a light to the scene
    SCNNode *lightNode   = [SCNNode node];
    lightNode.light      = [SCNLight light];
    lightNode.light.type = SCNLightTypeOmni;
    lightNode.position   = SCNVector3Make(0, 10, 10);
    [scene.rootNode addChildNode:lightNode];

    // create and add an ambient light to the scene
    SCNNode *ambientLightNode    = [SCNNode node];
    ambientLightNode.light       = [SCNLight light];
    ambientLightNode.light.type  = SCNLightTypeAmbient;
    ambientLightNode.light.color = [UIColor darkGrayColor];
    [scene.rootNode addChildNode:ambientLightNode];

    SCNGeometry *geometry;
    SCNMaterial *material;
    SCNNode *tempNode;
    SCNPhysicsShape* shape;
    SCNPhysicsBody* body;

    //--
    SCNScene *loaded = [SCNScene sceneNamed:@"art.scnassets/ship.scn"];
    tempNode = [loaded.rootNode childNodeWithName:@"ship" recursively:YES];

    geometry = [SCNCylinder cylinderWithRadius:16 height:8];
    shape    = [SCNPhysicsShape shapeWithGeometry:geometry options:nil];

    tempNode.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeDynamic shape:shape];
    tempNode.physicsBody.restitution      = 1;
    tempNode.physicsBody.friction         = 0.25;
    tempNode.physicsBody.categoryBitMask  = 2;
    tempNode.physicsBody.collisionBitMask = 1;
    tempNode.position = SCNVector3Make(32, 32, 0);
    [scene.rootNode addChildNode:tempNode];
    ship = tempNode;

    //--
    geometry = [SCNCylinder cylinderWithRadius:16 height:8];

    material = [[SCNMaterial alloc] init];
    material.diffuse.contents = UIColor.yellowColor;
    geometry.materials        = @[material];

    shape = [SCNPhysicsShape shapeWithGeometry:geometry options:nil];
    body  = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeDynamic shape:shape];

    tempNode = [SCNNode nodeWithGeometry: geometry];
    tempNode.physicsBody                  = body;
    tempNode.physicsBody.restitution      = 1;
    tempNode.physicsBody.friction         = 0.25;
    tempNode.physicsBody.categoryBitMask  = 2;
    tempNode.physicsBody.collisionBitMask = 1;
    tempNode.position = SCNVector3Make(0, 32, 0);
    [scene.rootNode addChildNode:tempNode];
    node = tempNode;

    //--
    geometry = [[SCNFloor alloc] init];

    material = [[SCNMaterial alloc] init];
    material.diffuse.contents = UIColor.blueColor;
    geometry.materials        = @[material];

    shape = [SCNPhysicsShape shapeWithGeometry:geometry options:nil];
    body  = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeKinematic shape:shape];

    tempNode = [SCNNode nodeWithGeometry: geometry];
    tempNode.physicsBody = body;
    tempNode.physicsBody.categoryBitMask = 1;
    [scene.rootNode addChildNode:tempNode];
    ground = tempNode;

    //--
    SCNLookAtConstraint * constraint = [SCNLookAtConstraint lookAtConstraintWithTarget: ground];
    constraint.gimbalLockEnabled = YES;
    cameraNode.constraints = @[constraint];

    // configure the SCNView
    SCNView *scnView = (SCNView *)self.view;
    scnView.scene = scene;
    scnView.allowsCameraControl = NO;
    //scnView.antialiasingMode = SCNAntialiasingModeMultisampling2X;
    scnView.debugOptions = SCNDebugOptionShowPhysicsShapes;
    scnView.showsStatistics = YES;
    scnView.backgroundColor = [UIColor blackColor];

    // add a tap gesture recognizer
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    NSMutableArray *gestureRecognizers = [NSMutableArray array];
    [gestureRecognizers addObject:tapGesture];
    [gestureRecognizers addObjectsFromArray:scnView.gestureRecognizers];
    scnView.gestureRecognizers = gestureRecognizers;
}

- (void) handleTap:(UIGestureRecognizer*)gestureRecognize
{
    float x = (rand() / (float)RAND_MAX) - 0.5f;
    float y = (rand() / (float)RAND_MAX) - 0.5f;
    float speed = (rand() / (float)RAND_MAX) * 300;

    CGPoint velocity = CGPointMake(x, y);
    float angle = [self AngleBetween:velocity And:CGPointMake(1, 0)] + M_PI_2;

    [node.physicsBody applyForce:SCNVector3Make(velocity.x*speed, 0, velocity.y*speed) impulse:YES];
    [ship.physicsBody applyForce:SCNVector3Make(velocity.x*speed, 0, velocity.y*speed) impulse:YES];

    // if comment these lines the problem doesn't appears
    node.eulerAngles = SCNVector3Make(0, angle, 0);
    ship.eulerAngles = SCNVector3Make(0, angle, 0);
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (float) AngleBetween:(CGPoint)_origin And:(CGPoint)_destination
{
    float dotProduct = (_origin.x * _destination.x) + (_origin.y * _destination.y);
    float perpDotProduct = (_origin.x * _destination.y) - (_origin.y * _destination.x);

    return -atan2f(-perpDotProduct, dotProduct);
}

@end

If you comment the lines where the euler angles are set (at handleTap method) the problem doesn't appears.


Solution

From Apple's SCNPhysicsBody documentation:

If you change the transform value—or any of the other properties that are components of the transform, such as position and rotation—of a node affected by physics, SceneKit resets the physics simulation for that node.

The physics simulated values are in the presentationNode property. So in your case the way to go is to copy the presentation node's position before applying the transformation, and then write it back:

SCNVector3 nodePosition = [[node presentationNode] position];
SCNVector3 shipPosition = [[ship presentationNode] position];

[node.physicsBody applyForce:SCNVector3Make(velocity.x*speed, 0, velocity.y*speed) impulse:YES];
[ship.physicsBody applyForce:SCNVector3Make(velocity.x*speed, 0, velocity.y*speed) impulse:YES];

// if comment these lines the problem doesn't appears
node.eulerAngles = SCNVector3Make(0, angle, 0);
ship.eulerAngles = SCNVector3Make(0, angle, 0);

[node setPosition: nodePosition];
[ship setPosition: shipPosition];


Answered By - Ramy Al Zuhouri
Answer Checked By - Mary Flores (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Older Posts Home
View mobile version

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
All Comments
Atom
All Comments

Copyright © PHPFixing