Metal crash upon adding SKSpriteNode to SKEffectNode - ios

> -[MTLDebugRenderCommandEncoder setScissorRect:]:2028: failed assertion (rect.x(0) + rect.width(1080))(1080) must be <= 240
I am getting this crash when adding a simple SKSpriteNode to a SKEffectNode with the following code
SKSpriteNode *warpSprite = [SKSpriteNode spriteNodeWithImageNamed:#"art.scnassets/symbol.png"];
SKEffectNode *entryEffectsNode = [[SKEffectNode alloc] init];
[entryEffectsNode addChild:warpSprite];
[self addChild:entryEffectsNode];
I have not touched these nodes anywhere else in my project, when i change the sprite the value in (must be <=value) changes within the error.
Edit: I have replaced the sprite image with a simple spriteNodeWithColor:Size: and the (<=value) is always twice size of the sprite. Also it should be noted that the SKScene is being used as a overlay in a SceneKit scene.
I have created a seperate SKScene with the following code, which still results in the same error.
#implementation testScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKSpriteNode *testSprite = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(100, 100)];
SKEffectNode *testEffect = [[SKEffectNode alloc] init];
[testEffect addChild:testSprite];
[self addChild:testEffect];
}
return self;
}
#end
Edit 2:
I have just tested the above scene as an overlay on a default SceneKit Project and it crashes with the same error.
Edit 3:
I have reproduced this using swift.
Bug report summited to Apple.

Related

Change Physical body frame in spritekit

I develop an iOS game using SpriteKit (such a helpful framework to quickly make a game). I add texture and configure a physical body for a main character as image
The green rectangle is the frame of the physical body. I'm using the following code to create it
#interface MainCharacter : SKSpriteNode
#end
#implementation MainCharacter
+ (instancetype)mainCharacterAtPosition:(CGPoint)pos {
MainCharacter* mainChar = [[MainCharacter alloc] initWithTexture:[SKTexture textureWithImageNamed:#"stand_up"]];
mainChar.position = pos;
mainChar.xScale = 0.5f;
mainChar.yScale = 0.5f;
return mainChar;
}
- (instancetype)initWithTexture:(SKTexture *)texture {
if (self = [super initWithTexture:texture]) {
self.name = kCharacterName;
self.anchorPoint = CGPointMake(0.5f, 0.0f);
[self standup];
CGSize spriteSize = self.size;
CGPoint center = CGPointMake(spriteSize.width*(self.anchorPoint.x-0.5f), spriteSize.height*(0.5f-self.anchorPoint.y));
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spriteSize center:center];
self.physicsBody.dynamic = NO;
self.physicsBody.categoryBitMask = kCharacterCategory;
self.physicsBody.contactTestBitMask = 0x0;
self.physicsBody.collisionBitMask = 0x0;
}
return self;
}
- (void)standup {
SKAction* standupAction = [SKAction setTexture:self.standupTexture resize:YES];
[self runAction:standupAction];
}
- (void)standdown {
SKAction* standownAction = [SKAction setTexture:self.standdownTexture resize:YES];
[self runAction:standownAction completion:^{
}];
[self performSelector:#selector(standup) withObject:nil afterDelay:1.0f];
}
MainCharacter is a class that inherits from SKSPriteNode, just an convienient class to manage a main character. Stand Up is a first state of the character. I have another state, temporarily called stand down (demonstrate as following image)
I add a swipe down gesture to make character stand down.
The green rectangle also the physical body but it's too large for the character. I want to make a physical body frame as the red rectangle.
Can anyone help me how to make the physical body smaller when my character stand down and enlarge the physical body after it stands up
You can destroy the current physics body self.physicsBody = nil; and then simply create a new one with the new size requirements.
I solve this problem by using 2 nodes for 2 states (as a suggestion): stand up state and stand down state. I named it
standupNode and standdownNode
First, add the standupNode to the game scene. If swipe donw gesture recognize, I remove the standupNode from game scene and add the standdownNode instead. On contrary, removing the standdownNode from the game scene then add the standupNode if character stands up

Tilemap floor NOT display before background picture

I am having a little trouble doing something that is supposed to be very simple.
I cannot get the floor of my tiles to display above a background picture. However I can get all my other game objects to show from my control pad, to my HUD to even coins and monsters set up in the same tile map. Basically everything appears in front the background like I expect the floor of my tilemap so it looks like im walking on air. I have tried many things like changing which layer i add the background picture or the tilemap floor too, or even tried setting it the same way i set my characters but same results. Tilemap floor is always at the back.
Adding my Set up code, Hope it is helpful too solving the problem.
I created this BG sprite since, I wanted my tilemap to scroll vertically or horzi. automatically. So the easiest way I found to do that was to make the tilemap the child of the "bg" and scroll the "bg" hence scrolling the tile map. However, I have tried setting the background as the child of the bg and setting the Z for both of them but that didnt seem to help.
Thanks in advance for any help in solving this
#implementation GameLevelScene
{
SKNode *_worldNode;
SKSpriteNode *bg;
SKSpriteNode *bkg;
}
Init
-(id)initWithSize:(CGSize)size level:(int)level {
if (self = [super initWithSize:size]) {
// [self showBackground];
NSDictionary *levelData = config[#"levels"][level];
//[show background];
if (levelData[#"tmxFile"]) {
[self showBackground];
_tileMap = [ JSTileMap mapNamed:levelData[#"tmxFile"]];
}
//self.backgroundColor = [SKColor colorWithRed:.4 green:.4 blue:.95 alpha:1.0];
// UIImage *bkgb =[UIImage imageNamed:#"land.jpg"];
// self.position=CGPointZero;
// self.anchorPoint=CGPointZero;
// self.backgroundColor=[UIColor colorWithPatternImage:bkgb];
//Above code shows no picture but it changes the color
[self setUpWorld];
[self createChar];
[self controlPadNode];
//[show background];
}
return self;
}
setUpWorld
- (void)setUpWorld
{
bg = [SKSpriteNode spriteNodeWithImageNamed:#"bg3"];
bg.userInteractionEnabled=NO;
bg.anchorPoint = CGPointZero;
bg.zPosition=0;
bg.position = CGPointZero;
bg.name = #"bg";
[self addChild:bg];
_worldNode = [SKNode node];
if (_tileMap) {
[bg addChild:_tileMap];
}
[bg addChild:_worldNode];
self.physicsWorld.contactDelegate = self;
}
create char
- (void)createChar
{
_Layer = [[TmxTileMapLayer alloc]
initWithTmxObjectGroup:[_tileMap
groupNamed:#"LevelOneObjects"]
tileSize:_tileMap.tileSize
gridSize:_bgLayer.gridSize];
[self addChild:_Layer];
}
Create Control
- (SKSpriteNode *)controlPadNode
//-(void)controlPad
{
SKSpriteNode *controlPadNode = [SKSpriteNode spriteNodeWithImageNamed:#"controller.png"];
controlPadNode.position = CGPointMake(100,50);
controlPadNode.name = #"controlPadNode";
controlPadNode.zPosition = 1.0;
[self addChild:controlPadNode];
}
background
-(void)showBackground
{
bkg = [SKSpriteNode spriteNodeWithImageNamed:#"desert_land.jpg"];
bkg.userInteractionEnabled=NO;
bkg.anchorPoint = CGPointZero;
bkg.position = CGPointZero;
bkg.zPosition=-1;
bkg.name = #"bkg";
// [self addChild:bkg];
//[_tileMap addChild:bkg];
// [_worldNode addChild:bkg];
[bg addChild:bkg];
}
Set your bkg.zposition to 1 and set your bg.zPosition to 2.
Also, the whole point of having a tile map is NOT to use a gigantic background picture but to instead use tiles.
** Update **
I just tested your code and ran a sample project myself. I assume you are using the Tiled app for your tiles. I ran variations on parents (self, worldNode, etc...) and zPositions. The bottom line is you cannot do it. Tiled does not have an alpha channel for its background color options. So either the background image is covered by the tile map or, in your case, the background image covers the tile map.
Your possible solutions are to either not use Tiled and place your tiles manually or to look for another tile app which has an alpha channel.
I noticed that where you define the wall properties of the tile if you say
SKSpriteNode* wall =
[SKSpriteNode spriteNodeWithColor:[SKColor greenColor]
size:CGSizeMake(w, h)];
the green color will be uptop of the background. Bit of a dirty fix than an answer

Can a child have multiple parents in Sprite Kit?

I'm working on a Sprite-Kit game and I have a menu that displays all the levels. I've created a locked image that I want to display on levels that are locked, below is the code:
SKSpriteNode *locked = [SKSpriteNode spriteNodeWithImageNamed:#"Locked.png"];
locked.position = CGPointMake(0, 0);
locked.zPosition = 2.0;
locked.size = CGSizeMake(20, 20);
Then I want to display it on all the levels until they are unlocked. This is the code:
SKSpriteNode *level2 = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(40, 40)];
level2.position = CGPointMake(CGRectGetMidX(self.frame)-75, CGRectGetMidY(self.frame)+100);
[level2 addChild:locked];
[_levels addObject:level2];
[self addChild:level2];
But when I tried to display it on the third level:
SKSpriteNode *level3 = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(40, 40)];
level3.position = CGPointMake(CGRectGetMidX(self.frame)-30, CGRectGetMidY(self.frame)+100);
[level3 addChild:locked];
[_levels addObject:level3];
[self addChild:level3];
I ran into an error because locked already had a parent.
Can a child have multiple parents?
If so where am I going wrong?
A SKNode can only have one parent. (Its parent method can only return one thing, after all.)
It also conforms to NSCopying, which means you can copy a node if you need more than one with the copy method. So, you might try something like [level3 addChild:[locked copy]];

Access property of current SKScene?

I'm testing out a few different technologies to integrate into my Sprite Kit-powered game, and I'm stumbling on what I'm sure is a simple task.
The test project I'm using came as part of a framework that integrates Spine with Sprite Kit. Everything is contained (and defined) in a single ViewController (which creates one of four views depending on which option of a UISegmentedControl is currently selected). At the bottom of the screen I have a UISwitch which is hooked up to an action:
-(IBAction)changeCostume:(UISwitch *)sender {
if(sender.on) {
NSLog(#"New costume");
} else {
NSLog(#"Old costume");
}
}
The scene I'm working on is defined like this:
+ (SKScene *) buildAvatarWithSize:(CGSize) size
{
SpineSkeleton *avatar = [DZSpineSceneBuilder loadSkeletonName:#"test-avatar" scale:1]; //json
spSkeleton_setSkinByName(avatar.spineContext->skeleton, "test-avatar");
spSkeleton_setSlotsToSetupPose(avatar.spineContext->skeleton);
DZSpineSceneDescription *sceneDesc = [DZSpineSceneDescription description];
... define animations etc. here...
NSArray *nodes = [sceneDesc buildScene];
SKNode *placeHolder = [SKNode node];
placeHolder.position = CGPointMake(100, size.height);
placeHolder.name = #"root";
... more setup code...
SKScene *scene = [[SKScene alloc] initWithSize:size];
scene.scaleMode = SKSceneScaleModeAspectFill;
scene.backgroundColor = [UIColor whiteColor];
[scene addChild:placeHolder];
return scene;
}
The property I want to access is sceneDesc - I need to modify its contents on the fly, when the UISwitch is pressed. I know that it's possible from within the scene setup code, but I'm having trouble figuring out how to do so once the scene's on screen.
Changing values of this property will alter the SKTexture used in various nodes.
It probably doesn't help that I'm still new to Objective-C, and the setup of the project is rather different to how I've been working so far (splitting up scenes into their own classes, with properties that can be easily accessed programatically).
You can use NSNotificationCenter to send a message to the scene when the switch is pressed.
I actually gave up on trying to access sceneDesc programatically, and just changed the textures of the relevant SKSpriteNodes:
SKSpriteNode *root = (SKSpriteNode *)[placeHolder.children[0] childNodeWithName:#"root"];
SKSpriteNode *arm = (SKSpriteNode *)[root childNodeWithName:#"upper arm"];
SKSpriteNode *upperArm = (SKSpriteNode *)[arm childNodeWithName:#"upper arm"];
SKSpriteNode *lowerArm = (SKSpriteNode *)[[arm childNodeWithName:#"bone3"] childNodeWithName:#"lower arm"];
upperArm.texture = [SKTexture textureWithImageNamed:#"blue_sleeve_upper"];
lowerArm.texture = [SKTexture textureWithImageNamed:#"blue_sleeve_lower"];

SKTexture from UIImage looks different

I'm playing around with SpriteKit and I'm creating a SKTexture from an UIImage, then using SKSpriteNode to add the child to my SKScene (As a background), everything works fine, except that the UIImage looks very different from the original image, I tried to recreate the image in photoshop and the issue still remains, tested on Simulator and real device and different image colors, no changes.
The image format is PNG, and I added through Images.xcassets in Xcode 5
Image, results:
Different image, results:
I'm using the following code in my SKScene subclass:
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
SKTexture *textureGradient = [SKTexture textureWithImage:[UIImage imageNamed:#"Image"]];
SKSpriteNode* spriteGradient = [SKSpriteNode spriteNodeWithTexture:textureGradient];
[self addChild:spriteGradient];
}
return self;
}
What I'm doing wrong?
Any help would be appreciated. :)
Solution:
It was my fault, the image position was wrong, so I changed the position property:
SKTexture *textureGradient = [SKTexture textureWithImage:[UIImage imageNamed:#"Image"]];
SKSpriteNode* spriteGradient = [SKSpriteNode spriteNodeWithTexture:textureGradient];
spriteGradient.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
[self addChild:spriteGradient];

Resources