How to make this building blocks code more flexible / efficient? - ios

The code below stacks bricks on top of each other. When TouchesBegin is called a new brick is added.
I am new to coding. I want the code to be more flexible, so different kind of shapes of bricks can be added too.
Thanks for helping.
CODE
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
if (integer == 0) {
[_previousBrick removeAllActions];
[self spawnNextBrick];
}
if (integer == 1) {
[self spawnPrevBrick];
}
}
-(void)spawnPrevBrick
{
_previousBrick = [SKSpriteNode spriteNodeWithImageNamed:#"TestBridgePiece"];
_previousBrick.anchorPoint = CGPointMake(0.5, 0.0);
_previousBrick.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_previousBrick.frame.size];
_previousBrick.position = CGPointMake(0.0, _nextBrick.position.y + _previousBrick.size.height);
_previousBrick.physicsBody.categoryBitMask = bridgeCategory;
_previousBrick.physicsBody.contactTestBitMask = leftEdgeCategory | rightEdgeCategory | newBrickNotificator;
_previousBrick.physicsBody.collisionBitMask = bridgeCategory;
_isPreviousBrick = YES;
[_previousBrickLayer addChild:_previousBrick];
}
-(void)spawnNextBrick
{
_nextBrick = [SKSpriteNode spriteNodeWithImageNamed:#"TestBridgePiece"];
_nextBrick.anchorPoint = CGPointMake(0.5, 0.0);
_nextBrick.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_nextBrick.frame.size];
_nextBrick.position = CGPointMake(self.size.width, _previousBrick.position.y + _nextBrick.size.height);
_nextBrick.physicsBody.contactTestBitMask = leftEdgeCategory | rightEdgeCategory | newBrickNotificator;
_nextBrick.physicsBody.collisionBitMask = bridgeCategory;
_isPreviousBrick = NO;
[_previousBrickLayer addChild:_nextBrick];
}
-(void)update:(CFTimeInterval)currentTime {
if (_isPreviousBrick == NO) {
integer = 1;
}
if (_isPreviousBrick == YES) {
integer = 0;
}
NSLog(#"integer = %i", integer);
}

Related

iOS SpriteKit - ray(line) is reflected from bounds

We have line(ray) which moves to bounds and reflects when bound is reached. These images demonstrates the dynamic of movement and reflections.
And i'd like to implement it in SpriteKit(obj-c is prefer) but don't understand from which point I should start.
I found how to implement it. Hope it'll be useful for others
#import "GameScene.h"
static const float GUIDE_MASS = .0015;
static const int SEGMENTS_COUNT = 10;
static const int SEGMENT_LENGTH = 5;
#interface GameScene(private)
-(void) createGuidesAndShot;
#end
#implementation GameScene
SKShapeNode *shot;
NSMutableArray* shotSegments;
-(void)didMoveToView:(SKView *)view {
[self setBackgroundColor:[SKColor whiteColor]];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
}
-(void)update:(CFTimeInterval)currentTime {
CGMutablePathRef pathToDraw = CGPathCreateMutable();
if (shotSegments!=nil) {
bool isFirst = YES;
for (SKNode* segment in shotSegments) {
if(isFirst){
CGPathMoveToPoint(pathToDraw, NULL,
segment.position.x,
segment.position.y);
isFirst =NO;
} else {
CGPathAddLineToPoint(pathToDraw, NULL,
segment.position.x,
segment.position.y);
}
}
shot.path = pathToDraw;
}
}
-(void)didBeginContact:(SKPhysicsContact *)contact {
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (shotCategory|screenBoundsCategory)){
}
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
shotSegments = [NSMutableArray new];
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
SKPhysicsBody* borderBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody = borderBody;
self.physicsBody.friction = 0.0f;
self.physicsBody.categoryBitMask = screenBoundsCategory;
self.physicsBody.contactTestBitMask = shotCategory;
self.physicsWorld.contactDelegate = self;
[self createGuidesAndShot];
}
return self;
}
-(void) createGuidesAndShot{
for (int i = 0; i<SEGMENTS_COUNT*SEGMENT_LENGTH; i+=SEGMENT_LENGTH) {
SKShapeNode* guide = [SKShapeNode shapeNodeWithCircleOfRadius:1];
guide.position = CGPointMake(self.frame.size.width/2+i,
self.frame.size.height/2-i);
// guide.fillColor = [SKColor blackColor];
guide.name = [NSString stringWithFormat:#"guide%i", i];
[self addChild:guide];
[shotSegments addObject:guide];
guide.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:guide.frame.size.width/2];
guide.physicsBody.friction = 0.0f;
guide.physicsBody.restitution = 1.0f;
guide.physicsBody.linearDamping = 0.0f;
guide.physicsBody.allowsRotation = NO;
guide.physicsBody.categoryBitMask = shotCategory;
guide.physicsBody.contactTestBitMask = screenBoundsCategory;
guide.physicsBody.collisionBitMask = screenBoundsCategory;
guide.physicsBody.mass = GUIDE_MASS;
[guide.physicsBody applyImpulse:CGVectorMake(0.1f, -0.1f)];
}
shot = [SKShapeNode node];
[shot setStrokeColor:[UIColor redColor]];
[self addChild:shot];
}
#end

Removing specific nodes in SpriteKit

Need some help as a beginner: I've got different nodes: 4 squares (sprite1) and 1 counter (counterLabel, counts the nodes, which have been removed). I want to remove the 4 squares by touching them. With the code below the squares can be removed, but also the counter. Strangely enough, because I tried to address the square nodes (sprite1) exclusively. Is there any possibility to remove the square nodes (sprite 1) exclusively?
#implementation GameScene {
BOOL updateLabel;
SKLabelNode *counterLabel;
}
int x;
int y;
int counter;
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]){
self.backgroundColor = [SKColor /*colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0*/ whiteColor];
counter = 0;
updateLabel = false;
counterLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
counterLabel.name = #"myCounterLabel";
counterLabel.text = #"0";
counterLabel.fontSize = 48;
counterLabel.fontColor = [SKColor greenColor];
//counterLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
//counterLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeBottom;
counterLabel.position = CGPointMake(50,50); // change x,y to location you want
//counterLabel.zPosition = 900;
[self addChild: counterLabel];
}
return self;
}
-(void) didMoveToView:(SKView *)view {
SKTexture *texture1 = [SKTexture textureWithImageNamed:#"square"];
for (int i = 0; i < 4; i++) {
x = arc4random()%668;
y = arc4random()%924;
SKSpriteNode *sprite1 = [SKSpriteNode spriteNodeWithTexture:texture1];
sprite1.position = CGPointMake(x, y);
sprite1.name = #"square";
[self addChild:sprite1];
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint: [touch locationInNode: self]];
for (SKNode *sprite1 in nodes) {
[sprite1 removeFromParent];
counter ++;
updateLabel = true;
}
}
-(void)update:(CFTimeInterval)currentTime {
if(updateLabel == true){
counterLabel.text = [NSString stringWithFormat:#"%i",counter];
updateLabel = false;
}
}
#end
you should use the property name of SKSpriteNode
in this case you can do:
for (SKNode *sprite1 in nodes) {
if(![sprite1.name isEqualToString:#"myCounterLabel"]) {
[sprite1 removeFromParent];
}
counter ++;
updateLabel = true;
}
So if the SKNode name is different to the name of counterLabel, then removeFromParent.

Updating a node's position while adding new ones?

I have a enemy node that moves by updating its position in the update method, I add new nodes in a set interval, when two of the same nodes appear, the most recent one updates its position and the last node doesn't update its position, how do I write my code accordingly to update all the positioning of my enemy nodes when I add more?
The Enemy Method
-(void)Enemies {
SKTexture *pM1 = [SKTexture textureWithImageNamed:#"enemy-1"];
enemy = [SKSpriteNode spriteNodeWithTexture:pM1];
enemy.zPosition = 8;
enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemy.size];
enemy.physicsBody.categoryBitMask = fEnemyCategory;
enemy.physicsBody.contactTestBitMask = fPlatformCategory | fMainPlatformCategory | fPlayerCategory | fPitOfCertainDoomCategory;
enemy.physicsBody.collisionBitMask = fPlatformCategory | fPlayerCategory | fEnemyCategory;
enemy.physicsBody.allowsRotation = NO;
enemy.physicsBody.friction = 0.3;
enemy.physicsBody.linearDamping = 0.7;
enemy.physicsBody.dynamic = YES;
enemy.physicsBody.affectedByGravity = YES;
enemy.physicsBody.usesPreciseCollisionDetection = YES;
enemy.position = CGPointMake(CGRectGetMidX(self.frame) + 30, CGRectGetMidY(self.frame));
enemy.position = CGPointMake(730, enemy.position.y - 129);
NSLog(#"Spawned");
[self addChild:enemy];
[enemy runAction:runAnimation];
}
Update Method
-(void)update:(CFTimeInterval)currentTime {
if (gameStart == YES & gameOver == NO) {
if (enemyExists == YES) {
if (switchMovement == NO) {
enemy.position = CGPointMake(enemy.position.x - 3.66, enemy.position.y);
}
else if (switchMovement == YES) {
enemy.position = CGPointMake(enemy.position.x + 2.83, enemy.position.y);
}
}
This is how you would implement what #LearnCocos2D has mentioned. I make no promises on casting the object as a spritenode properly ;)
Define Array:
NSMutableArray *array = [NSMutableArray alloc] init];
Add Enemy to Array:
[array addObject:myObject]; //Directly after [self addChild:enemy];
New Update:
-(void)update:(CFTimeInterval)currentTime {
if (gameStart == YES & gameOver == NO)
{
for (NSObject* o in array1)
{
SKSpriteNode enemyTemp = (SKSpriteNode*)o;
if (switchMovement == NO)
{
enemyTemp.position = CGPointMake(enemyTemp.position.x - 3.66, enemy.position.y);
}
else if (switchMovement == YES)
{
enemyTemp.position = CGPointMake(enemyTemp.position.x + 2.83, enemy.position.y);
}
}
}

How can I keep track of how many times a sprite has been touched in cocos2d?

In my program, I have sprites fall from the top of the screen and the user taps each sprite to keep them from falling to the ground, which results in game over. These sprites are in the shape of stars.
My question is, how can I keep track of how many times each star has been tapped, so when a user taps the star 3 times, it disappears?
I currently have 2 different types of stars fall from the sky, and whenever they are added to the game, they are added into an array. Hopefully my code explains what I'm doing.
I'm new to objective C, so please feel free to let me know what else is wrong in my code... looking to get better!
#import "MainScene.h"
#import <CoreGraphics/CGGeometry.h>
#include <stdlib.h>
#import "Star.h"
#import "redStar.h"
#implementation MainScene {
CCSprite *_star;
CCSprite *_redStar;
CCPhysicsNode *_physicsNode;
CCNode *_ground;
CCNode *_leftWall;
CCNode *_rightWall;
CCNode *_ceiling;
CCLabelTTF *_scoreLabel;
NSInteger _points;
BOOL _gameOver;
CCButton *_restartButton;
NSInteger _taps;
NSMutableArray *_allStars;
NSInteger _rando;
}
- (void)didLoadFromCCB {
_rando = (arc4random_uniform(1000));
self.userInteractionEnabled = TRUE;
self.starList = [NSMutableArray array];
[self addNewStar];
// set collision txpe
_ground.physicsBody.collisionType = #"level";
// set this class as delegate
_physicsNode.collisionDelegate = self;
}
-(void)addNewStar {
float ranNum01 = (arc4random_uniform(200)+60);
float pos1 = ranNum01;
_star = (Star *)[CCBReader load:#"Star"];
_star.physicsBody.collisionGroup = #"starGroup";
_star.physicsBody.collisionType = #"star";
_star.position = ccp(pos1,500);
[_physicsNode addChild:_star];
[self.starList addObject:_star];
}
-(void)addRedStar {
float ranNum01 = (arc4random_uniform(200)+60);
float pos1 = ranNum01;
_redStar = (redStar *)[CCBReader load:#"redStar"];
_redStar.physicsBody.collisionGroup = #"starGroup";
_redStar.physicsBody.collisionType = #"star";
_redStar.position = ccp(pos1,500);
[_physicsNode addChild:_redStar];
[self.starList addObject:_redStar];
}
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair star:(CCNode *)star level:(CCNode *)level {
[self gameOver];
return TRUE;
}
- (void)update:(CCTime)delta {
// clamp velocity. -1*MAXFLOAT means no falling speed limit.
float yVelocity = clampf(_star.physicsBody.velocity.y, -1 * MAXFLOAT, 1000.f);
_star.physicsBody.velocity = ccp(0, yVelocity);
}
- (void)starDropper
{
if (_taps == 0)
{
return;
}
if ((_taps + (_rando)) % 5 == 0)
{
[self addNewStar];
}
if ((_taps + (_rando)) % 8 == 0)
{
[self addRedStar];
}
}
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
float ranNum1 = (arc4random_uniform(100));
float ranNum2 = (arc4random_uniform(100));
float sideForce = ranNum1 - ranNum2;
self._tappedStar = NO;
if (!_gameOver) {
for (_star in self.starList) {
CGPoint touchLocation = [touch locationInNode:_physicsNode];
if(CGRectContainsPoint([_star boundingBox], touchLocation)) {
[_star.physicsBody applyImpulse:ccp(sideForce, 2500.f)];
[_star.physicsBody applyAngularImpulse:2500.f];
self._tappedStar = YES;
_taps++;
_points++;
_scoreLabel.string = [NSString stringWithFormat:#"%d", _points];
}
}
if (self._tappedStar == NO)
{
return;
}
if (self._tappedStar == YES)
{
[self starDropper];
}
}
}
- (void)restart {
CCScene *scene = [CCBReader loadAsScene:#"MainScene"];
[[CCDirector sharedDirector] replaceScene:scene];
}
- (void)gameOver {
if (!_gameOver) {
_gameOver = TRUE;
_restartButton.visible = TRUE;
_star.rotation = 90.f;
_star.physicsBody.allowsRotation = FALSE;
[_star stopAllActions];
CCActionMoveBy *moveBy = [CCActionMoveBy actionWithDuration:0.2f position:ccp(-2, 2)];
CCActionInterval *reverseMovement = [moveBy reverse];
CCActionSequence *shakeSequence = [CCActionSequence actionWithArray:#[moveBy, reverseMovement]];
CCActionEaseBounce *bounce = [CCActionEaseBounce actionWithAction:shakeSequence];
[self runAction:bounce];
}
}
#end
UPDATE: I think I'm close..this is what I've got, but I must be missing something because the stars still won't disappear...ALSO - "world" is an undeclared identifier - not sure how to identify
#implementation MainScene {
CCSprite *touchedStar;
CCSprite *_star;
CCSprite *_redStar;
CCSprite *oneTappedStar;
CCSprite *twoTappedStar;
CCSprite *threeTappedStar;
CCPhysicsNode *_physicsNode;
CCLabelTTF *_scoreLabel;
NSInteger _points;
BOOL _gameOver;
CCButton *_restartButton;
NSInteger _rando;
CCActionFadeIn *fadeIn;
}
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
float ranNum1 = (arc4random_uniform(100));
float ranNum2 = (arc4random_uniform(100));
float sideForce = ranNum1 - ranNum2;
self._tappedStar = NO;
if (!_gameOver) {
for (_star in self.starList) {
CGPoint touchLocation = [touch locationInNode:_physicsNode];
if(CGRectContainsPoint([_star boundingBox], touchLocation))
{
[_star.physicsBody applyImpulse:ccp(sideForce, 2500.f)];
[_star.physicsBody applyAngularImpulse:2500.f];
self._tappedStar = YES;
_taps++;
_points++;
_scoreLabel.string = [NSString stringWithFormat:#"%d", _points];
// starTaps++;
if (touchedStar == threeTappedStar) {
[self removeChild:touchedStar];
world->DestroyBody(touchedStar.physicsBody);
}
//3
if (touchedStar == twoTappedStar) {
touchedStar = threeTappedStar;
}
//2
if (touchedStar == oneTappedStar) {
touchedStar = twoTappedStar;
}
//1
if (touchedStar == _star) {
touchedStar = oneTappedStar;
}
}
}
if (self._tappedStar == NO)
{
return;
}
if (self._tappedStar == YES)
{
[self starDropper];
}
}
}
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
float ranNum1 = (arc4random_uniform(100));
float ranNum2 = (arc4random_uniform(100));
float sideForce = ranNum1 - ranNum2;
CCSprite *starTouched;
if (!_gameOver) {
for (starTouched in starList) {
CGPoint touchLocation = [touch locationInNode:_physicsNode];
if(CGRectContainsPoint([starTouched boundingBox], touchLocation)) {
[starTouched.physicsBody applyImpulse:ccp(sideForce, 2500.f)];
[starTouched.physicsBody applyAngularImpulse:2500.f];
_taps++;
_points++;
_scoreLabel.string = [NSString stringWithFormat:#"%ld", (long)_points];
if (starTouched.scale == 1.000002) {
[_physicsNode removeChild:starTouched];
CCLOG(#"DESTROY");
}
if (starTouched.scale == 1.000001) {
starTouched.scale = 1.000002;
CCLOG(#"2");
}
// FOR DIFFERENT TYPE OF STARS
//star
if (starTouched == _star) {
starTouched.scale = 1.000001;
CCLOG(#"1");
}
//redStar
if (starTouched == _redStar) {
starTouched.scale = 1.000001;
CCLOG(#"1");
}
}
}
}
}

sprite not updating to the correct position

I have written a code to display using CCLog the exact position of a sprite when a mousejoint moving it is released. Below is the Sprite.mm class and the ccTouchesEnded method (which is in the HelloWorldLayer.mm class). The sprite position is not updating, the output is constantly x: 0.00 and y: 0.00.
Sprite.mm:
-(id)addSprite:(CCLayer *)parentLayer
inWorld:(b2World *)world
{
PhysicsSprite *aSprite = [PhysicsSprite spriteWithFile:#"spriteIm.png"];
aSprite.tag = 1;
[parentLayer addChild:aSprite];
b2BodyDef spriteBodyDef;
spriteBodyDef.userData = aSprite;
spriteBodyDef.type = b2_dynamicBody;
CGSize s = [CCDirector sharedDirector].winSize;
spriteBodyDef.position = [Convert toMeters:ccp(s.width * 0.25,s.height-400)];
b2FixtureDef fixtureDef;
fixtureDef.density = 0.01;
b2CircleShape circleShape;
circleShape.m_radius = aSprite.contentSize.width/2 / PTM_RATIO;
fixtureDef.shape = &circleShape;
spriteBody = world->CreateBody( &spriteBodyDef );
spriteFixture = spriteBody->CreateFixture( &fixtureDef );
[aSprite setPhysicsBody:spriteBody];
return aSprite;
}
ccTouchesEnded:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (mouseJoint)
{
for(b2Body *b = world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *mySprite = (CCSprite *)b->GetUserData();
if (mySprite.tag == 1) {
CGPoint spritePosition = mySprite.position;
CCLOG(#"the sprite position is x:%0.2f, y:%0.2f", spritePosition.x, spritePosition.y);
}
}
}
world->DestroyJoint(mouseJoint);
mouseJoint = NULL;
}
}
Please help. I've been at it for a few days.
I finally managed to get it working. I guess the x:0.00 and y:0.00 were because I was taking the position of the sprite not the body. The sprite is parented to the body so it was giving its position inside it's parent, which is 0,0. This is how I understand it. Here are the changes I made to the ccTouchesEnded code.
ccTouchesEnded:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (mouseJoint)
{
for(b2Body *b = mouseJoint->GetBodyB(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL)
{
CCSprite *mySprite = (CCSprite*)b->GetUserData();
if (mySprite.tag == 1) {
mySprite.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
CCLOG(#"the sprite postion is x:%0.2f , y:%0.2f", mySprite.position.x, mySprite.position.y);
}
}
}
world->DestroyJoint(mouseJoint);
mouseJoint = NULL;
}
}

Resources