Uikit dynamic density - objective-c

i'm trying to make a barrier in uikit dynamic sso this barrier don't get affected by gravity but when a object hits it it start floating instead of keeping in place and stop the object, I was planing to set a high density but can't get it to work.

I have the same question with you. but i cant find the correct answer.if you want wo use UIDynamic to creat barrier,that the better thing is to create a barrier to add below behavior.
UIDynamicItemBehavior itemBehaviorNoBounce = [[UIDynamicItemBehavior alloc] init];
itemBehaviorNoBounce.allowsRotation = NO;
itemBehaviorNoBounce.elasticity = 0;
this can make the item collision a little, but if you have a lot of thing to crash,that is a not good way to use UIDynamic for a barrier. beacause the calculate of the item is complex. And you cant control it.

Related

Issue with updating score based on collision detection in SpriteKit

I am working on a SpriteKit game where in one of the scenes I have to update score based on collision between two sprites. I intend to increment score by 1 whenever those two SKSpriteNodes collide with each other. There is a collision detection method in SpriteKit, which takes care of collision detection itself. I am using that default method didBeginContact: to detect collision, remove one of the objects involved in collision and increment score by 1. There are multiple objects of the same kind falling from the top and there is a basket like object that a player can move horizontally to catch those falling objects. On colliding with the basket, objects falling from the top are removed and score get incremented. The issue is very simple, that the score is being incremented not only by 1, but by 2,3,4,5 as well. That means instead of detecting single collision as it should be the case, it is detecting more than one collisions and hence incrementing score accordingly.
I have viewed here another question like this but that solution can never apply to mine. In my game for a limited time, similar objects keep falling from top until the time ends. Is there any possible way to solve this issue. I have tried using bool variable like didCollide inside collision detection method and even in a separate score incrementing method but the issue does not get resolved.
Here is the code I am trying in collision detection method.
-(void)didBeginContact:(SKPhysicsContact *)contact {
if (contact.bodyA.categoryBitMask == Stones) {
[contact.bodyA.node removeFromParent];
if (contactOccurred == NO) {
contactOccurred = YES;
[self updateScore:contactOccurred];
}
}
else {
[contact.bodyB.node removeFromParent];
if (contactOccurred == NO) {
ContactOccurred = YES;
[self updateScore:contactOccurred];
}
}
}
Code snippet for the method to increment score is here.
-(void)updateScore:(BOOL)collisionOccurred {
if (collisionOccurred == YES) {
contactOccurred = NO;
self.score= self.score + 1;
}
}
I have solved the issue myself after some reading from Apple's documentation and experimenting different options. Issue was that the didBeginContact method that is a default method provided by SpriteKit to detect contacts and collisions, was called multiple times as Joern tried to explain in his answer. But objects involved in collision in my game are not of irregular shapes. One kind of objects are oval shaped while the other kind of object is of more or less rectangular shape.Yet the method was being called more than once whenever the contact was made between two objects.
How did I solve it?
I tried applying the technique Joern suggested although I knew it wasn't the real solution I was looking but more of a temporary cover up. But surprisingly it did not work for my game as score would still increment randomly. I removed my oval shaped sprites and replaced them with simple round solid colour sprites just in case my oval shaped sprites were not smooth near the edges. Even then the problem continued that led me to Apple's documentation on this link a link. I came to know that to have best performance from a physical body and better accuracy for collision detection, one should go for simpler physical bodies when possible. A Circular physical body is most performance efficient as it is pretty fast to process and the simplest. Rectangular physics body comes next, followed by a polygonal physics body and physics body from an image texture on last. More complex the phycis body is, more is going to be computational cost and chances of losing accuracy increase. I had created physical bodies of my colliding objects using image texture. Physical bodies created from texture somehow were the cause (or at least in my case) why didContactMethod was being called multiple times. Even physical body of a simple round sprite created from texture was incrementing score by 2 instead of 1. I changed the code to create physical bodies of circular shape for my oval shaped sprites and everything is perfect now without needing to change category for to be removed nodes or any boolean flag.
Avoiding multiple calls to didBeginContact method by use of Boolean flags or any other way can be a cover up but not the solution which works in few cases but won't work in others. Try using simplest physics bodies where possible especially when you start getting inaccurate results from collisions and contacts.
When you are using SKSpriteNodes whose SKPhysicsBodies have irregular shapes they can have more than one contact point when they are touching. That's why didBeginContact can be called multiple times for the same two SKSpriteNodes before the Node is removed from its parent.
See this example for a contact with 2 contact points (which causes didBeginContact to be called twice for the same two objects):
To avoid this you can change the physicsBody's categoryBitMask in didBeginContact so that all following contacts are not recognized any more:
-(void)didBeginContact:(SKPhysicsContact *)contact {
if (contact.bodyA.categoryBitMask == Stones) {
contact.bodyA.categoryBitMask = None
[contact.bodyA.node removeFromParent];
self.score= self.score + 1;
} else if (contact.bodyB.categoryBitMask == Stones) {
contact.bodyB.categoryBitMask = None
[contact.bodyB.node removeFromParent];
self.score= self.score + 1;
}
}
Obviously you have to define the None bitmask value and exclude it from the contactTestBitMask of your basket like SKSpriteNode. That way after changing the categoryBitMask of your Stone SKSpriteNode from Stones to None all further contacts will be ignored.

What is a proper paradigm for having a mutable global value in objective-C

So, let's say that I am displaying an integer myInt value in OneViewController. Then, while a different view is showing, AnotherViewController, I need to increment or decrement myInt.
So the scope needs to be global or at least be able to be accessed by other viewControllers and it needs to be mutable.
I know that properties one way to do this but I haven't been able to get them to work. I have been importing the header file of OneViewController into AnotherViewController but that wasn't what I was missing.
I've gone through several introductory books but multi-view controller variable work wasn't explicitly covered in any of them. Clearly I'm a beginner so please excuse any conceptual misunderstandings.
Doesn't have to be view controllers -- any sort of custom classes.
In FirstClass.h:
#property(whatever) int someIntInFirstClass;
-(void) someMethodInFirstClass;
SecondClass.h
#property(whatever) FirstClass* myParent;
FirstClass.m
SecondClass* second = [[SecondClass alloc] init];
second.myParent = self;
[second startSomething];
SecondClass.m:
[self.myParent someMethodInFirstClass];
int x = self.myParent.someIntInFirstClass;
self.myParent.someIntInFirstClass = x + 1;
Have a look at ReactiveCocoa library and check how the signal pattern works. The library has to offer a lot of things including the scenario you have just mentioned.
https://github.com/ReactiveCocoa/ReactiveCocoa
A bit of a learning curve. But worth!

Creating a Jump action

I'm working in spritekit/IOS where I have a button that runs an action when it is clicked. The button works fine, but my action is terrible. On click I run this action.
actionMove=[SKAction moveTo:CGPointMake(300,300)duration:2.0];
Which then causes my sprite does a spinning flying kick too that location. I was needed a little help cause I tried replacing the y axis with
_sprite.position+10
But it gives me an error.
Thanks
What you need is the action moveByX:y:duration:...
Sort of.
You can do this...
SKAction *rise = [SKAction moveByX:0 y:10 duration:1];
SKAction *fall = [SKAction moveByX:0 y:-10 duration:1];
SKAction *jump = [SKAction sequence:#[rise, fall]];
Then you can run the jump action on your sprite.
This will move the sprite up by 10 points over 1 second and then down by 10 points over 1 second.
However, it will not look like a jump. It will not accelerate or anything.
If you are including something like a jump in your game then you would normally want to have some sort of collision detection with the floor and use forces to move your sprite instead of actions.
Collision detection method
Sprite Kit Physics Engine
There are two general ways you could do this. The easiest (although longest learning curve) is to use SKPhysicsBody and the built in physics engine in SpriteKit.
You would add a SKPhysicsBody to your character and a boundary SKPhysicsBody to the floor.
Then to make the character jump you would use something like...
[character.physicsBody applyImpulse:CGVectorMake(0, 1)];
This will apply an immediate force to the character so it "jumps" in the air. Then with the physics engine you have built in gravity and so the character will start to slow down and fall until it hits the floor again.
There is a bit of setup for this (less than you would think) but once the setup is done the rest is VERY VERY VERY simple.
Manually
To do it manually is another case. This requires no setup but a LOT of maths. The way this works is to use the update: function and then each update cycle calculate what the velocity and position of the character is and to update the position accordingly.
You really don't want to do this though.
Make things really easy for yourself by adding SKPhysicsBody to the things that need to collide (the character and the floor) and then exploit the gravity and applyImpulse. It will make it much easier, it will perform faster and it will look a million times better :D
There you go :
CGPoint pos = _sprite.position;
pos.y = pos.y + 10;
_sprite.position = pos;
If you are going to use force (and physics) to move your player then using impulse will give you better results:
_sprite.physicsBody applyImpulse:CGVectorMake(0, <value>);
The above depends on a number of factors, including gravity value and the mass of the _sprite.physicsBody. Experimenting is the best way to figure out what works here.
If you are not using physics you can use the followPath action and easing to get a somewhat realistic jumping effect (similar to cocos2d's jump to action). A simple example of how this can be implemented as a category method on SKAction:
+ (SKAction *)jumpWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint height:(CGFloat)height {
UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
[bezierPath moveToPoint:startPoint];
CGPoint peak = CGPointMake(endPoint.x - startPoint.x, startPoint.y + height);
[bezierPath addCurveToPoint:endPoint controlPoint1:peak controlPoint2:peak];
SKAction *jumpAction = [SKAction followPath:bezierPath.CGPath asOffset:NO orientToPath:NO duration:.5f];
jumpAction.timingMode = SKActionTimingEaseIn;
return jumpAction;
}

Error removing sprites from a spritesheet in Cocos2D

I'm in the initial building stages of an iphone game, and I'm using sprite sheets to create some random people, each one with sub-sprites for hair, clothing etc.
I'm storing my sprite images in spritesheets using CCSpriteBatchNode. I'm just doing an initial setup test now, where you tap the screen to generate a new random set of people. So the weird thing is, you can tap once and it will remove the old people and replace them with new people, but the second time, it crashes with the error:
"CCSpriteBatchNode doesn't contain the sprite. Can't remove it"
Now I'm sure I've added the sprite to the batch node, in my Person.m constructor I have this line:
[spriteSheet addChild:person];
In my test code in ccTouchesEnded I've got the following code:
//updated with changes suggested by Mazyod and Jer
for(int i=6; i>=0; i--){
Person *per = [_people objectAtIndex:i];
[_people fastRemoveObjectAtIndex:i];
[_spritesheet removeChild:per cleanup:YES];
per = nil;
}
for(int i = 0; i < 7; i++){
Person *per = nil;
per = [Citizen personFromCountry:_country1 WithSpriteSheet:_spritesheet];
per.position = ccp(100 + (50 * i),160);
[_people addObject:per];
[_spritesheet addChild:per];
}
Can anybody suggest what I'm missing? I've read a bunch about spritesheets in cocos2d and am given to understand that removing individual sprites is tricky so I'm sure there's some vital lines I need to add here. Thanks for your help!
Edit: I googled the error and found this thread: http://www.cocos2d-iphone.org/forum/topic/17170 which seems to confirm that Cocos2d thinks I'm not adding the sprite to the spritesheet - but I am, as proven by the fact that the sprites add correctly the first time, just not the second.
One solution is to simply avoid removing the sprites at all, just make them invisible and redraw them with new characteristics when they need to be reused. I'd rather know what the real solution is though because it seems cleaner.
Looks like you need to change
[_people addObject:per];
to
[_people replaceObjectAtIndex:i withObject:per];
In your first loop you are just setting the value of the object in the array to nil, but not removing it from the array. In the second loop you just add it onto the end of the array, but your array already has 7 nils in it.
Let me know if it works.
Well, I could help you clear out one thing for now:
Any CCNode can only be a child to one parent. ie It has to have a single parent.
But, what you have here:
for(int i=0; i<7; i++){
Person *per = [_people objectAtIndex:i];
[self removeChild:per cleanup:YES];
[_spritesheet removeChild:per cleanup:YES];
per = nil;
}
Suggest you are trying to add the person to both the spriteSheet and self at the same time.. Check your Log, it must have something like:
cocos2d: removeChild, child not found.
And from the error you are getting, I am betting that the person is added to self and not to the sprite sheet.
So, how to solve this?
Well, you have to add the person to the spriteSheet as a child, then add the spriteSheet to self as a child. (Actually, the order you add them doesn't matter).
Sort this out, and maybe this problem will go away, or at least it will be clearer so we can help you.
I just want to mention my experience here with this problem and how I solved it.
Remember, you are either trying to remove a child that was never added..
OR
Trying to remove a child TWICE.
This was the case for me. The collision detection in my game was solid (at least I thought). Then randomly, like 1 out of every 7-10 runs... I would get this crash. I realized it was because I had coded my projectiles to be removed once they intersected a target.
I did not however, put a failsafe where IF my tick method detected that it was in collision with MORE then 1 target at a time.
This was because for every projectile, I iterated through each target to check for a collision, then removed the respective projective if collision was detected. So I created a simple BOOL, and set it to YES if it had already collided with a target. Then I only checked for collision if the projectile had not collided with anything.
So... before:
if (CGRectIntersectsRect(projectileRect, targetRect))
{
//code to remove projectile
}
After:
if (CGRectIntersectsRect(projectileRect, targetRect) && projectile.hasHitaTarget == NO)
{
//code to remove projectile
}

Pauses/computation between function execution?

I'm working on a game and the speed of the game is 60fps, giving me about 16ms to execute what I need to execute. What I'm finding tho is that certain code paths are taking a while to execute. At first I thought this must be an issue with memory allocation/deallocation. It could possibly be, but I have implemented object pooling for the more heavyweight objects, and this seems to have had little effect.
I have stripped out the offendingly large objects, and replaced them with a much simpler object, yet it still takes about 3ms to make this object. The simple object consists of two custom objects, 2 arrays, and 2 dictionaries. The large object is of an arbitrary complexity. Making the more complex larger objects seem to take linearly more time, taking up to 20-30ms. In many instances in my game I can make a much more complicated object in a fraction of the time. But somehow these specific locations in code cause a serious slowdown.
I am using the following code to profile my functions (from SO originally):
NSDate* methodStart = [NSDate date];
// My code here.
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(#"[CH] executionTime to create %# = %f", myObject , executionTime );
As best as I can confirm if I do something like the above in an inner and outer function, it looks like there can be a serious slowdown:
Inner function call completed: 4ms
...no code between inner and outer code except timer...
Outer function call completed: 8ms
My current theory is there is 'in-between' computation that occurs between the functions that is causing the serious slowdowns. As I'm new to Obj-C/C I'm not entirely sure what this slowdown could be. It could be threading, it could be because of memory alloc/autorelease/dealloc, or some other kind of unrelated issue. I have attempted to get more info from Instruments with little benefit.
So my question is: Does this sound logical? Is it possible that some kind of computation could be happening between my functions that would take up 2-4ms of cpu on an ipad2? And if my theory isn't possible, any ideas what it could be?
The best way to track down this type of problem is to use Instruments to profile the execution of the code. Often, you can run this against the code on the Mac under the simulator to see where the time is going, however, in this case you may need to profile it on your iPad to be certain.
Remove your NSDate-based profiling code, as NSDate can be a pretty heavy-weight object, especially when you put the results into the autorelease pool, which you are doing here.
If you feel you must do NSDate-based profiling, you should only need to create a single NSDate object and the use:
[methodStart timeIntervalSinceNow]
to calculate the time delta without having to create a separate object and perform a date subtraction operation.