This is my code to make my background repeat, just one background and it should be repeating forever:
SKTexture* bgTexture = [SKTexture textureWithImageNamed:#"nightbackground"];
bgTexture.filteringMode = SKTextureFilteringNearest;
SKAction* movebgSprite = [SKAction moveByX:-bgTexture.size.width*2 y:0 duration:0.1 * bgTexture.size.width*2];
SKAction* resetbgSprite = [SKAction moveByX:bgTexture.size.width*2 y:0 duration:0];
SKAction* movebgSpritesForever = [SKAction repeatActionForever:[SKAction sequence:#[movebgSprite, resetbgSprite]]];
for( int i = 0; i < 2 + self.frame.size.width / ( bgTexture.size.width * 2 ); ++i ) {
SKSpriteNode* sprite = [SKSpriteNode spriteNodeWithTexture:bgTexture];
[sprite setScale:1.0];
sprite.zPosition = -20;
sprite.position = CGPointMake(self.size.width/2, self.size.height/2);
[sprite runAction:movebgSpritesForever];
[self addChild:sprite];
But it does not repeat forever, it stops after a while. What might be wrong with it?
This case will work in landscape orientation and have the view repeat scrolling infinitely to the left (-x direction). You create two instances of the background SKSPriteNode and place them next to each other. When the first one scrolls completely off the left side of the screen, it is placed to the right of the second background sprite node.
in didMoveToView:
for (int i = 0; i < 2; i++) {
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:#"background"];
bg.anchorPoint = CGPointZero;
bg.position = CGPointMake(i * bg.size.width, 0);
bg.name = #"starBackground";
[self addChild:bg];
}
in the update: loop
[self enumerateChildNodesWithName:#"background" usingBlock:^(SKNode *node, BOOL *stop) {
SKSpriteNode *bg = (SKSpriteNode *)node;
bg.position = CGPointMake(bg.position.x - 1.5, bg.position.y);
if (bg.position.x <= -bg.size.width) {
bg.position = CGPointMake(bg.position.x + bg.size.width * 2, bg.position.y);
}
}];
Related
I am making a game with sprite kit and objective c. Currently I am trying to make my background scroll infinitely. I cannot seem to make this work. Here is my code:
SKAction method
-(void) setUpActions {
SKAction* move = [SKAction moveByX:-landscape.frame.size.width * 2 y:0 duration:2.0];
SKAction* reset = [SKAction moveByX:landscape.frame.size.width * 2 y:0 duration:0.0];
SKAction* moveInfinitely = [SKAction sequence:#[move, reset]];
//background and log Moving Actions
moveOver = [SKAction repeatActionForever:moveInfinitely];
}
SKAction calling method
-(void) runTheAction {
[landscape runAction:moveOver];
}
When I run the app nothing shows up on my screen.
Create two background sprites.
// create 2 background sprites
bg1 = [SKSpriteNode spriteNodeWithImageNamed:#"bg1"];
bg1.anchorPoint = CGPointZero;
bg1.position = CGPointMake(0, 0);
[self addChild:bg1];
bg2 = [SKSpriteNode spriteNodeWithImageNamed:#"bg2"];
bg2.anchorPoint = CGPointZero;
bg2.position = CGPointMake(bg1.size.width-1, 0);
[self addChild:bg2];
Then in update method:
bg1.position = CGPointMake(bg1.position.x-4, bg1.position.y);
bg2.position = CGPointMake(bg2.position.x-4, bg2.position.y);
if (bg1.position.x < -bg1.size.width){
bg1.position = CGPointMake(bg2.position.x + bg2.size.width, bg1.position.y);
}
if (bg2.position.x < -bg2.size.width) {
bg2.position = CGPointMake(bg1.position.x + bg1.size.width, bg2.position.y);
}
This should be pretty straightforward
I have a object in the scene which is determine by:
SKSpriteNode* object = [SKSpriteNode spriteNodeWithTexture:_objectTexture];
[object setScale:2];
object.position = CGPointMake(0, y);
object.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:object.size];
object.physicsBody.dynamic = NO;
then if my character hit it, it will stay there. Now, I want whenever the character hit the object, the object also move its upper half. How it moves depends on the index.
if index value in range 1, object change texture
if index value in range 2, object and character reflex by normal physical contact law
if index value in range 3, object broken into half
I tried to put
object.physicsBody.dynamic = YES;
then I saw it pulled down and disappear by gravity.
How do I set object dynamic and condition to satisfy the above need?
Thanks a lot for your help !
Added (as requested): My delegate method:
#interface MyScene () <SKPhysicsContactDelegate> {
SKSpriteNode* _character;
SKTexture* _object1;
SKTexture* _object2;
SKAction* _moveObjects;
SKNode* _moving;
SKNode* _objects;
BOOL _canRestart;
NSInteger _index;
SKTexture* characterTexture;
SKSpriteNode* _characterSprite;
}
later part (not sure if it is relevant)
-(id)initWithSize:(CGSize)size{
if (self = [super initWithSize:size]) {
/*Setup Scene here */
self.physicsWorld.gravity = CGVectorMake(0.0, -6.0);
self.physicsWorld.contactDelegate = self;
My objects are moved on scence by:
CGFloat distanceToMove = self.frame.size.width + 2 * _object1.size.width;
SKAction* moveObjects = [SKAction moveByX:-distanceToMove y:0 duration:0.01* distanceToMove];
SKAction* removeObjects = [SKAction removeFromParent];
_moveObjectsAndRemove = [SKAction sequence:#[moveObjects,removeObjects]];
Ps: add didBeginContact:
-(void)didBeginContact:(SKPhysicsContact *)contact{
if (_moving.speed > 0) {
//Score node
if ((contact.bodyA.categoryBitMask & scoreCategory) == scoreCategory || (contact.bodyB.categoryBitMask & scoreCategory) == scoreCategory)
{
_score++;
// Add a little visual
[_scoreLabelNode runAction:[SKAction sequence:#[[SKAction scaleTo:1.5 duration:0.1], [SKAction scaleTo:1.0 duration:0.1]]]];
}
else
//Collided with world
{
_moving.speed = 0;
_character.physicsBody.collisionBitMask = worldCategory;
[_character runAction:[SKAction rotateByAngle:M_PI * _character.position.y*0.01 duration:_character.position.y * 0.03] completion:^{_character.speed = 0; }];
....
}
}
You need to set
object.physicsBody.affectedByGravity = NO;
I have an SKSpriteNode which is running an actionForever. This SKSpriteNode is changing the object on a collision the problem is that because the other action is running forever it will change back to that. Is there a way to stop an action?
SKTexture* groundOverlay = [SKTexture textureWithImageNamed:#"layer-5"];
groundOverlay.filteringMode = SKTextureFilteringNearest;
SKAction* moveOverlaySprite = [SKAction moveByX:-groundOverlay.size.width*2 y:0 duration:0.01 * groundOverlay.size.width*2];
SKAction* resetOverlaySprite = [SKAction moveByX:groundOverlay.size.width*2 y:0 duration:0];
moveOverlaySpritesForever = [SKAction repeatActionForever:[SKAction sequence:#[moveOverlaySprite, resetOverlaySprite]]];
for( int i = 0; i < 2 + self.frame.size.width; ++i ) {
// Create the sprite
sprite1 = [SKSpriteNode spriteNodeWithTexture:groundOverlay];
[sprite1 setScale:1.0];
sprite1.position = CGPointMake(i * sprite1.size.width, sprite1.size.height / 2);
[sprite1 runAction:moveOverlaySpritesForever withKey:#"bg2"];
[self addChild:sprite1];
}
I've created this SKSpriteNode which is the moving background in the background. What i would like to is being able to stop all actions which i've done by
[self removeAllAction]
Which works, but not on the moving background why? and how can i obtain this
SKTexture* groundTexture = [SKTexture textureWithImageNamed:#"layer-1"];
groundTexture.filteringMode = SKTextureFilteringNearest;
SKAction* moveGroundSprite = [SKAction moveByX:-groundTexture.size.width*2 y:0 duration:0.02 * groundTexture.size.width*2];
SKAction* resetGroundSprite = [SKAction moveByX:groundTexture.size.width*2 y:0 duration:0];
moveGroundSpritesForever = [SKAction repeatActionForever:[SKAction sequence:#[moveGroundSprite, resetGroundSprite]]];
for( int i = 0; i < 2 + self.frame.size.width; ++i ) {
// Create the sprite
sprite = [SKSpriteNode spriteNodeWithTexture:groundTexture];
[sprite setScale:1.0];
sprite.position = CGPointMake(i * sprite.size.width, sprite.size.height / 2);
[sprite runAction:moveGroundSpritesForever withKey:#"bg"];
[self addChild:sprite];
}
I have this code as my background as a moving background:
SKTexture* bgTexture = [SKTexture textureWithImageNamed:#"nightbackground"];
bgTexture.filteringMode = SKTextureFilteringNearest;
SKAction* movebgSprite = [SKAction moveByX:-bgTexture.size.width*2 y:0 duration:0.1 * bgTexture.size.width*2];
SKAction* resetbgSprite = [SKAction moveByX:bgTexture.size.width*2 y:0 duration:0];
SKAction* movebgSpritesForever = [SKAction repeatActionForever:[SKAction sequence:#[movebgSprite, resetbgSprite]]];
for( int i = 0; i < 2 + self.frame.size.width / ( bgTexture.size.width * 2 ); ++i ) {
SKSpriteNode* sprite = [SKSpriteNode spriteNodeWithTexture:bgTexture];
sprite.position = CGPointMake(self.size.width/2, self.size.height/2);
[sprite runAction:movebgSpritesForever];
[self addChild:sprite];
And I add this code to have to respawning pipes:
SKTexture* _pipeTexture1 = [SKTexture textureWithImageNamed:#"Pipe1"];
_pipeTexture1.filteringMode = SKTextureFilteringNearest;
SKTexture* _pipeTexture2 = [SKTexture textureWithImageNamed:#"Pipe2"];
_pipeTexture2.filteringMode = SKTextureFilteringNearest;
SKNode* pipePair = [SKNode node];
pipePair.position = CGPointMake( self.frame.size.width + _pipeTexture1.size.width * 2, 0 );
pipePair.zPosition = -10;
CGFloat y = arc4random() % (NSInteger)( self.frame.size.height / 3 );
SKSpriteNode* pipe1 = [SKSpriteNode spriteNodeWithTexture:_pipeTexture1];
[pipe1 setScale:2];
pipe1.position = CGPointMake( 0, y );
pipe1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:pipe1.size];
pipe1.physicsBody.dynamic = NO; [pipePair addChild:pipe1];
SKSpriteNode* pipe2 = [SKSpriteNode spriteNodeWithTexture:_pipeTexture2];
[pipe2 setScale:2];
pipe2.position = CGPointMake( 0, y + pipe1.size.height + kVerticalPipeGap );
pipe2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:pipe2.size];
pipe2.physicsBody.dynamic = NO; [pipePair addChild:pipe2];
SKAction* movePipes = [SKAction repeatActionForever:[SKAction moveByX:-1 y:0 duration:0.02]];
[pipePair runAction:movePipes];
[self addChild:pipePair];
For some reason when I add this code the two pipes dont appear but something does push my character back. It just does not show up. If I remove the background code, the pipes appear and it works again? What is the problem.
It's probably this:
pipePair.zPosition = -10;
When adding your background sprites you don't specify any zPosition meaning they'll get the default 0.0 which is visible in front of anything at -10. Your character is pushed back because the physics-bodies are still interacting with each other even if the sprite is covered visually.
pipePair.zPosition = 10; // (or any other positive value)
ought to fix your problem.