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];
Related
> -[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.
I'm trying to position the background all over the scene background, but for some reason it puts it outside of screen.
This is what I used:
SKTexture *backgroundTexture = [self.atlas textureNamed:#"back"];
SKSpriteNode *background = [SKSpriteNode spriteNodeWithTexture:backgroundTexture size:self.view.frame.size];
background.position = (CGPoint) {CGRectGetMidX(self.view.frame), CGRectGetMidY(self.view.frame)};
[self addChild:background];
This is how it puts it:
You need to add your background image to the SKScene view and as such determine the coordinates from self.
SKSpriteNode *backgroundNode = [SKSpriteNode spriteNodeWithImageNamed:#"BackgroundImage"];
backgroundNode.position = CGPointMake(self.size.width/2, self.size.height/2);
backgroundNode.zPosition = 1;
[self addChild:backgroundNode];
Actually the problem was that in the new Xcode 6.3.1 when you create a new scene it adds a SKScene view of some kind, this view is bigger then the iPhone normal screen, maybe it's iPhone 6+ screen size that's why the background image was out of screen bounds. I just had to remove this view file and not reload it from code and then it worked out.
Thanks anyway, the comment above helped me to understand that.
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
So I have an SKSpriteNode which has undergone two SKActions which modify it's shape and coloring however I want to return the modified SKSpriteNode as an SKTexture which I can apply to another SKSpriteNode. This is what I'm currently using.
1) Generate the "modified" laserNode and store it as a property
-(void)generateLaserSprite
{
SKSpriteNode *laserNode = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:#"Laser.png"]];
[laserNode runAction:[SKAction group:#[[SKAction colorizeWithColor:[SKColor redColor] colorBlendFactor:100 duration:0.0],
[SKAction scaleXBy:0.4 y:0.7 duration:0.0],
]]];
_laserSprite = laserNode
}
2) Then a method from the SKScene calls this method to retrieve a copy of the property
-(SKSpriteNode*)retrieveLaserSprite
{
SKSpriteNode *laserNode = [_laserSprite copy];
laserNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(laserNode.size.width*0.8, laserNode.size.height*0.8)];
//other laserNode.physicsBody modifications
return laserNode;
The problem with this currently is that when I call the second method (retrieveLaserSprite), the returned LaserNode then shows up on screen as the original image (pre-SKAction), and then you can visibly see the SKActions take place on-screen.
It should actually be possible to create a texture from a sprite whose rendering properties have been modified using the -(SKTexture *)textureFromNode: method of the SKView class.
Your code would go like this:
-(SKSpriteNode*)retrieveLaserSprite {
SKTexture *tempTexture = [self.view textureFromNode:_laserSprite];
SKSpriteNode *laserNode = [SKSpriteNode spriteNodeWithTexture:tempTexture];
laserNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(laserNode.size.width*0.8, laserNode.size.height*0.8)];
//other laserNode.physicsBody modifications
return laserNode;
}
You should be able to accomplish this task using something like:
-(SKSpriteNode*)retrieveLaserSprite
{
SKTexture *texture = [self.view textureFromNode:[_laserSprite copy]];
SKSpriteNode *laserNode = [SKSpriteNode spriteNodeWithTexture:texture];
laserNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(laserNode.size.width*0.8, laserNode.size.height*0.8)];
//other laserNode.physicsBody modifications
return laserNode;
}
I'm trying to set a background texture and I want it to cover the entire screen.
I prepared the background files exactly to size in photoshop before hand. There are 2 files in my project:
background.png - 1024x768px
background#2x.png - 2048x1536px
I am running the following code:
SKTexture *backgroundTexture = [SKTexture textureWithImageNamed:#"background"];
SKSpriteNode *background = [SKSpriteNode spriteNodeWithTexture:backgroundTexture];
background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
background.size = CGSizeMake(750, 550);
[self addChild:background];
And it is giving me this result http://d.pr/i/Ej2m - notice that the entire screen is almost filled and the background size is background.size = CGSizeMake(750, 550). Why is this?
You manually changed the sprite's size:
background.size = CGSizeMake(750, 550);
So it will display in a smaller region (750x550) than its original size (1024x768). Allow me to say: d'uh! ;)