cocos2d, CC_HONOR_PARENT_TRANSFORM_SCALE, how do i use this enum property? - objective-c

I want to add a sprite2 to sprite1, scale the width of of sprite 1 without scaling sprite2.
I found the code below part of the Cocos2d api; CCSprite.h line 54, but I don't know how to use it nor what the "1<<2" means.
Basically, I'm doing the following but it's not working:
[self addChild: sprite1];
[sprite1 addChild: sprite2]
sprite1.scaleX = 2;
sprite2.CC_HONOR_PARENT_TRANSFORM_SCALE = false;???
Yeah not sure how to use the enum.
thank you
typedef enum {
//! Translate with it's parent
CC_HONOR_PARENT_TRANSFORM_TRANSLATE = 1 << 0,
//! Rotate with it's parent
CC_HONOR_PARENT_TRANSFORM_ROTATE = 1 << 1,
//! Scale with it's parent
CC_HONOR_PARENT_TRANSFORM_SCALE = 1 << 2,
//! All possible transformation enabled. Default value.
CC_HONOR_PARENT_TRANSFORM_ALL = CC_HONOR_PARENT_TRANSFORM_TRANSLATE | CC_HONOR_PARENT_TRANSFORM_ROTATE | CC_HONOR_PARENT_TRANSFORM_SCALE,
} ccHonorParentTransform;

<< - is a bit operation of a shift (my native language is russian and i've translated as is - not sure it's correct). But it is not required for you to understand how it work in this situation because in this case it's just a method to fill the enum values.
From cocos2d documentation
- (ccHonorParentTransform) honorParentTransform [read, write, assign]
whether or not to transform according to its parent transfomrations. Useful for health bars. eg: Don't rotate the health bar, even if the parent rotates. IMPORTANT: Only valid if it is rendered using an CCSpriteBatchNode.
Are you using batch rendering ?
EDIT:
This line is very strange (doesn't it give a warning?)
sprite2.CC_HONOR_PARENT_TRANSFORM_SCALE = false
You should write
sprite2.honorParentTransform &= ~CC_HONOR_PARENT_TRANSFORM_SCALE;
PS: The enum is created using bit operations because it's give you the ability to misc the configuration. For example you can write
sprite2.honorParentTransform &= ~(CC_HONOR_PARENT_TRANSFORM_SCALE | CC_HONOR_PARENT_TRANSFORM_ROTATE);
It will enable both translate and rotate
So the honorParentTransform is a bitmask, that allows you to configure it's configuration - not only use some predefined values but also use there combinations.
Here you can write more about bitwise operations
http://www.cprogramming.com/tutorial/bitwise_operators.html
In our case is happening something like this:
You have a current mask for example 01101111 (it is 32 bit really)
and CC_HONOR_PARENT_TRANSFORM_SCALE is something like this 00001000 - it have only one nonzero bit. ~ - is inversion: so it transform 00010000 to 11101111 and then you make the bitwise addition with you current mask - so all the bits will be preserved except the forth one!

Related

Error: No operator "=" matches these operands in "Servo_Project.cpp", Line: 15, Col: 22

So I tried using code from another post around here to see if I could use it, it was a code meant to utilize a potentiometer to move a servo motor, but when I attempted to compile it is gave the error above saying No operator "=" matches these operands in "Servo_Project.cpp". How do I go about fixing this error?
Just in case ill say this, the boards I was trying to compile the code were a NUCLEO-L476RG, the board from the post I mentioned utilized Nucleo L496ZG board and a Tower Pro Micro Servo 9G.
#include "mbed.h"
#include "Servo.h"
Servo myservo(D6);
AnalogOut MyPot(A0);
int main() {
float PotReading;
PotReading = MyPot.read();
while(1) {
for(int i=0; i<100; i++) {
myservo = (i/100);
wait(0.01);
}
}
}
This line:
myservo = (i/100);
Is wrong in a couple of ways. First, i/100 will always be zero - integer division truncates in C++. Second, there's not an = operator that allows an integer value to be assigned to a Servo object. YOu need to invoke some kind of Servo method instead, likely write().
myservo.write(SOMETHING);
The SOMETHING should be the position or speed of the servo you're trying to get working. See the Servo class reference for an explanation. Your code tries to use fractions from 0-1 and thatvisn't going to work - the Servo wants a position/speed between 0 and 180.
You should look in the Servo.h header to see what member functions and operators are implemented.
Assuming what you are using is this, it does have:
Servo& operator= (float percent);
Although note that the parameter is float and you are passing an int (the parameter is also in the range 0.0 to 1.0 - so not "percent" as its name suggests - so be wary, both the documentation and the naming are poor). You should have:
myservo = i/100.0f;
However, even though i / 100 would produce zero for all i in the loop, that does not explain the error, since an implicit cast should be possible - even if clearly undesirable. You should look in the actual header you are using to see if the operator= is declared - possibly you have the wrong file or a different version or just an entirely different implementation that happens to use teh same name.
I also notice that if you look in the header, there is no documentation mark-up for this function and the Servo& operator= (Servo& rhs); member is not documented at all - hence the confusing automatically generated "Shorthand for the write and read functions." on the Servo doc page when the function shown is only one of those things. It is possible it has been removed from your version.
Given that the documentation is incomplete and that the operator= looks like an after thought, the simplest solution is to use the read() / write() members directly in any case. Or implement your own Servo class - it appears to be only a thin wrapper/facade of the PwmOut class in any case. Since that is actually part of mbed rather than user contributed code of unknown quality, you may be on firmer ground.

UIControlStateSelected|UIControlStateDisabled, Objective C Explanation

I am doing the stanford Course Assignments and he posted this code
UIControlStateSelected|UIControlStateDisabled
what exactly does this mean and what does the | operand do?
Also, I am trying to set the value on a button using this code but it wont work, any help?
if(!sender.isSelected){
[sender setTitle:self.deck.drawRandomCard.contents forState:UIControlStateSelected];
} else {
[sender setTitle:#"" forState:UIControlStateDisabled];
}
Buttons have many states represented as enumeration values. What you have here are just two of them:
UIControlStateSelected|UIControlStateDisabled
The whole list in UIControl.h:
typedef NS_OPTIONS(NSUInteger, UIControlState) {
UIControlStateNormal = 0,
UIControlStateHighlighted = 1 << 0, // used when UIControl isHighlighted is set
UIControlStateDisabled = 1 << 1,
UIControlStateSelected = 1 << 2, // flag usable by app (see below)
UIControlStateApplication = 0x00FF0000, // additional flags available for application use
UIControlStateReserved = 0xFF000000 // flags reserved for internal framework use
};
So, what does this mean? As you can see in the enumeration definition, the values set to the enumerations are single set bits for each value. So, here is the binary representation of the above:
1 << 0 = 0000 0001 b
1 << 1 = 0000 0010 b
.. and so on
As you can see, the << is a shift operator, and we are simply shifting the bits to the left, so that we can combine these enumerations together in a singe variable! what do I mean? Here:
0000 0011 b // This is essentially two flags set, on for the highlighted state one for the disabled
So, we usually use bit wise OR operator to combine these flags:
0000 0001 | 0000 0010 = 0000 0011
Finally, when combining these flags, and sending them to the method to set the title, you are telling the underlying implementation to change the title for those two options in a single method call.
...
As for your second question about the code that doesn't work, it would be useful to describe what "doesn't work" mean. Does it crash? What is the desired output your looking for?
Edit:
I just read the comments, and there seems a few more issues need to be covered by this answer:
In order to change the state of the button pragmatically, you should call something like:
[sender setEnabled:NO];
The code you have just tells the button to display that text AFTER it has changed to the disabled state.
Another issue regarding the || operator, that certainly is an OR operation, just not a bit-wise OR. This operator is used for boolean expressions instead of bit-wise operations.
What does | mean (for the UIButton states case)?
It means applying the attribute when the button is selected and disabled at the same time.
The | operator means bitwise OR, as far as I understand. But somehow when you bitwise OR the UIControlState together, they must be met at the same time for the effect to take place. Yes, it is strange but that is how it behaves currently, based on my experience too.
Take a look at the other answer here, which shows that it also behaves like what I said: UIButton setTitle:forState: question
So for example, when a user is highlighting a button that is initially selected, you can apply a particular title for that UIControlStateHighlighted|UIControlStateSelected state.
Now about what your code does not work:
Your code is just setting the title of the button when the button is selected (or disabled for the else block), but it does not mean it will make the button selected (or disabled).
You need to make the button property to be selected (or disabled) to see the title change take place.
Those properties, such as enabled, selected, highlighted, can be triggered by the touch of the finger, or you can also set those properties programmatically. Take a look at the class reference of UIControl which include those properties listed.
For example:
myButton.enabled = NO;
myButton.highlighted = YES;
myButton.selected = YES;

Can UIControlEvents in iOS be OR'd together?

Let's say I have the following code:
[somevalue_field
addTarget:self
action:#selector(somevalue_fieldDidChange:)
forControlEvents:UIControlEventEditingDidEnd | UIControlEventTouchDragExit |
UIControlEVentTouchDragOutside ];
Will the bitwise ORing of these UIControlEvents actually work together in terms of combining their effects so that if either of these events happen, the method in the selector will fire?
Or would that result in too many bits being strung together to fit in one integer?
Yes you can OR the control events flags together.
I think you may be a little confused about how bitwise OR works.
ORing does not increase the number of bits, it just increasse the number of set bits.
When you see flags defined like this:
UIControlEventTouchDragOutside = 1 << 3,
UIControlEventTouchDragExit = 1 << 5,
UIControlEventEditingDidEnd = 1 << 18,
it is often a clue that it was intended they could be ORed together.
In binary these flags and the result of the OR would be:
UIControlEventTouchDragOutside 00000000000000000000000000001000
UIControlEventTouchDragExit 00000000000000000000000000100000
UIControlEventEditingDidEnd 00000000000001000000000000000000
Result of OR 00000000000001000000000000101000
So as you can see, the number of bits in the result is still the same (32) it's just the number of set bits that changes.
Google "binary arithmetic" and "bitwise boolean operators" for more on this.
A final note, the Apple docs for addTarget:action:forControlEvents say:
controlEvents
A bitmask specifying the control events for which the
action message is sent. See “Control Events” for bitmask constants.
The term bitmask implies that you can OR together the Control Event constants for this call.

Generate a random Y for a sprite

I need some help (duh). I want to generate a random Y position for my game in cocos2d.
So the situation goes like this:
The game spawns a platform every 0.2 second. The iPhone / iPad is in landscape mode. Platform appear on the right of the screen (bigger x than width so that the platform appears outside the screen) and starts moving towards the left end of the screen using CCMoveTo.
I pick a random Y for every platform. The problem is that I do not want to spawn a platform on top of another. This means that I need to make a randY which is not "already taken".
The code I've tried so far is this:
//this is a part of code from my addPlatform function. This part in particular cares for the generation of my Y coordinate.
int randY = arc4random() % (int)(3 * (winSize.height/4)); //This prevents to spawn a Y larger than 3/4 of the screen
//here I would like to loop long enough to find a good Y
while (![self isGoodPlatformY:randY])
{
randY = arc4random() % (int)(3 * (winSize.height/4));
}
The next part is my isGoodPlatformY function
- (bool)isGoodPlatformY:(int)platY
{
CGSize winSize = [[CCDirector sharedDirector] winSize];
int padding = 100;
bool ok = true;
for (CCSprite *body in [self children])
{
if (body.tag > platformBody)
{
if (body.position.x < (winSize.width - padding))
{
if (abs(body.position.y - platY) < 20)
{
ok = false;
}
}
}
}
return ok;
}
I loop through all the bodies with larger tag than my platform. I have different types of platform which I separate by using tag. If the body is a platform I first check the X coordinate. If the platform is enough away (padding) I can spawn a new one at that exact point so I check the next one. If not I want to check the Y of that platform. If the Y coordinate is less than 20 pixels in this case I must find a new Y so thats why set the bool to false and return it after the for loop.
I know there is no need for those curly brackets but I was testing some other stuff, thats why I put them there.
This doesn't seem to work. Hope I made myself clear what I want to accomplish. Any help from your side would be much appreciated. Hope I didn't miss something too newbie style :)
I tagged the question in other languages to because this problem could occur "everywhere".
Assuming that all the spawned platforms have the same tag as you mentioned that you are using tags to separate different types of platforms.
All previous platforms will not return true for this line
if (body.tag > platformBody)
because they all have the same tag, you will compare (1 > 1) which is false.
Therefore your method will always return YES (which is your default value for ok) and will never check to see if the platforms collide with each other.
I recommend stepping through the method to see if this is the case.
Now I have discovered that I can answer my own questions :) (silly me). So yeah, the problem was fixed a long time ago but to anyone who might be reading this, the solution was to change the line:
if (body.position.x < (winSize.width - padding))
To:
if (body.position.x > (winSize.width - padding))

Cocoa -- toggling a BOOL without repeating its name

If a BOOL has a nice short name, it's easy enough to write:
myBOOL = !myBOOL;
But what if the BOOL has a long name?
objectWithLongishName.memberWithLongishName.submember.myBOOL = !(objectWithLongishName.memberWithLongishName.submember.myBOOL);
. . . does not look so pretty.
I'm wondering if there is an easy way to toggle the BOOL without entering its name twice?
Here's another:
MyBooleanYaddaYadda ^= YES;
This is kinda brittle - it will break on legacy C code that implies that any nonzero integer evaluates to true. But then again, so will Apple framework code - I encountered cases in Cocoa where a nonzero, non-one int, when passed as a BOOL, would not cause the same effect as passing a YES.
However, it does not rely on the bit pattern of YES - only on NO being 0. Which is pretty much a given, considering the way C interprets integers as logical values. Also, it does not assume the actual datatype of BOOL (which on Cocoa is signed char, by the way).
The bit pattern of YES on Cocoa is 1. But that's not a universal convention. On some platforms with no built-in boolean datatype, the integer constant that serves as a logical TRUE is -1 - all one bits. That's 0xFFFFFFFF if interpreted as unsigned. This coding has a vague advantage that bitwize NOT (the ~ operator in C ) is equivalent to logical NOT (the ! operator in C). That is, ~0xFFFFFFFF is 0, i. e. ~TRUE is FALSE. Doesn't work that way if TRUE is defined as 1.
#define NOT(b) (b) = !(b)
NOT(MyBooleanVariableWithAFreakishlyLongName);
Or, if it's Objective C++:
inline void NOT(BOOL &b)
{
b = !b;
}
No there isn't an obvious way in (Objective-)C to do what you describe (without using a preprocessor macro), but see Seva's answer for a possible (though potentially brittle) solution. More importantly, something like objectWithLongishName.memberWithLongishName.submember.myBOOL indicates a Law of Demeter violation; you should be providing submember directly to any code unit that needs to access submember.myBOOL.
Write a method for the submember class that toggles it for you?
- (void) toggleMyBOOL {
self.myBool = !self.myBool;
}
Then you can do:
[objectWithLongishName.memberWithLongishName.submember toggleMyBOOL];
Use XOR. In C, this is ^.
BOOL x = YES;
x ^= YES; // it's now NO
x ^= YES; // it's now YES
x ^= YES; // it's now NO
x ^= YES; // it's now YES
x ^= YES; // it's now NO
x ^= YES; // it's now YES
...
Edit: someone posted this already, apparently. I guess I should say I've never actually used this in code. :-)
You have a lovely set of answers focused on flipping a YES to a NO or vice-versa, but no answers that touched on what would appear to be an architectural issue in the code.
Well, some answers. I'm blind.
Namely, you have this:
objectWithLongishName.memberWithLongishName.submember.myBOOL =
!(objectWithLongishName.memberWithLongishName.submember.myBOOL);
That smells like a potential encapsulation violation. In particular (and assuming this is a model layer), it means that the connectivity of the sub-graph of objects is being overtly exposed -- flattened into, effectively -- the entry point of that path; whatever objectWithLongishName is must now have rather intimate knowledge of the innards of the objects along the rest of the path.
Typically, you don't reach deeply into the model layer along key paths to edit state outside of the Cocoa Bindings layer (and even that is a bit fragile).
Sometimes such long-ish paths do make sense. In such a case, I would leave the über-verbose form you have above as a visual indication that encapsulation is being purposefully shred.