Couldn't really find much help anywhere on this subject-- I'm stuck trying to figure out how to implement a virtual D-Pad on an orthogonal tilemap to simulate movement as seen in the GBA pokemon/zelda games.
Does anyone have a good tutorial i should look at? If not, I'd appreciate example code as well.
SneakyInput is what I used for my D-Pad in my game, the classes can be found at https://github.com/sneakyness/SneakyInput.
#import "SneakyJoystick.h"
#import "SneakyButton.h"
#import "SneakyButtonSkinnedBase.h"
#import "SneakyJoystickSkinnedBase.h"
#interface GameplayLayer : CCLayer
{
SneakyJoystick *leftJoystick;
SneakyButton *jumpButton;
SneakyButton *attackButton;
}
#end
You then declare the dimensions of each of the buttons and their positions on the screen:
-(void)initJoystickAndButtons
{
CGSize screenSize = [CCDirector sharedDirector].winSize;
CGRect joystickBaseDimensions = CGRectMake(0, 0, 128.0f, 128.0f);
CGRect jumpButtonDimensions = CGRectMake(0, 0, 64.0f, 64.0f);
CGRect attackButtonDimensions = CGRectMake(0, 0, 64.0f, 64.0f);
CGPoint joystickBasePosition;
CGPoint jumpButtonPosition;
CGPoint attackButtonPosition;
joystickBasePosition = ccp(screenSize.width*0.0625f, screenSize.height*0.052f);
jumpButtonPosition = ccp(screenSize.width*0.946f, screenSize.height*0.052f);
attackButtonPosition = ccp(screenSize.width*0.947f, screenSize.height*0.169f);
}
If you want the full code block I can help you out, but its long and I don't want to type it all out here. Hope this helps.
Related
I need to take the screenshot in my cocos2d application. I've searched a lot, even in stack overflow. Then I found the following code:
+(UIImage*) screenshotWithStartNode:(CCNode*)stNode
{
[CCDirector sharedDirector].nextDeltaTimeZero = YES;
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCRenderTexture* renTxture =
[CCRenderTexture renderTextureWithWidth:winSize.width
height:winSize.height];
[renTxture begin];
[stNode visit];
[renTxture end];
return [renTxture getUIImage];
}
Now,
Problem: The above code gives me the entire screenshot. But I am in need of the screenshot of a custom are, such as, within a CGRect(50,50,100,200).
Can anyone please help me..? Thanks...
Wow... found out what I need. I've changed the above method like:
-(UIImage*) screenshotWithStartNode:(CCNode*)startNode
{
[CCDirector sharedDirector].nextDeltaTimeZero = YES;
CGSize winSize = [CCDirector sharedDirector].winSize;
CCRenderTexture* rtx =
[CCRenderTexture renderTextureWithWidth:winSize.width
height:winSize.height];
[rtx begin];
[startNode visit];
[rtx end];
UIImage *tempImage = [rtx getUIImage];
CGRect imageBoundary = CGRectMake(100, 100, 300, 300);
UIGraphicsBeginImageContext(imageBoundary.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// translated rectangle for drawing sub image
CGRect drawRect = CGRectMake(-imageBoundary.origin.x, -imageBoundary.origin.y, tempImage.size.width, tempImage.size.height);
// clip to the bounds of the image context
CGContextClipToRect(context, CGRectMake(0, 0, imageBoundary.size.width, imageBoundary.size.height));
// draw image
[tempImage drawInRect:drawRect];
// grab image
UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return subImage;
}
I would be very grateful for any advice you can offer as I am growing increasingly frustrated with an issue I am having - I also appreciate that the issue I am having is due to my lack of knowledge / understanding.
In an attempt to further my knowledge and stretch myself, I have chosen to create a PlayerStats class that handles the players scoring - and in time, health, etc.
I have the GameLevelLayer and PlayerStats classes implemented as follows:
GameLevelLayer.m as follows:
#import "GameLevelLayer.h"
#import "Player.h"
#import "PlayerStats.h"
#interface GameLevelLayer() {
CCTMXTiledMap *map;
Player *player;
PlayerStats *playerStats;
}
#end
#implementation GameLevelLayer
#synthesize grabber = _grabber;
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
GameLevelLayer *layer = [GameLevelLayer node];
PlayerStats *hudLayer = [PlayerStats node];
[scene addChild: layer];
[scene addChild: hudLayer];
return scene;
}
-(id) init {
if( (self=[super init]) ) {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
playerStats = [[PlayerStats alloc]init];
...........
}
PlayerStats.m is as follows:
-(id) init
{
if ((self = [super init])) {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
score = [CCLabelTTF labelWithString:#"Score : 0" dimensions:CGSizeMake(100,20) hAlignment:UITextAlignmentRight fontName:#"Marker Felt" fontSize:(18.0)];
int margin = 5;
score.position = ccp(screenSize.width - (score.contentSize.width/2) - margin, score.contentSize.height/2 + margin);
[self addChild:score z:99];
}
return self;
}
-(void)numberOfItemsCollected:(int)collected {
NSString *str = [score string];
CCLOG(#"What does the label say %#", str);
// This is actually displaying the correct string of what the score should be ..
[score setString:[NSString stringWithFormat:#"Score : %d", collected]];
}
When (from the GameLevelLayer.m) I initiate
[playerStats numberOfItemsCollected:5];
the CCLog shows that the label should show Score : 5 but the label itself does not update.
Any advice would be greatly appreciated as I am very aware that I am misunderstanding the issue.
I think the issue is to do with the Layer that I am updating not being the one I believe it is....
Thanks in advance.
I had declared the CCLabelTTF *score as an instance variable in the PlayerStats Class header. What a difference a night away from code makes.
Finally I managed to solve this issue set string to an empty string then reSet it to your string
[label setString:#""];
[label setString:yourString];
I have an app where I have several layers created from PNG images with transparency. These layers are all on the screen over each other. I need to be able to ignore touches given to transparent areas of layers and just be able to detect as touches, when the user taps on a non-transparent area of a layer... see pic...
How do I do that? thanks.
Here you have a possible solution.
Implement an extension on CCLayer and provide this method:
- (BOOL)isPixelTransparentAtLocation:(CGPoint)loc
{
//Convert the location to the node space
CGPoint location = [self convertToNodeSpace:loc];
//This is the pixel we will read and test
UInt8 pixel[4];
//Prepare a render texture to draw the receiver on, so you are able to read the required pixel and test it
CGSize screenSize = [[CCDirector sharedDirector] winSize];
CCRenderTexture* renderTexture = [[CCRenderTexture alloc] initWithWidth:screenSize.width
height:screenSize.height
pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[renderTexture begin];
//Draw the layer
[self draw];
//Read the pixel
glReadPixels((GLint)location.x,(GLint)location.y, kHITTEST_WIDTH, kHITTEST_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
//Cleanup
[renderTexture end];
[renderTexture release];
//Test if the pixel's alpha byte is transparent
return (pixel[3] == 0);
}
if Lio's solution doesn't work, you may add add transparent sprite as a child you yours, place it just under your non-transparent area with size of this non-tranparent area and resive all touches by this new transparent sprite, but not by original sprite.
Here is my solution to your requirement, let me know if it works or not
Create a Category on CCMenu with Name Transparent
File CCMenu+Tranparent.h
#import "CCMenu.h"
#interface CCMenu (Transparent)
#end
File CCMenu+Tranparent.m
#import "CCMenu+Transparent.h"
#import "cocos2d.h"
#implementation CCMenu (Transparent)
-(CCMenuItem *) itemForTouch: (UITouch *) touch{
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
CCMenuItem* item;
CCARRAY_FOREACH(children_, item){
UInt8 data[4];
// ignore invisible and disabled items: issue #779, #866
if ( [item visible] && [item isEnabled] ) {
CGPoint local = [item convertToNodeSpace:touchLocation];
/*
TRANSPARENCY LOGIC
*/
//PIXEL READING 1 PIXEL AT LOCATION
CGRect r = [item rect];
r.origin = CGPointZero;
if( CGRectContainsPoint( r, local ) ){
if([NSStringFromClass(item.class) isEqualToString:NSStringFromClass([CCMenuItemImage class])]){
CCRenderTexture* renderTexture = [[CCRenderTexture alloc] initWithWidth:item.boundingBox.size.width * CC_CONTENT_SCALE_FACTOR()
height:item.boundingBox.size.height * CC_CONTENT_SCALE_FACTOR()
pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[renderTexture begin];
[[(CCMenuItemImage *)item normalImage] draw];
data[3] = 1;
glReadPixels((GLint)local.x,(GLint)local.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
[renderTexture end];
[renderTexture release];
if(data[3] == 0){
continue;
}
}
free(data);
return item;
}
}
}
return nil;
}
#end
This will check for pixel for returning the CCMenuItem.
Its working fine here.. let me know if you face any issues
-Paresh Rathod
Cocos2d Lover
The solution that worked great for me was using Sprite sheets. I use TexturePacker to create sprite sheets. Steps to create sprite sheet using TexturePacker:
1. Load all the image (.png) files into TexturePacker.
2. Chose data format as coco2d and choose PVR as the texture format.
3. Load the sprite sheet into your code and extract images from your sprite sheet.
Detailed description can be found here.
How do I get the world space coordinate of point that is in the center of the screen, in Cocos2d-iPhone?
Simple, just take the height and width and divide it by 2
CGSize winSize = [[CCDirector sharedDirector] winSize];
CGPoint point = ccp(winSize.width/2, winSize.height/2);
Here is a somewhat more advanced way to do it.
This will also work if you have called setPosition on the parent of the sprite (=self in this example)
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite* centerSprite = [CCSprite spriteWithFile:#"sprite"];
CGPoint centerPoint = ccpSub(ccp(winSize.width/2, winSize.height/2), [self position]);
[centerSprite setPosition:centerPoint];
[self addChild: centerSprite];
You can get the exact center of the screen no matter what framework you are using, Cocos or not, and also even if Cocos is not set to use the entire screen (such is the case sometimes if you crop Cocos to make room for ads) by doing something like this:
int width=[[UIScreen mainScreen] bounds].size.width
int height=[[UIScreen mainScreen] bounds].size.height
CGPoint center=ccp(width/2,height/2);
Note the ccp macro works in Cocos only; otherwise, use CGPointMake
I have created a loading scene separate class derived from CCScene which I can reuse in other projects. I have added a label called "Loading.." inside it.
#interface LoadingScene : CCScene
{
TargetScenes targetScene_;
}
I want to give effects to label while other scene is loading but I am not able to do so..
In .m file here goes the code for adding labels:
-(id) initWithTargetScene:(TargetScenes)targetScene
{
if ((self = [super init]))
{
targetScene_ = targetScene;
CCLabelTTF* label = [CCLabelTTF labelWithString:#"Loading ..." fontName:#"Marker Felt" fontSize:64];
label.color = ccWHITE;
CGSize size = [[CCDirector sharedDirector] winSize];
label.position = CGPointMake(size.width / 2, size.height / 2);
CCBlink *blink = [CCBlink actionWithDuration:2 blinks:10];
[label runAction:blink];
[self addChild:label];
}
return self;
}
The blink is not work.. None of the actions are working and giving me big headache...
Please can someone let me know the reason behind it? Also, How to overcome it?
Have you overridden onEnter in your class? Did you remember to call [super onEnter]?