How to use global / static variables OBJ-C - iphone

I'm looking to save a variable that is used for one method, and then call it in another method for an App. Does this have something to do with global/extern/static variables? If so, I was wondering how it would be set up. I've tried to use global and static with no success.
I'm trying to hold the information of newX and newY
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
...
int newX = (int)(Button.center.x + valueX);
int newY = (int)(Button.center.y + valueY);
...
}
and then call it in
-(IBAction)clicked:(id)sender
{
randX = arc4random() % 320;
randY = arc4random() % 548;
CGPoint randNewPlace = CGPointMake(randX, randY);
Rand.center = randNewPlace;
if (newX == randX || newY == randY)
{
[Rand sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
thanks.

Just do as below
Declare properties
#property(nonatomic,weak) int newX;
#property(nonatomic,weak) int newY;
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
...
self.newX = (int)(Button.center.x + valueX);
self.newY = (int)(Button.center.y + valueY);
...
}
-(IBAction)clicked:(id)sender
{
randX = arc4random() % 320;
randY = arc4random() % 548;
CGPoint randNewPlace = CGPointMake(randX, randY);
Rand.center = randNewPlace;
if (self.newX == randX || self.newY == randY)
{
[Rand sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}

If you want to define an unchanging constant variable define it in your .h and .m
For example, if i want to define the color black as a hexadecimal string in my .h I put above the #interface.
// Default Black
extern NSString * const Black;
Then in my .m above the #implementation
// Default Black
NSString * const Black = #"0xFF000000";
Any time I call the variable Black, out comes 0xFF000000
Of course you could define any type of variable, it doesn't have to be an NSString. extern simply exposes your variables to the rest of your application.
Hope that helps!

#property (nonatomic) int newX,newY;
To access them just instantiate the class then use dot notation. Class.newX

Related

Segmented Controllers

Trying to set an int value using a Segmented Controller. I've seen several tuts on how to change labels, but I need to set an int value.
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize caseCost;
#synthesize dilution;
#synthesize returnMsg;
#synthesize opcValue;
//synthesize opc; < -- Tried
//int opc; <--- tried
- (IBAction)opcView:(id)sender {
if (opcValue.selectedSegmentIndex == 0) {
int opc = 320;
}
if (opcValue.selectedSegmentIndex == 1) {
int opc = 128;
}
if (opcValue.selectedSegmentIndex == 2) {
int opc = 135;
}
if (opcValue.selectedSegmentIndex == 3) {
int opc = 88;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//int opc; <--- tried
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)finishBtn:(id)sender {
//int opc = 320;
float case_cost = ([caseCost.text floatValue]);
float dilutionValue = ([dilution.text floatValue]);
float gpc = (opc / dilutionValue);
float gCost = (case_cost / gpc);
float bCost = (gCost / 4);
float bpc = (gpc * 4);
NSNumberFormatter *formatterCur = [[NSNumberFormatter alloc] init];
NSNumberFormatter *formatterInt = [[NSNumberFormatter alloc] init];
[formatterCur setNumberStyle:NSNumberFormatterCurrencyStyle];
[formatterInt setNumberStyle:NSNumberFormatterDecimalStyle];
NSString *bottlesCost = [formatterCur stringFromNumber:[NSNumber numberWithFloat:bCost]];
NSString *gallons = [formatterInt stringFromNumber:[NSNumber numberWithInt:gpc]];
NSString *gallonsCost = [formatterCur stringFromNumber:[NSNumber numberWithFloat:gCost]];
NSString *bottles = [formatterInt stringFromNumber:[NSNumber numberWithInt:bpc]];
returnMsg.text = [NSString stringWithFormat:#"%# gallons per case at %# per gallon and %# - 32 oz bottles at %# per bottle.", gallons, gallonsCost, bottles, bottlesCost];
}
- (IBAction)opcView:(id)sender {
}
#end
in the line "float gpc = (opc / dilutionValue);" is shows as an unknown value of opc, even though I think it should from the segmented controller. I'm using the segmented controller instead of Radio Buttons i've used in Java. I used the "//int opc=320" to make sure the rest of the code worked.
In each of the if blocks in your method - (IBAction)opcView:(id)sender you are creating a local int variable named opc. So when execution leaves the if block, the local variable disappears. Thus, in - (IBAction)finishBtn:(id)sender there is no variable named opc in scope.
You should declare opc to be a property as well. You will set this property when the segment control changes selection. Later, you can read the property's value in your finish button's handler.
#import "SecondViewController.h"
#interface SecondViewController()
#property (nonatomic) int opc;
#end
#implementation SecondViewController
// this method is wired to the segment control's UIControlEventValueChanged event
- (IBAction)opcView:(id)sender
{
if (opcValue.selectedSegmentIndex == 0) {
self.opc = 320;
}
if (opcValue.selectedSegmentIndex == 1) {
self.opc = 128;
}
if (opcValue.selectedSegmentIndex == 2) {
self.opc = 135;
}
if (opcValue.selectedSegmentIndex == 3) {
self.opc = 88;
}
}
- (IBAction)finishBtn:(id)sender
{
float case_cost = ([caseCost.text floatValue]);
float dilutionValue = ([dilution.text floatValue]);
float gpc = (self.opc / dilutionValue);
// lots more code
}

cut a sprite sheet on cocos2d for animation

I want to cut a sprite in 6 equivalent parts just with one image, a .png file which I found on the web, no with texturepacker, (the image below by example)
I can take other way, but I want to know if I can do that. any one haves idea?
I'll revise my answer if this isn't what you were asking about, but I think you are asking how to 'manually run an animation' using a spritesheet without a plist.
Here's one way. It would be better if you encapsulated this into it's own class, but this can push you in the right direction I think:
ManualAnimationTest.h
#interface ManualAnimationTest : CCLayer
{
CCSprite *animatedSprite;
int x,y;
float animatedSpriteWidth, animatedSpriteHeight;
int animatedSpriteColumns, animatedSpriteRows;
}
#end
ManualAnimationTest.m
#import "ManualAnimationTest.h"
#implementation ManualAnimationTest
-(id) init
{
if( (self=[super init]))
{
CGSize s = [CCDirector sharedDirector].winSize;
x = 0;
y = 0;
animatedSpriteColumns = 3;
animatedSpriteRows = 2;
animatedSpriteWidth = 95.0f;
animatedSpriteHeight = 125.0f;
animatedSprite = [CCSprite spriteWithFile:#"animal_animation.png" rect:CGRectMake(x * animatedSpriteWidth,y * animatedSpriteHeight,animatedSpriteWidth,animatedSpriteHeight)];
[self addChild:animatedSprite];
[animatedSprite setPosition:ccp(s.width / 2.0f, s.height / 2.0f)];
[self schedule:#selector(animateAnimatedSprite) interval:0.5f];
}
return self;
}
-(void) animateAnimatedSprite
{
[animatedSprite setTextureRect:CGRectMake(x * animatedSpriteWidth, y * animatedSpriteHeight, animatedSpriteWidth, animatedSpriteHeight)];
x +=1;
if(x > (animatedSpriteColumns - 1))
{
x = 0;
y +=1;
}
if(y > (animatedSpriteRows - 1))
{
y = 0;
}
}
#end

Can I have a UICollectionViewFlowLayout with scrollDirection different from layout direction?

The UICollectionViewFlowLayout is great, however, I want it tweaked slightly so that the scrollDirection is different from the layout direction. Examples of what I'd like is the springboard home screen or the emoji keyboards where you can swipe left/right, but the cells are laid out left to right, top to bottom (instead of top to bottom, left to right as they are with the UICollectionViewFlowLayout with scrollDirection set to horizontal). Anyone know how I can easily subclass the FlowLayout to make this change? I'm disappointed they don't have a layoutDirection in addition to scrollDirection on the UICollectionViewFlowLayout object :(
#rdelmar I implemented something similar to your solution, and that works (not as elegant as I'd like), but I noticed that occasionally items disappear from the collection unless re-drawn, which is why I didn't accept the answer. Here is what I ended up with:
#interface UICollectionViewPagedFlowLayout : UICollectionViewFlowLayout
#property int width;
#property int height;
#end
#implementation UICollectionViewPagedFlowLayout
#warning MINOR BUG: sometimes symbols disappear
- (CGSize)collectionViewContentSize {
CGSize size = [super collectionViewContentSize];
// make sure it's wide enough to cover all the objects
size.width = self.collectionView.bounds.size.width * [self.collectionView numberOfSections];
return size;
}
- (NSArray*) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes* attributes in array) {
if (CGRectIntersectsRect(attributes.frame, rect)) {
// see which section this is in
CGRect configurableRect = UIEdgeInsetsInsetRect(visibleRect, self.sectionInset);
int horizontalIndex = attributes.indexPath.row % self.width;
int verticalIndex = attributes.indexPath.row / self.width;
double xspace = (configurableRect.size.width - self.width * self.itemSize.width) / self.width;
double yspace = (configurableRect.size.height - self.height * self.itemSize.height) / self.height;
attributes.center = CGPointMake(attributes.indexPath.section * visibleRect.size.width + self.sectionInset.left + (self.itemSize.width + xspace) * horizontalIndex + self.itemSize.width / 2, self.sectionInset.top + (self.itemSize.height + yspace) * verticalIndex + self.itemSize.height / 2);
}
}
return array;
}
#end
IIRC, exactly this is demonstrated in the WWDC 2012 sessions on UICollectionView.
I don't know about easily, depends on your definition I guess. I made a project where I had the layout that's close to what you're looking for. This lays out the rows horizontally, left to right, top to bottom. My data source was an array of arrays, where each subarray provided the data for one line.
#import "SimpleHorizontalLayout.h" // subclass of UICollectionViewFlowLayout
#define kItemSize 60
#implementation SimpleHorizontalLayout
-(CGSize)collectionViewContentSize {
NSInteger xSize = [self.collectionView numberOfItemsInSection:0] * (kItemSize + 20); // the 20 is for spacing between cells.
NSInteger ySize = [self.collectionView numberOfSections] * (kItemSize + 20);
return CGSizeMake(xSize, ySize);
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path {
UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];
attributes.size = CGSizeMake(kItemSize,kItemSize);
NSInteger xValue = kItemSize/2 + path.row * (kItemSize +20) ;
NSInteger yValue = kItemSize + path.section * (kItemSize +20);
attributes.center = CGPointMake(xValue, yValue);
return attributes;
}
-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
NSInteger minRow = (rect.origin.x > 0)? rect.origin.x/(kItemSize +20) : 0; // need to check because bounce gives negative values for x.
NSInteger maxRow = rect.size.width/(kItemSize +20) + minRow;
NSMutableArray* attributes = [NSMutableArray array];
for(NSInteger i=0 ; i < self.collectionView.numberOfSections; i++) {
for (NSInteger j=minRow ; j < maxRow; j++) {
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:j inSection:i];
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
}
return attributes;
}
Until Apple adds a simple flag to change the layout orientation on flow layouts, I ended up sub-classing. Some of the stuff is specific to my implementation, but it might help someone else:
#interface UICollectionViewPagedFlowLayout : UICollectionViewFlowLayout
#property int width;
#property int height;
#end
#implementation UICollectionViewPagedFlowLayout
#warning MINOR BUG: sometimes items disappear
- (CGSize)collectionViewContentSize {
CGSize size = [super collectionViewContentSize];
size.width = self.collectionView.bounds.size.width * [self.collectionView numberOfSections];
return size;
}
- (NSArray*) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes* attributes in array) {
if (CGRectIntersectsRect(attributes.frame, rect)) {
// see which section this is in
CGRect configurableRect = UIEdgeInsetsInsetRect(visibleRect, self.sectionInset);
int horizontalIndex = attributes.indexPath.row % self.width;
int verticalIndex = attributes.indexPath.row / self.width;
double xspace = (configurableRect.size.width - self.width * self.itemSize.width) / self.width;
double yspace = (configurableRect.size.height - self.height * self.itemSize.height) / self.height;
attributes.center = CGPointMake(attributes.indexPath.section * visibleRect.size.width + self.sectionInset.left + (self.itemSize.width + xspace) * horizontalIndex + self.itemSize.width / 2, self.sectionInset.top + (self.itemSize.height + yspace) * verticalIndex + self.itemSize.height / 2);
}
}
return array;
}
#end

IPHONE SDK, How to put Void function into my BOOL??? PLEASE!

I am using the IPhone's Accelerometer to make a object move. I want to be able to make this function work and not work depending on different states.
I have my code for my Accelerometer function and i want to put it into a BOOL so i can call on it when i need it, but i am having problems. Can anyone Help me put this code into a BOOL named:
-(BOOL) accelerometerWorks
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
valueX = acceleration.x*25.5;
int newX = (int)(ball.center.x +valueX);
if (newX > 320-BALL_RADIUS)
newX = 320-BALL_RADIUS;
if (newX < 0+BALL_RADIUS)
newX = 0+BALL_RADIUS;
int XA = (int)(balloonbit1.center.x +valueX);
if (XA > 320-BALL_RADIUS)
XA = 320-BALL_RADIUS;
if (XA < 0+BALL_RADIUS)
XA = 0+BALL_RADIUS;
int XB = (int)(balloonbit2.center.x +valueX);
if (XB > 320-BALL_RADIUS)
XB = 320-BALL_RADIUS;
if (XB < 0+BALL_RADIUS)
XB = 0+BALL_RADIUS;
int XE = (int)(balloonbit5.center.x +valueX);
if (XE > 320-BALL_RADIUS)
XE = 320-BALL_RADIUS;
if (XE < 0+BALL_RADIUS)
XE = 0+BALL_RADIUS;
int XF = (int)(balloonbit6.center.x +valueX);
if (XF > 320-BALL_RADIUS)
XF = 320-BALL_RADIUS;
if (XF < 0+BALL_RADIUS)
XF = 0+BALL_RADIUS;
int XH = (int)(balloonbit8.center.x +valueX);
if (XH > 320-BALL_RADIUS)
XH = 320-BALL_RADIUS;
if (XH < 0+BALL_RADIUS)
XH = 0+BALL_RADIUS;
ball.center = CGPointMake (newX, 415);
balloonbit1.center = CGPointMake (XA, 408);
balloonbit2.center = CGPointMake (XB, 395);
balloonbit5.center = CGPointMake (XE, 388);
balloonbit6.center = CGPointMake (XF, 413);
balloonbit8.center = CGPointMake (XH, 426);
}
Please help. i have been trying for ages with no success. Thanks.
Harry.
Here's my best guess about what you're after, with nothing to verify it on.
If all you want to do is declare a BOOL value in your code, put
BOOL accelerometerWorks;
in your .h file.
Otherwise, if you want a function to check the state of the game as needed, do something like this:
-(BOOL) accelerometerWorks{
//check conditions, return YES or NO...
return time == 0;
}
and this:
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
if(![self accelerometerWorks]) return;
valueX = acceleration.x*25.5;
int newX = (int)(ball.center.x +valueX);
if (newX > 320-BALL_RADIUS)
newX = 320-BALL_RADIUS;
if (newX < 0+BALL_RADIUS)
newX = 0+BALL_RADIUS;
//etc.
}
You can't mess around with the declaration of accelerometer:didAccelerate or you'll just stop receiving the messages, but you CAN check for an invalid state inside of it.
Harry - you also might want to make the 320 a constant, like you did with BALL_RADIUS (you're going to want this to be able to work on an iPad, right? maybe?) and you might also consider factoring out the code you repeat five times into its own method. aehilrs's code should do exactly what you want for the accelerometer.
-(int) limitTravel:(position) {
if (position > MAX_POSITION-BALL_RADIUS)
return MAX_POSITION-BALL_RADIUS;
if (position < BALL_RADIUS)
return BALL_RADIUS;
}
If you decide to change how the limiting code works, you'll only have to change it one place. Your CGPoint magic numbers would be better as constants too for the same reason as the 320.

iphone code - CGPoint question

i have 10 moving objects (UIImageView),
is there a better way to write this code?
- (void) jumpOnTimer {
jumpBall1.center = CGPointMake(jumpBall1.center.x+pos1.x,jumpBall1.center.y+pos1.y);
if(jumpBall1.center.x > 60 || jumpBall1.center.x < 0)
pos1.x = -pos1.x;
if(jumpBall1.center.y > 211 || jumpBall1.center.y < 82)
pos1.y = -pos1.y;
jumpBall2.center = CGPointMake(jumpBall2.center.x+pos2.x,jumpBall2.center.y+pos2.y);
if(jumpBall2.center.x > 40 || jumpBall2.center.x < 0)
pos2.x = -pos2.x;
if(jumpBall2.center.y > 206 || jumpBall2.center.y < 82)
pos2.y = -pos2.y;
and so on...
Judging by that code snippet, it looks like you have a single controller which "owns" the ten balls, and you want the balls to bounce around according to a set of rules that are unique to each ball. A more object-oriented approach would be as follows:
#interface JumpBallClass
{
CGPoint center;
CGPoint speed;
CGPoint lowerLimit;
CGPoint upperLimit;
}
#property (assign) CGPoint lowerLimit;
#property (assign) CGPoint upperLimit;
- (void)update;
#end
#implementation JumpBallClass
- (void)update
{
center.x += speed.x;
center.y += speed.y;
if (center.x > upperLimit.x || center.x < lowerLimit.x)
{ speed.x = -speed.x; }
if (center.y > upperLimit.y || center.y < lowerLimit.y)
{ speed.y = -speed.y; }
}
#end
This setup would allow you to configure all of the balls once, by setting their upper and lower limits:
[jumpBall1 setUpperLimit:CGPointMake(60, 211)];
[jumpBall1 setLowerLimit:CGPointMake(0, 82)];
...
And then simply calling update on each ball in your timer method:
- (void) jumpOnTimer {
[jumpBall1 update];
[jumpBall2 update];
...
}
You can simplify this even further by storing all of the balls in an NSArray:
NSArray * balls = [NSArray arrayWithObjects:jumpBall1, jumpBall2, ..., nil];
And then calling makeObjectsPerformSelector:
[balls makeObjectsPerformSelector:#selector(update)];
You can make an array of jumpBalls and then loop through each and do the code for that. You can do something like this:
JumpBallClass *myjumpballs[10];
for (i=0; i<10; i++) {
myjumpballs[i].center = CGPointMake(myjumpballs[i].center.x+pos1.x,myjumpballs[i].center.y+pos1.y);
if(myjumpballs[i].center.x > 60 || myjumpballs[i].center.x < 0)
pos1.x = -pos1.x;
if(myjumpballs[i].center.y > 211 || myjumpballs[i].center.y < 82)
pos1.y = -pos1.y;
}
Looks like you're trying to manually animate. Have a look at using UIView animations instead