affectedbygravity in SceneKit? - ios8

I want to make a floating ball.
In spritekit I do physicsbody.affectedbygravity=NO;
But what have I do in scenekit?
I tried to set mass to zero, but dynamicbody turns to static: it not moved by gravity, nor by collision. My code is
// add ball
SCNNode *ball = [SCNNode node];
ball.geometry = [SCNSphere sphereWithRadius:5];
ball.geometry.firstMaterial.locksAmbientWithDiffuse = YES;
ball.geometry.firstMaterial.diffuse.contents = #"ball.jpg";
ball.geometry.firstMaterial.diffuse.contentsTransform = SCNMatrix4MakeScale(2, 1, 1);
ball.geometry.firstMaterial.diffuse.wrapS = SCNWrapModeMirror;
ball.physicsBody = [SCNPhysicsBody dynamicBody];
ball.physicsBody.restitution = 0.9;
//ball.physicsBody.mass=0; //here makes a ball statical and not moving
ball.physicsBody.allowsResting = YES;
[[scene rootNode] addChildNode:ball];
UPD this not helps too - ball falls slowly.
- (void)renderer:(id<SCNSceneRenderer>)aRenderer didSimulatePhysicsAtTime:(NSTimeInterval)time{
[ball.physicsBody applyForce:SCNVector3Make(0, 9.8, 0) atPosition:SCNVector3Make(0,0,0) impulse:NO]; //this
ball.physicsBody.velocity=SCNVector3Make(0,0,0); //or this
}

You can turn off gravity by setting scene.physicsWorld.gravity to zero.
However If you want some objects to be affected and some not you need to add a [SCNPhysicsField linearGravityField] and configure the categoryBitMask to make it affect the nodes you want.

I found partial solution and some fun bug.
This makes ball stay unmovable until collision and "float" after that
// .... the same code above in creation
ball.physicsBody.mass=1;
[[scene rootNode] addChildNode:ball];
ball.physicsBody.mass=0; //important right after creating!!! or it become bodyless after changing mass to 1
and release it if contact. If you apply up force equal to gravity, it will be floating, slowly falling down. Speed of falling may be damped, of cause.
// physics contact delegate
- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact{
if (contact.nodeA.physicsBody.type == SCNPhysicsBodyTypeDynamic && contact.nodeA.physicsBody.mass==0)
contact.nodeA.physicsBody.mass=1;
else
if (contact.nodeB.physicsBody.type == SCNPhysicsBodyTypeDynamic && contact.nodeB.physicsBody.mass==0)
contact.nodeB.physicsBody.mass=1;
}

Related

How to invert the sprite position in GameMaker Studio 2 code?

I put this code for my sprite to reverse the position according to its direction but it reverses the position and it looks skinny. How to fix this?
key_left = keyboard_check(ord("A"))
key_right = keyboard_check(ord("D"))
key_jump = keyboard_check(vk_space)
var move = key_right - key_left
hspd = move * spd;
vspd = vspd + grv;
if (hspd != 0) {
image_xscale = sign(hspd)
}
The code's correct. You must have resized the sprite in the room editor, delete the instance and put it in again and don't resize it, it should work.
Also if you need it a little bigger you can (If 1.5 doesn't satisfy you, feel free to use a bigger number).
image_xscale = sign(hspd) * 1.5;
The code seem to be correct, have you tried setting the origin point at the center? By default the origin point is on the top-left, and once it's set at the center of your sprite, it won't change positions when turning around.
You can set the origin point at the sprite window.

Unity3D: How do I improve my Idle animation (Y-axis)

Okay, I am almost finished with my 2d rpg click to move game. If you look at this video you will be able to see that when I click forward my player, once it gets to it's position, face the wrong direction rather than facing straight towards the players. To make myself more clearer, this is an image of the sprite sheet I am currently using, as you can see it has 8 directions. When you click here (in the game), my player would walk down and face this direction or this direction, rather than facing this direction (the normal/preferred position). This also happens when I click here (in the game) my player would walk up and face this direction or face this direction, rather than facing this direction. How can I make sure that my player face the right direction once it reached it's destination. Again this is only occurring within the Y-axis, so walking along the X-axis is fine.
private Animator anim;
public float speed = 15f;
private Vector3 target;
private bool touched;
private bool playerMovementRef;
void Start () {
target = transform.position;
anim = GetComponent<Animator> ();
}
void Update () {
if (Input.GetMouseButtonDown (0)) {
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = 10; // distance from the camera
target = Camera.main.ScreenToWorldPoint (mousePosition);
target.z = transform.position.z;
var movementDirection = (target - transform.position).normalized;
Vector3 animDirection = Vector3.zero;
if (movementDirection.sqrMagnitude > 0)
{
// Use >= to default to horizontal on both being equal
if (movementDirection.x > movementDirection.y)
animDirection.x = 1;
else
animDirection.y = 1;
anim.SetBool ("walking", true);
anim.SetFloat ("SpeedX", movementDirection.x);
anim.SetFloat ("SpeedY", movementDirection.y);
if (movementDirection.x < 0) {
anim.SetFloat ("LastMoveX", -1f);
} else if (movementDirection.x > 0) {
anim.SetFloat ("LastMoveX", 1f);
} else {
anim.SetFloat ("LastMoveX", 0f);
}
if (movementDirection.y > 0) {
anim.SetFloat ("LastMoveY", 1f);
} else if (movementDirection.y < 0) {
anim.SetFloat ("LastMoveY", -1f);
} else {
anim.SetFloat ("LastMoveY", 0f);
}
}
} else {
if (Mathf.Approximately (transform.position.x, target.x) && Mathf.Approximately (transform.position.y, target.y)) {
touched = false;
anim.SetBool ("walking", false);
} else {
transform.position = Vector3.MoveTowards (transform.position, target, speed * Time.deltaTime);
}
}
}
}
I'm just starting out with Unity, but hope I can help.
From the video you've posted I've noticed that the sprite is only 'wrong' when the oldPosition and newPosition click differs in the X component, e.g. when you would click straight down it would show the desired behavior and sprite.
Have you tried printing out the x and y values that your code is using to calculate which sprite it's setting?
At first I thought that maybe it's because the values you set in the Blend Tree were at -1, 1 etc, and due to normalizing you sometimes wound up with 0.9 for a certain value.
Can you maybe try debugging it with the animator window open, like you did at the end? Writing down the values and comparing them between Desired and Undesired behavior might tell you something more.
Sorry I don't have a concrete solution to your problem, but I hope this helps.
Edit for clarification:
Basically, what I'm recommending is to:
1) Print out the values you are getting when the behavior happens, an example of how to print these things out is by using LogFormat, for example:
Debug.LogFormat("X: {0}, Y: {1}", xPosition, yPosition);
Now, you will get the values printed out when it finishes moving.
2) Write down the values for when the moving finishes with the 'Wrong' sprite, and keep clicking to move until the 'Right' sprite shows up. Write down the values again.
3) Compare each values, and find the differences. Now deduce why the differences are as they are, using the values in conjunction with your blend trees.
4) Once you know why, go back through your code/blend trees and rewrite/fix it to work as you intended it to.

Physics body as an SKTexture does not rotate

I am making a game where the main character rotates, however, I want to use an SKTexture to set custom boundaries to the character sprite node. However, when I do this, my character does not rotate. When I use a regular circleOfRadius (because my sprite is round, but no perfectly round) it rotates, but is not accurate on collisions. Here is my code:
var mainSpriteTexture = SKTexture(imageNamed: "Main")
mainSprite = SKSpriteNode(texture: mainSpriteTexture)
mainSprite.setScale(0.2)
mainSprite.position = CGPoint(x: self.frame.width / 2, y: 100)
mainSprite.physicsBody = SKPhysicsBody(texture: mainSpriteTexture, size: mainSprite.size)
mainSprite.physicsBody?.categoryBitMask = PhysicsCatagory.player
mainSprite.physicsBody?.collisionBitMask = PhysicsCatagory.platform | PhysicsCatagory.ground
mainSprite.physicsBody?.contactTestBitMask = PhysicsCatagory.platform | PhysicsCatagory.ground | PhysicsCatagory.score
mainSprite.physicsBody?.affectedByGravity = true
mainSprite.physicsBody?.dynamic = true
mainSprite.physicsBody?.allowsRotation = true
self.addChild(mainSprite)
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
updateSpritePosition()
if gameStarted == true {
if died == false {
mainSprite.physicsBody?.velocity = CGVectorMake(direction, (mainSprite.physicsBody?.velocity.dy)!)
}
else if died == true {
mainSprite.physicsBody?.velocity = CGVectorMake(0, (mainSprite.physicsBody?.velocity.dy)!)
}
}
Here is the shape I am using: http://imgur.com/JCeEAbv
Not really sure how you rotate your sprite, or move it, but if I give it a certain default rotation and drop it on the surface, it rotates for me as it should (I used a picture you have provided). This way, it will not land perfectly on the ground (zRotation 0.0).
Try to use this:
mainSprite.zRotation = 0.1 //note that these are radians
and drop it on a flat surface.
Same thing you could probably achieve by applying a small force or impulse which should affect sprite's zRotation property... What you are going to use, depends on how you move your node actually - using physics, or by changing its position property directly (see my comment about mixing physics & manual node movement for important details).

How would I create a "wall" on the left and right side of my screen Swift Spritekit?

I want objects to be able to pass through the bottom and top of the screen but not be able to leave the right and left side. I have this code but when my objects go to the left or right it doesn't act as a wall and lets it go right through it. I used the contactTestBitMask to make sure there was contact but there is no collision. This is the code for the wall on the left:
func wall() {
let leftWall = SKNode()
leftWall.physicsBody = SKPhysicsBody(edgeLoopFromRect:CGRectMake(1.0,
1.0, 1.0, CGRectGetHeight(self.frame)));
leftWall.physicsBody?.categoryBitMask = OutsideCategory
leftWall.physicsBody?.contactTestBitMask = HeroCategory
leftWall.physicsBody?.collisionBitMask = 0
leftWall.physicsBody?.mass = 5
leftWall.physicsBody?.friction = 1.0
leftWall.physicsBody?.restitution = 1
leftWall.physicsBody?.usesPreciseCollisionDetection = true
leftWall.physicsBody?.dynamic = false
leftWall.physicsBody?.affectedByGravity = false
leftWall.position = CGPointMake(0, self.size.height / 40)
leftWall.setScale(1.0)
self.addChild(leftWall)
As long as the category bit mask is set on your wall, and your walls do in fact exist where you expect them to exist (you can set a flag on the scene to draw physics bodies which will display your wall), and the collisionBitMask of the nodes that should collide with the walls are set to the categoryBitMask of the wall (and you have created world physics body on the scene), you should be good to go.
Example:
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.contactDelegate = self;
self.physicsBody.categoryBitMask = CNPhysicsCategoryEdge;
_catNode.physicsBody.collisionBitMask = CNPhysicsCategoryBlock | CNPhysicsCategoryEdge | CNPhysicsCategorySpring;
_catNode.physicsBody.contactTestBitMask = CNPhysicsCategoryBed | CNPhysicsCategoryEdge;
The cat sprite node in this example will collide with the world physics body now.
Your collisionBitMask cannot be set to 0. It must match an enum value that coinsides with the categoryBitMask of the other objects. Per apple's documentation:
collisionBitMask Property A mask that defines which categories of
physics bodies can collide with this physics body.
Declaration
SWIFT var collisionBitMask: UInt32 OBJECTIVE-C
#property(nonatomic, assign) uint32_t collisionBitMask
Discussion When
two physics bodies contact each other, a collision may occur. This
body’s collision mask is compared to the other body’s category mask by
performing a logical AND operation. If the result is a nonzero value,
this body is affected by the collision. Each body independently
chooses whether it wants to be affected by the other body. For
example, you might use this to avoid collision calculations that would
make negligible changes to a body’s velocity.
The default value is 0xFFFFFFFF (all bits set).
Example:
CGRect bodyRect = CGRectInset(frame, 2, 2);
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:bodyRect.size];
self.physicsBody.categoryBitMask = CNPhysicsCategoryBlock;
self.physicsBody.collisionBitMask = CNPhysicsCategoryBlock | CNPhysicsCategoryCat | CNPhysicsCategoryEdge;

How to Randomly Move Sprites and Keep Collisions Working - Cocos2d?

I want to have a random sprite spawn and move across the screen.
I'm using CGRectIntersectsRect to detect collisions between the player and the randomly spawned sprites.
I've done this, the code works fine - when I have a set interval.
However, when I add randomness to the sprite's spawn times, collisions do not work all the time. Most collisions do not work at all.
I'm not sure what I'm doing wrong and would really appreciate any help in the right direction.
I think it has something to do with the schedule interval and how long it actually takes for the sprite to move across the screen.
Not sure though.
Also, if you could, I would also like to know the best way to remove enemySprite from the scene after it is off the screen?
Here's my code:
-(void)targetTimer {
[self schedule: #selector(enemySprite:) interval: 3.0f];
}
-(void)enemySprite:(id)sender {
CGSize winSize = [[CCDirector sharedDirector] winSize];
//SPAWN ENEYMY
enemySprite = [CCSprite spriteWithFile:#"eneymySprite.png"];
enemySprite.position = ccp (winSize.width/16, winSize.height/5);
[self addChild:enemySprite z:300];
CCAction *moveEnemyRight = [CCMoveTo actionWithDuration:3 position:ccp (winSize.width/1, winSize.height/5) ];
[enemySprite moveEnemyRight];
if ( enemySprite.position.y >= winSize.width ) {
//Best Way to Remove enemySprite from Scene?
}
NSLog(#"Collision");
[self unschedule:#selector(enemySprite:)];
unsigned int t = arc4random()%4 + 1;
[self schedule:#selector(enemySprite:) interval: t];
}
You have to craete an array of your enemies to be able to check if they leave game area (screen in your case). In your code this part
if ( enemySprite.position.y >= winSize.width ) {
//Best Way to Remove enemySprite from Scene?
}
will never be called. Because enemySprite.position.y >= winSize.width will be always NO as you just created this sprite and place it to the game area with coordinate
ccp(winSize.width/16, winSize.height/5)

Resources