My goal is to create a single physics body out of several of SceneKit's SCNBox geometries.
My understanding is that when I pass an SCNPhysicsShape(shapes:transforms:) to an SCNPhysicsBody(type:shape:), it should create a single physics body.
However, I end up with something that seems suspiciously like it's not a single physics body at all, but rather several separate physics bodies -- one for each shape I passed into SCNPhysicsShape(shapes:transforms:).
When I turn on scnView.debugOptions = .showPhysicsShapes, I can clearly see red lines defining the separate bodies in question. On its own, this isn't very convincing evidence (it's conceivable that those lines could be shown for whatever reason while still being a single physics body).
But there's another piece of data, here: The project in which I'm encountering this issue features a small ball that rolls around the scene -- and when that ball rolls over the red lines in question, the ball bounces up into the air a bit. So, it's quite obvious that, whatever is actually going on, there are edges where I would expect to see none.
This behavior is clearly visible in the following GIF. In it, each colored block is a separate SCNBox geometry with its own physics body. Each block has the exact same position.z. The ball bounces considerably as it crosses the point where one geometry meets another.
Here's some code illustrating the issue. parent is an SCNNode that holds the child nodes, and is the node to which I assign the physics body. Please assume that all properties are defined; I'm omitting things that aren't terribly relevant.
let childShape1 = SCNBox(width: 6, height: 2, length: 6, chamferRadius: 0.0)
//Other child shapes defined here...
//Set up the positional translation relative to the child node's parent:
let translateMatrixShape1 = SCNMatrix4MakeTranslation(childShape1.position.x, childShape1.position.y, childShape1.position.z)
//Other child translations defined here...
let parentShape = SCNPhysicsShape(shapes: [childShape1, childShape2, childShape3, childShape4], transforms: [translateMatrixShape1, translateMatrixShape2, translateMatrixShape3, translateMatrixShape4])
parent.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.static, shape: parentShape)
Now, parentShape is four rectangular boxes arranged around a central point, creating a sort of picture-frame-shaped object.
The ball is an SCNNode with an SCNSphere geometry and a dynamic physics body.
Question: Does anyone have any idea what might be going on, here? Have I somehow misunderstood how this whole thing works, or is this a limitation of SceneKit?
Usually you can create one single PhysicsBody from several geometry objects by making a flattenendClone from out of your (i.Ex.) parent node. This new node will have one single geometry then. For the PhysicsBody you can then use the geometry element of the new node. In Addition I recoommend to use a concavePolyhedron for the static body type. (I hope I understood you correctly)
Related
I am currently working on a 2D endless runner, written in Swift3 and using Spritekit.
Short question:
Is there a way to only check for collisions on the right side of my character's rectangular physics body?
More info:
The platform on which the character runs is made of puzzle pieces and the user builds upon it as the game progresses. The character progresses left to right, in respect to the background (which goes right to left).
I want the character to automatically jump when he collides with a piece on his right side. However, any pieces that the player puts to the right of him (same Y value as the character) is of the same class as the pieces underneath him.
So the same code that checks for collision between the character and pieces to his right, and make him jump, will also make him jump as long as the game detects collision between the character and the pieces under him.
I have not been able to find another problem like mine, since usually others' characters are colliding with objects of different classes from their ground class.
Thanks!
P.S. I have tried to make my character a SKSpriteNode with two physics bodies, but I could not find any helpful documentation. If it helps any, my character also performs a looping running animation--though I can't imagine that would harm anything.
You could achieve that by detecting collisions with your rectangle and then deciding whether the collision was with the side of your interest or not. Here is a discussion about how to do that. Good luck!
Have you tried adding a non visible sub node (e.g. feetNode) to your character's sprite node and giving that sub node the physics body (class) for floor contact ?
Depending on the rest of your logic, it may allow you to use a different physics class for your character have more flexibility in collision detection.
In fact, you could probably use that approach with several sub nodes in your character's sprite node and have multiple collision behaviours for the character depending on what hits it.
Once you obtain the contact point of the 2 bodies that are colliding, determine which body is the one that is colliding by checking the categorymasks and then check its CGPoints x position. This x position can be compared to the other body's x position to know exactly which side it is colliding from.
if Body A's x position > Body B's x position, Body A is on the right and if not, its on the left.
As simple as that.
Hope this helps!
I am working on a game, and I am using an alpha mask to create an SKPhysicsBody for the basket + catcher. The SKView has showPhysics set to true.
I can't figure out what in the world the disc is hitting. There is no physics field there. When I recreate the reference node with SKSpriteNodes this works flawlessly. I would like to use a reference node though because it would make it easier to make lots of these quickly. Here is where I set up the reference node:
Here is where I create the scene itself:
I have zero idea at this point what is happening. Clearly there is an error with showing the physics as well, because there is no blue outline there.
I am seeming to have difficulty keeping my sprite nodes inside a map boundary that I have set up in the following way:
I have an SKNode *enemy that moves around an SKScene by goals and behaviors courtesy of GameplayKit from iOS 9. Currently the node wanders, and avoids obstacles that are defined GKPolygonObstacle objects. I have my bitmask set up so that any obstacle is deemd category wall, which the node is told to collide with (AKA disallow passing through).
In my didBeginContact:(SKPhysicsContact *)contact I am handling these collisions. All is working exactly as planned and there are no issues when manually moving this enemy.
However, the problem begins when I have the enemy wander around the scene through an SKGoal *wanderGoal set up as
// Low --> 0.5 Lowest --> 0.25
enemy.wanderGoal = [GKGoal goalToWander:low];
[enemy.agent.behavior setWeight:lowest forGoal:enemy.wanderGoal];
// Add obstacles to avoid for each of the inner map nodes
// that act as impassible areas for the enemy to pass through.
NSArray *obstacles = [SKNode obstaclesFromNodePhysicsBodies:innerMapArray];
/** This goal does not change --> enemies will ALWAYS
avoid the obstacles in the level map. This should always
be set to the highest priority of the enemy goals
*/
enemy.avoidGoal = [GKGoal goalToAvoidObstacles:obstacles maxPredictionTime:10];
// Highest --> 250
[enemy.agent.behavior setWeight:highest forGoal:enemy.avoidGoal];
The enemy moves randomly as expected, and seems to avoid the obstacles most of the time...yet on the occasion the enemy does in fact pass through the map barrier. Let me expand on this:
The map barrier is essentially a rectangle, and I have set up 2 nodes that act as a shell that represent the left half and the right half of this shape. These nodes have a thickness of 100 points so they are not simply CGPath refs but rather shapes. They act as these two brackets act: [] (my halves are flush touching at the middle).
My question is such:
How can I prevent the enemy from passing through these obstacles with using either physics with the bitmask categories, or by the goal behavior? (Or both together)
I understand that while a GKGoal is a suggested behavior it does not guarantee this goal to be reached (but it can be ~95% sure it wont happen as Apple's AgentsCatalog shows). But, what I don't understand is why the enemy does not simply "slide" along the edge of the boundary as the goal tells it to (try to) "pass" through such boundary.
This "sliding" behavior does happen when I manually move the enemy around the scene, and as I attempt to move it passed a boundary deemed an obstacle, it slides towards the direction that I am having it move (just as any video game does that has map boundaries).
SO
If someone can help me prevent this from happening / explain how to approach preventing the enemy from ever passing through these (supposedly) "impassible" areas, I would be most appreciative.
FYI: If you are unclear with what I am describing / how I have created any objects, please ask and I will provide more info to help.
I have basic rectangle node with physics body, I want to find middle pint of it, because, I want to both ends of rectangle react different to collision with another objects.I was looking for answer on the Internet, I find that I can use CGGeometry, but I don't have knowledge how to do it. How can I do that?
Why not just add a physics body on each end of your rectangle as a child. Then you can just detect if the child physics bodies collided without any complicated math
I have built a landscape model in blender, exported to .dae and added to my xcode project.
I have loaded the scene then attached the child (landscape grid mesh) to my landscapeNode, this loads perfectly.
However when I attach a static physics body to the landscspeNode my heroNode seems to crash into a invisible wall when attempting to fly above the land.
The functionality I am looking for is the obvious collision with the land I have modelled so the heroNode cannot fly through the land and is forced to move around it.
Note: I did not do any converting of the y axis in blender nor xcode just simply rotated the node 90degrees about the -x axis.
Edit: code i've attempted to add physics shape
landscapeNode.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeStatic shape:[SCNPhysicsShape shapeWithNode: [landscapeScene.rootNode childNodeWithName:#"Grid" recursively:NO] options:#{SCNPhysicsShapeTypeKey:SCNPhysicsShapeTypeConcavePolyhedron}]];
landscapeNode.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeStatic shape:[SCNPhysicsShape shapeWithNode: landscapeNode options:#{SCNPhysicsShapeTypeKey:SCNPhysicsShapeTypeConcavePolyhedron}]];
landscapeNode.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeStatic shape:[SCNPhysicsShape shapeWithGeometry: landscapeNode.geometry options:#{SCNPhysicsShapeTypeKey:SCNPhysicsShapeTypeConcavePolyhedron}]];
If you don't specify additional options when creating a physics body for a node, what you get is a convex hull encompassing that node's geometry.
Because your landscape is a static body, you can make it use a concave shape that more closely approximates the geometry. (Note that this works only for static bodies.) To do this, you'll need to:
Use the bodyWithShape:type: method to create the body, not staticBody.
For that method you need to pass an SCNPhysicsShape. Create one with shapeWithGeometry:options: or shapeWithNode:options:.
For the options parameter, pass a dictionary containing the key SCNPhysicsShapeTypeKey and corresponding value SCNPhysicsShapeTypeConcavePolyhedron.