I'm using Cocos3D.
There i've a list of different CC3Nodes. I want to put an image next to each of it.
My problem is: how to create a new CC3Node and add it as a Child.
You need to doing something like this:
CC3PlaneNode *imageNode = [CC3PlaneNode nodeWithName:#"One Plane Node on 3D Object"];
[imageNode populateAsCenteredRectangleWithSize: CGSizeMake(200.0, 200.0)
andTessellation:ccg(40, 40) withTexture: [CC3Texture textureFromFile:#"Your Image Address"] invertTexture: YES];
imageNode.material.specularColor = kCCC4FLightGray;
imageNode.shouldCullBackFaces = NO;
[imageNode retainVertexLocations];
[self addChild:imageNode];
And for doing this for each Node:
CC3PlaneNode *newImageNode = [imageNode copyWithName:#"New Node Name"];
...
[self addChild:newImageNode];
At the end of it, if you want to add these node each node as a child do:
[previousNode addChild:newNode];
instead of:
[self addChild:newNode];
I hope it works for you!
Related
I'm using a virtual joystick for SpriteKit, and it works great. I have tried either JCInput version, or SpriteKit-Joystick version. Both were used for the movement, and used them on the left.
This is the code I used, although the documentation is very good in the gitHub anyway:
For JCInput version:
self.joystick = [[JCJoystick alloc] initWithControlRadius:40 baseRadius:45 baseColor:[SKColor blueColor] joystickRadius:25 joystickColor:[SKColor redColor]];
[self.joystick setPosition:CGPointMake(70,70)];
[self addChild:self.joystick];
and the update function:
-(void)update:(CFTimeInterval)currentTime {
[self.myLabel1 setPosition:CGPointMake(self.myLabel1.position.x+self.joystick.x, self.myLabel1.position.y+self.joystick.y)];
[self.myLabel2 setPosition:CGPointMake(self.myLabel2.position.x+self.imageJoystick.x, self.myLabel2.position.y+self.imageJoystick.y)];
/* Called before each frame is rendered */
}
And for the SpriteKit-Joystick version:
SKSpriteNode *jsThumb = [SKSpriteNode spriteNodeWithImageNamed:#"joystick"];
[jsThumb setScale:0.5f];
SKSpriteNode *jsBackdrop = [SKSpriteNode spriteNodeWithImageNamed:#"dpad"];
[jsBackdrop setScale:0.5f];
self.joystick = [Joystick joystickWithThumb:jsThumb andBackdrop:jsBackdrop];
self.joystick.position = CGPointMake(50,50);
[self addChild:self.joystick];
//I've already declared it in the header file
velocityTick = [CADisplayLink displayLinkWithTarget:self selector:#selector(joystickMovement)];
[velocityTick addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
and the update function:
-(void)joystickMovement
{
if (self.joystick.velocity.x != 0 || self.joystick.velocity.y != 0)
{
[self.myLabel1 setPosition:CGPointMake(self.myLabel1.position.x+.1 *self.joystick.velocity.x, self.myLabel1.position.y+.1 * self.joystick.velocity.y)];
}
}
Now everything works perfectly, and don't have any issue with it. But I need to add another one to rotate my character (let's call it the self.myLabel1). I tried duplicating the object creation (with unique names, parameters and positions to put them to the right side of the screen, but other bits of code being exactly the same as what I used above).
They also work, but the problem is that they don't work simultaneously. I can either use the left one or the right one at any given time, and not together. Do I need to run them on two separate thread? I've tried using two CADisplayLinks with two separate Selectors, and nothing. I tried using the same one, and nothing.
Can anyone shed some light on this shadow?
Thanks a lot in advance.
You should be overriding update in your SKScene instead of using CADisplayLink. You can call joystickMovement from update and achieve the desired effect.
You can read more about the different methods called as SKScene processes each frame in the SKScene class reference.
If you haven't already, you'll also need to set multipleTouchEnabled to true in your SKScene's view. You can do this from your GameViewController with
self.view.multipleTouchEnabled = YES;
I am having a hard time trying to implement click handling in a simple isometric Sprite Kit game.
I have a Game Scene (SKScene) with a Map (SKNode) containing multiple Tile objects (SKSpriteNode).
Here is a screenshot of the map :
I want to be able to detect the tile the user clicked on, so I implemented mouseDown on the Tile object. Here is my mouseDown in Tile.m :
-(void)mouseDown:(NSEvent *)theEvent
{
[self setColorBlendFactor:0.5];
}
The code seems to work fine but there is a glitch : the nodes overlap and the click event is detected on the transparent part of the node. Example (the rects have been added to illustrate the problem only. They are not used in the logic) :
As you can see, if I click on the top left corner of the tile 7, the tile 8 becomes transparent.
I tried something like getting all the nodes at click location and checking if click is inside a CGPath without success (I think there was something wrong in the coordinates).
So my question here is how to detect the click only on the texture and not on the transparent part? Or maybe my approach of the problem is wrong?
Any advice would be appreciated.
Edit : for anyone interested in the solution I finally used, see my answer here
My solution for such a problem 'right now' is:
in your scene get all nodes which are in that position of your click, i.e.
[myScene nodesAtPoint:[theEvent lactionInNode:myScene]]
don't forget to check if your not clicking the root of your scene
something like that:
if (![[myScene nodeAtPoint:[theEvent locationInNode:myScene]].name isEqual: #"MyScene"])
then go through the Array of possible nodes and check the alpha of the Texture (NOT myNode.alpha)
if the alpha is 0.0f go to the next node of your Array
pick the first node which alpha is not 0.0f and return the nodes name
this way you can find your node (first) and save it, as the node you need, and kill the array, which you don't need anymore
than do what you want with your node
btw check if your new node you wish to use is nil after searching for its name. if thats true, just break out of your moveDown method
To get the alpha try this.
Mine looks something like that:
-(void)mouseDown:(NSEvent *)theEvent {
/* Called when a mouse click occurs */
if (![[self nodeAtPoint:[theEvent locationInNode:self]].name isEqual: self.name]]) {
/* find the node you clicked */
NSArray *clickedNodes = [self nodesAtPoint:[theEvent locationInNode:self]];
SKNode *clickedNode = [self childNodeWithName:[clickedNodes getClickedCellNode]];
clickedNodes = nil;
/* call the mouseDown method of your Node you clicked to to node specific actions */
if(clickedNode) {
[clickedNode mouseDown:theEvent];
}
/* kill the pointer to your clicked node */
clickedNode = nil;
}
}
For simple geometries like yours, a workaround would be to superimpose invisible SKShapeNodes on top of your diamonds, and watch for their touches (not for the skspritenode ones).
If this still does not work, make sure you create the SKPhysicsBody using the "fromPolygon: myNode.path!" option...
i have some problem with bugs [SKPhysicsWorld enumerateBodiesAtPoint].
But i found my solution and it will work for you too.
Create tile path (your path 4 points)
Catch touch and convert point to your tile node
if touch point inside shape node - win!
CODE:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
selectedBuilding = nil;
NSArray *nodes = [farmWorldNode nodesAtPoint:point];
if (!nodes || nodes.count == 0 || nodes.count == 1) {
return;
}
NSMutableArray *buildingsArray = [NSMutableArray array];
int count = (int)nodes.count;
for (int i = 0; i < count; i++) {
SKNode *findedBuilding = [nodes objectAtIndex:i];
if ([findedBuilding isKindOfClass:[FBuildingBaseNode class]]) {
FBuildingBaseNode *building = (FBuildingBaseNode *)findedBuilding;
CGPoint pointInsideBuilding = [building convertPoint:point fromNode:farmWorldNode];
if ([building.colisionBaseNode containsPoint:pointInsideBuilding]) {
NSLog(#"\n\n Building %# \n\n ARRAY: %# \n\n\n", building, findedBuilding);
[buildingsArray addObject:building];
}
}
}
selectedBuilding = (FBuildingBaseNode *)[buildingsArray lastObject];
buildingsArray = nil;
}
i have a ccmenuitemfont and its contained inside a ccsprite. .
the touch event is assigned to menuitemfont.. i need to get the reference of the ccsprite which contains the menuitemfont on ccmenuitemfont click... that is i need to get the reference of the parent sprite.. how to implement? any ideas ? the code i used is as follows..
CCSprite *ballSprite=[CCSprite spriteWithFile:imageName];
[ballSprite setTag:randomNumber];
CCMenuItem *labelButton=[CCMenuItemFont itemFromString:[NSString stringWithFormat:#"%d",randomNumber]target:self selector:#selector(clickedBallLabel :)];
[labelButton setTag:randomNumber];
CCMenu *ball=[CCMenu menuWithItems:labelButton, nil];
[ball setPosition:ccp([ballSprite boundingBox].size.width/2, [ballSprite boundingBox].size.height/2)];
[ballSprite addChild:ball];
[self addChild:ballSprite];
[ballSprite setPosition:randomStartPoint];
id move = [CCMoveTo actionWithDuration:5 position:ccp(randomX, -30)];
[ballSprite runAction:move];
in my point of view , there is a logic problem in you program,you want your labelbutton have a recation right? when your touch it,so why you need a reference to parent with the button?but if there is a must for sure ,you need a spritesheet like this :
[[CCSpriteFrameCache sharedSpriteFrameCache]addSpriteFramesWithFile:#"scene1atlas.plist"];
spriteBatchNode = [CCSpriteBatchNode batchNodeWithFile:#"scene1atlas.png"];
then you can add your obj into the batchnode,after that you can use [obj parent] get the parent reference
i'm not sure i know what your meaning,when the button been touched,the ballsprite should be changed?if so,you can just change the ballsprite directly for another new sprite,of course,the better way is the sprites should be into one batchnode as much as possible, otherwise,if your ballsprite is a spritesheet ,then use the method i've told before
This is pretty simple question, but I'm having really hard time with it.
I have made a method which takes int variable. With it, it would need to use it to do action with CCSprite.
For example I call it with this: [_hud hideThisActionLed:2]; and it should then hide CCSprite named actionLed2.
I can't pass the actual CCSprite to the method, because I call it from another class which don't have access to that particular sprite.
I can make the sprite name with this: [NSString stringWithFormat:#"actionLed%d", actionLedNumber], but can't come up with a way to use that to point to that specified CCSprite.
Here's how I declared the sprites in hud class:
actionLed1 = [CCSprite spriteWithFrameName:#"actionLed1.png" setScale:TRUE resetAnchor:TRUE];
[actionLed1 setOpacity:0];
[self addChild: actionLed1 z:11 tag:1];
That x4 for all 4 leds.
This depends on how can access the different leds.
If they are properties inside your class, then you can access them like this:
NSString *actionLedName = [NSString stringWithFormat:#"actionLed%d", actionLedNumber];
CCSprite *actionLed = [self valueForKey:actionLedName];
If they are stored in an array, then you can access them like this:
CCSprite *actionLed = [self.actionLeds objectAtIndex:actionLedNumber];
If you have set up a tag for each actionLed when adding it, then you can access them like this:
CCSprite *actionLed = [self getChildByTag:actionLedNumber];
When you add the CCSprite objects to your layer, use the withTag option. Then you can reference the sprites by the tag number which is the number you pass in to the hideThisActionLed method.
[_hud addChild:ledSprite withTag:1];
[_hud addChild:ledSprite2 withTag:2];
etc...
-(void)hideThisActionLed:(int)ledNum {
CCSprite *theSprite = [_hud getChildByTag:ledNum];
... hide the sprite ...
Working on my third Cocos2d iPhone game and running into problems trying to make a create new account textfield. I have a menu image and some text that need to be displayed. On top of this layer I would like a Textfield so that the user can type the name of their new account. Seems like it would be pretty simple. I have looked at every example I could find online and nothing seems to work. Here is the method that I need to create the textfield in:
-(void) CreateNewAccount: (id) sender
{
[self removeChild:MainMenu cleanup:YES];
BG2 = [CCSprite spriteWithFile:#"WelcomeMenu.png"];
BG2.position = ccp(512, 384);
[self addChild:BG2 z:6];
[self removeChild:BG cleanup:YES];
NewNameText = [CCSprite spriteWithFile:#"NewName.png"];
NewNameText.position = ccp(512, 300);
[self addChild:NewNameText z:7];
}
Thanks for any help you can provide!!!
It looks like your text field is actually a sprite? I would suggest creating an actual UITextField for your purposes.
See the following: UITextField Example in Cocos2d