How do I get the NAME of a UIColor/SKColor (i.e. [UIColor redColor] --> #"red" - objective-c

I kinda asked the question in the title but suppose I have a UIColor (i.e. [UIColor redColor]. How do i get an NSString to equal #"red" OR how can i find out is a color is the same as [UIColor redColor]?
For example I have tried,
SKSpriteNode *player = [SKSpriteNode spriteNodeWithImageNamed:#"image"];
[player runAction:[SKAction colorWithColor:[SKColor blueColor] withColorBlendFactor:1 duration:0.01];
[self addChild:player];
Then later:
if (player.color == [SKColor blueColor]) { //Also I have tried 'isEqual' and that didn't work either!
}
PLEASE HELP ME! Thanks in advance!

I assume you do not know about userData as rmaddy already suggested so I will give you some sample code. First though, this is what Apple says about the userData:
You use this property to store your own data in a node. For example, you might store game-specific data about each node to use inside your game logic. This can be a useful alternative to creating your own node subclasses to hold game data.
Sprite Kit does not do anything with the data stored in the node. However, the data is archived when the node is archived.
#implementation MyScene
{
SKSpriteNode *frank;
SKSpriteNode *sally;
}
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
frank = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(50, 50)];
frank.position = CGPointMake(100, 100);
frank.userData = [NSMutableDictionary dictionary];
[frank.userData setValue:#"blue" forKey:#"color"];
[self addChild:frank];
sally = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(50, 50)];
sally.position = CGPointMake(200, 100);
sally.userData = [NSMutableDictionary dictionary];
[sally.userData setValue:#"red" forKey:#"color"];
[self addChild:sally];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode: self];
SKNode *node = [self nodeAtPoint:location];
NSMutableDictionary *tempDictionary = node.userData;
NSString *tempString = [NSString stringWithFormat:#"%#",[tempDictionary objectForKey:#"color"]];
if([tempString isEqualToString:#"blue"])
NSLog(#"My color is blue");
if([tempString isEqualToString:#"red"])
NSLog(#"My color is red");
}

Related

Sprite Kit SKLabel is not appearing when I initialize it in initWithSize:(CGSize)size

I read up on other posts and changed view controller viewdidload to:
(void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
}
and I'm really not sure what the problem is. here is my code:
(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
world=SKNode.node;
[self addChild:world];
self.anchorPoint= CGPointMake(0.5, 0.5);
SKSpriteNode *ground = [SKSpriteNode spriteNodeWithColor:[UIColor yellowColor] size: CGSizeMake(self.frame.size.width, 150)];
ground.position= CGPointMake(0, -self.frame.size.height/2+ ground.frame.size.width/2);
ground.physicsBody= [SKPhysicsBody bodyWithRectangleOfSize:ground.size];
ground.physicsBody.dynamic=NO;
NSLog(#"ground position: %f" , -self.frame.size.height/2+ ground.frame.size.width/2);
[world addChild:ground];
generator = [WorldGenerator generatorWithWorld:world];
[self addChild:generator];
[generator populate];
hero = [MLHero hero];
[world addChild:hero];
pointsLabel =[SKLabelNode labelNodeWithFontNamed:#"ChalkDuster"];
if (pointsLabel)
NSLog(#"true");
pointsLabel.fontColor=[SKColor redColor];
pointsLabel.fontSize=40;
pointsLabel.text=#"0";
pointsLabel.position= CGPointMake(200,200); //I have tried many different values and none seem to work, including setting to the width and height etc.
[self addChild:pointsLabel];
}
return self;
}

SprikeKit physics - How can i make my character stand up after falling down?

I'm new to sprite kit and game physics in general. I want my character to stand up upright whenever he falls over or knocked down. A bit like a floor-mounted punch bag. Here's my current code:
#import "MyScene.h"
#interface MyScene () <SKPhysicsContactDelegate> {
SKSpriteNode *_body;
SKSpriteNode *_leg1;
SKSpriteNode *_leg2;
SKSpriteNode *_foot1;
SKSpriteNode *_foot2;
}
#end
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
//self.backgroundColor = [SKColor greenColor];
self.physicsWorld.gravity = CGVectorMake(0, -2.0);
self.physicsWorld.contactDelegate = self;
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
SKSpriteNode *button = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(50, 50)];
button.position = CGPointMake(40, 40);
button.zPosition = 10;
button.name = #"button";
[self addChild: button];
[self createCharacter];
}
return self;
}
-(void)createCharacter {
// Add sprites
_body = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(40, 60)];
_body.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild: _body];
_leg1 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(14, 60)];
_leg1.position = CGPointMake(_body.position.x+20-7, _body.position.y-65);
[self addChild:_leg1];
_foot1 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(20, 10)];
_foot1.position = CGPointMake(_leg1.position.x-2.5, _leg1.position.y-40);
[self addChild:_foot1];
_leg2 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(14, 60)];
_leg2.position = CGPointMake(_body.position.x-20+7, _body.position.y-65);
[self addChild:_leg2];
_foot2 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(20, 10)];
_foot2.position = CGPointMake(_leg2.position.x-2.5, _leg2.position.y-40);
[self addChild:_foot2];
// Add physics bodies to sprites
_body.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_body.size];
_leg1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_leg1.size];
_foot1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_foot1.size];
_foot1.physicsBody.mass = 1;
_leg2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_leg2.size];
_foot2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_foot2.size];
_foot2.physicsBody.mass = 0.5;
// Add joints
SKPhysicsJoint *hipJoint = [SKPhysicsJointFixed jointWithBodyA:_body.physicsBody bodyB:_leg1.physicsBody anchor:_leg1.position];
SKPhysicsJoint *ankleJoint = [SKPhysicsJointFixed jointWithBodyA:_leg1.physicsBody bodyB:_foot1.physicsBody anchor:_foot1.position];
SKPhysicsJointPin *hipJoint2 = [SKPhysicsJointPin jointWithBodyA:_body.physicsBody bodyB:_leg2.physicsBody anchor:CGPointMake(_leg2.position.x, CGRectGetMaxY(_leg2.frame))];
[hipJoint2 setShouldEnableLimits:YES];
[hipJoint2 setLowerAngleLimit:-M_PI_2];
[hipJoint2 setUpperAngleLimit:0.0];
SKPhysicsJoint *ankleJoint2 = [SKPhysicsJointFixed jointWithBodyA:_leg2.physicsBody bodyB:_foot2.physicsBody anchor:_foot2.position];
[self.scene.physicsWorld addJoint:hipJoint];
[self.scene.physicsWorld addJoint:ankleJoint];
[self.scene.physicsWorld addJoint:hipJoint2];
[self.scene.physicsWorld addJoint:ankleJoint2];
}
-(void)characterJump {
CGFloat radianFactor = 0.0174532925;
CGFloat rotationInDegrees = _body.zRotation / radianFactor;
CGFloat newRotationDegrees = rotationInDegrees + 90;
CGFloat newRotationRadians = newRotationDegrees * radianFactor;
CGFloat r = 500;
CGFloat dx = r * cos(newRotationRadians);
CGFloat dy = r * sin(newRotationRadians);
[_body.physicsBody applyImpulse:CGVectorMake(dx, dy)];
NSLog(#"leg2 rotation: %f", _foot2.zRotation / radianFactor);
}
-(void)characterKick {
NSLog(#"Kick..");
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"button"]) {
[self characterJump];
[self characterKick];
}
}
-(void)update:(CFTimeInterval)currentTime {
}
#end
Run the code and tap the button to make him jump and eventually fall over. Also, the joint limits don't work as it breaks through the limits sometimes.
Help would be really appreciated.
I resolved this issue by checking the _body SKSpriteNode's 'y' position in the scene's update method. If the 'y' position was below a certain limit, I applied an impulse to the body's physicsBody from below to stand it up again.
This worked as required/desired.
-(void)update:(CFTimeInterval)currentTime {
if(_body.position.y < 30) {
[self upOnYourFeet];
}
}
-(void)upOnYourFeet {
[_body.physicsBody applyImpulse:CGVectorMake(0, 80)];
}

SpriteKit: textureFromNode method not working in initWithSize method

This doesn't work – the newNode's texture is nil:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKSpriteNode *node = [SKSpriteNode spriteNodeWithColor:[UIColor orangeColor] size:CGSizeMake(100, 100)];
SKTexture *texture = [self.view textureFromNode:node];
SKSpriteNode *newNode = [SKSpriteNode spriteNodeWithTexture:texture];
[self addChild:newNode];
}
return self;
}
This does work:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKSpriteNode *node = [SKSpriteNode spriteNodeWithColor:[UIColor orangeColor] size:CGSizeMake(100, 100)];
SKAction *createNewNode = [SKAction runBlock:^{
SKTexture *texture = [self.view textureFromNode:node];
SKSpriteNode *newNode = [SKSpriteNode spriteNodeWithTexture:texture];
[self addChild:newNode];
}];
[self runAction: createNewNode];
}
return self;
}
Can someone please explain why!? Thanks!
In case you're wondering why the node is not added the scene: The Apple documentation for textureFromNode states: "The node being rendered does not need to appear in the view’s presented scene."
My guess is: at the point where you are creating the sprite node (inside the scene's initWithSize:) the node graph is not fully set up yet. The scene isn't connected with (presented by) the view, and therefore it is not set up for rendering.
It's quite possible that SKSpriteNode textures for sprites using a color are only created after the scene is presented. This would explain why running the block action works.
You can probably fix this also by simply moving the code from initWithSize: to the scene's didMoveToView method, which is called after the scene was presented on the view.

UIBezierPath to draw straight lines

Here is the relevant .m that I am currently using.
- (void)drawRect:(CGRect)rect
{
[[UIColor redColor] setStroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
#pragma mark -
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
myPath=[[UIBezierPath alloc]init];
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
if([ud objectForKey:#"lineThickness"] == nil) {
myPath.lineWidth=5;
}
else {
float thicknessFloat = [ud floatForKey:#"lineThickness"];
myPath.lineWidth= 10. * thicknessFloat;
}
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
[pathArray addObject:myPath];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
if([ud objectForKey:#"lineThickness"] == nil) {
myPath.lineWidth=5;
}
else {
float thicknessFloat = [ud floatForKey:#"lineThickness"];
myPath.lineWidth= 10. * thicknessFloat;
}
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
It works great, but since this is tutorial code that is slightly modified by me, I do not know how to approach the problem of wanting to draw lines between two points, and have the framework connect the the points each time a point is added.
Can anyone please point me in a good direction on how to accomplish this please?
The particulars of how to implement this depend upon the effect that you're looking for. If you're just tapping on a bunch of points and want to add them to a UIBezierPath you can do something like the following in your view controller:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
CGPoint location = [mytouch locationInView:self.view];
// I'm assuming you have a myPath UIBezierPath which is an ivar which is
// initially nil. In that case, we'll check if it's nil and if so, initialize
// it, otherwise, it's already been initialized, then we know we're just
// adding a line segment.
if (!myPath)
{
myPath = [UIBezierPath bezierPath];
[myPath moveToPoint:location];
shapeLayer = [[CAShapeLayer alloc] initWithLayer:self.view.layer];
shapeLayer.lineWidth = 1.0;
shapeLayer.strokeColor = [UIColor redColor].CGColor;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
[self.view.layer addSublayer:shapeLayer];
}
else
{
[myPath addLineToPoint:location];
shapeLayer.path = myPath.CGPath;
}
}
If you wanted something where you can draw with your finger (e.g. dragging your finger draws), then it might look something like:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
CGPoint location = [mytouch locationInView:self.view];
myPath = [UIBezierPath bezierPath];
[myPath moveToPoint:location];
shapeLayer = [[CAShapeLayer alloc] initWithLayer:self.view.layer];
shapeLayer.lineWidth = 1.0;
shapeLayer.strokeColor = [UIColor redColor].CGColor;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
[self.view.layer addSublayer:shapeLayer];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
CGPoint location = [mytouch locationInView:self.view];
[myPath addLineToPoint:location];
shapeLayer.path = myPath.CGPath;
}
I would not use UIBezierPath since it is intended more for drawing curved paths.
The most efficient way to accomplish this would be to use core graphics draw commands within drawRect while using an array to store the points you want to draw; this array is appended to in your touch methods.
- (void)drawRect:(CGRect)rect {
CGContextRef c = UIGraphicsGetCurrentContext();
CGFloat black[4] = {0, 0,
0, 1};
CGContextSetStrokeColor(c, black);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 100, 100);
CGContextAddLineToPoint(c, 100, 200); //call this in a loop that goes through the point array
CGContextStrokePath(c);
}
There is much more information here: Quartz 2D Programming Guide
Hope this helps!

Eraser for UIBezierPath

I am using UIBezierPath for free hand drawing in an iPad app. I want to apply an eraser to a uibezierpath.
However, I want to only erase the drawing in its path. I cannot use the path color as the background color because I have other elements on the background.
Below is how I am creating my free hand drawings:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
lineWidths = 10;
brushPattern = [UIColor greenColor];
pathArray = [[NSMutableArray alloc]init];
bufferArray = [[NSMutableArray alloc]init];
self.multipleTouchEnabled = NO;
}
return self;
}
- (void)drawRect:(CGRect)rect {
for (NSMutableDictionary *dictionary in pathArray) {
UIBezierPath *_path = [dictionary objectForKey:#"Path"];
UIColor *_colors = [dictionary objectForKey:#"Colors"];
[_colors setStroke];
_path.lineCapStyle = kCGLineCapRound;
[_path stroke];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
myPath = [[UIBezierPath alloc]init];
myPath.lineWidth = lineWidths;
CGPoint touchPoint = [[touches anyObject] locationInView:self];
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
[myPath addLineToPoint:CGPointMake(touchPoint.x, touchPoint.y)];
dict = #{#"Path": myPath, #"Colors": brushPattern};
[pathArray addObject:dict];
[self setNeedsDisplay];
[undoManager registerUndoWithTarget:self selector:#selector(undoButtonClicked) object:nil];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
Store a BOOL value for erase: BOOL _erase;
BOOL eraseButtonIsTapped = ...
if eraseButtonIsTapped {
_erase = yes;
} else{
_erase = NO;
}
When drawing:
[myPath strokeWithBlendMode:_erase?kCGBlendModeClear:kCGBlendModeNormal alpha:1.0f];
Just try this
brushPattern = view.backgroundColor;
This will draw a new line with the color what exactly behind your drawn path. And you can use the same pathArray to do this. So that later on you can implement redo/undo operations too. if you want i could explain you more on this.