I am making a game with powerups. I have 3 powerups. When a powerup is active, I use an integer to identify which one it is, 1, 2, or 3, with 0 representing no active powerups. Once I activate a powerup, I want it to expire after a time interval, say 10 seconds. How do I reset the identifier integer back to 0?
For example, one powerup speeds up the ship. Here is my update method.
-(void) update:(ccTime)dt
{
if (powerupIdentifier == 0)
{
shipSpeed = 100;
}
if (powerupIdentifier == 1)
{
shipSpeed = 200;
}
CCArray* touches = [KKInput sharedInput].touches;
if ([touches count] == 1)
{
//MAKES SHIP MOVE TO TAP LOCATION
KKInput * input = [KKInput sharedInput];
CGPoint tap = [input locationOfAnyTouchInPhase:KKTouchPhaseBegan];
ship.position = ccp( ship.position.x, ship.position.y);
if (tap.x != 0 && tap.y != 0)
{
[ship stopAllActions]; // Nullifies previous actions
int addedx = tap.x - ship.position.x;
int addedy = tap.y - ship.position.y;
int squaredx = pow(addedx, 2);
int squaredy = pow(addedy, 2);
int addedSquares = squaredx + squaredy;
int distance = pow(addedSquares, 0.5);
[ship runAction: [CCMoveTo actionWithDuration:distance/shipSpeed position:tap]];//makes ship move at a constant speed
}
}
}
First, use an enum rather than an int.
typedef NS_ENUM(unsigned short, PowerUp) {
PowerUp_Level0,
PowerUp_Level1,
PowerUp_Level2,
PowerUp_Level3
};
Enum is far more readable, and is a lot more self-documenting then random integers.
Now, say we have a property:
#property (nonatomic, assign) PowerUp powerUp;
We can write a method to reset the power up:
- (void)resetPowerUp {
self.powerUp = PowerUp_Level0;
}
Now, when we've set it to some non-zero value and need to reset it (after 10 seconds), it's as simple as this:
self.powerUp = PowerUp_Level2;
[self performSelector:#selector(resetPowerUp) withObject:nil afterDelay:10.0f];
Related
I want to check if anyone enter in allocated boundary then i have to alert that user like "You are entered" and when user leaves then "You left". I am using .KML file for draw boundary in which there are more than latitude and longitude. Here i attached screenshot for the same.So, my concern is that how can i detect that anyone is entered within this boundary and left from that boundary. Thank you in advance
Boundary looks like this.Red color line is boundary.
Use map rects. Here's an example using the map's current visible rect. With regards to your question, you could use convertRegion:toRectToView: to first convert your region to a MKMapRect beforehand.
MKMapPoint userPoint = MKMapPointForCoordinate(mapView.userLocation.location.coordinate);
MKMapRect mapRect = mapView.visibleMapRect; // find visible map rect
//MKMapRect mapRect = [self getMapRectUsingAnnotations:arrCordinate];//find custom map rect
BOOL inside = MKMapRectContainsPoint(mapRect, userPoint);
MKMapRect mapRect = mapView.visibleMapRect;
Create your custom mapRect using your boundary region from multiple latitude and longitude
- (MKMapRect) getMapRectUsingAnnotations:(NSArray*)arrCordinate {
MKMapPoint points[[arrCordinate count]];
for (int i = 0; i < [arrCordinate count]; i++) {
points[i] = MKMapPointForCoordinate([arrCordinate[i] MKCoordinateValue]);
}
MKPolygon *poly = [MKPolygon polygonWithPoints:points count:[arrCordinate count]];
return [poly boundingMapRect];
}
Geofencing will not work on complex polygon shaped regions. May be you can solve the problem with some other approach. For instance divide the region into smaller CLCircularRegion and then develop aggregate logic for the case where you have to show notification for all those locationManager:didEnterRegion: and locationManager:didExitRegion: callbacks. But keep in mind that only a max of 20 simultaneous monitored regions per app are allowed.
Refer https://forums.developer.apple.com/thread/21323 phillippk1 suggestion for other possible approach.
Try this code. This is based on Winding Number Algorithm. This works for complex shapes such as your red line.
typedef struct {
double lon;
double lat;
} LATLON;
// returns true if w/in region
bool chkInRegion(LATLON poi, int npoi, LATLON *latlon)
{
int wn = 0;
for (int i = 0 ; i < npoi-1 ; i++) {
if (latlon[i].lat <= poi.lat && latlon[i+1].lat > poi.lat) {
double vt = (poi.lat - latlon[i].lat)/(latlon[i+1].lat - latlon[i].lat);
if (poi.lon < (latlon[i].lon + (vt * (latlon[i+1].lon - latlon[i].lon)))) {
wn++;
}
} else if (latlon[i].lat > poi.lat && latlon[i+1].lat <= poi.lat) {
double vt = (poi.lat - latlon[i].lat)/(latlon[i+1].lat - latlon[i].lat);
if (poi.lon < (latlon[i].lon + (vt * (latlon[i+1].lon - latlon[i].lon)))) {
wn--;
}
}
}
return wn < 0;
}
// test data
LATLON llval[] = {
{100,100},
{200,500},
{600,500},
{700,100},
{400,300},
{100,100}
};
#define NLATLON (sizeof(llval)/sizeof(LATLON))
int main(int argc, char **argv) {
while (1) {
char buf[1024];
fprintf(stderr, "lon = ");
fgets(buf, sizeof(buf), stdin);
double lon = atof(buf);
fprintf(stderr, "lat = ");
fgets(buf, sizeof(buf), stdin);
double lat = atof(buf);
LATLON ltest;
ltest.lat = lat;
ltest.lon = lon;
if (chkInRegion(ltest, NLATLON, llval)) {
fprintf(stderr, "\n*** in region ***\n\n");
} else {
fprintf(stderr, "\n=== outside ===\n\n");
}
}
return 0;
}
I am re-writing the particle filter library of iOS in Swift from Objective C which is available on Bitbucket and I have a question regarding a syntax of Objective C which I cannot understand.
The code goes as follows:
- (void)setRssi:(NSInteger)rssi {
_rssi = rssi;
// Ignore zeros in average, StdDev -- we clear the value before setting it to
// prevent old values from hanging around if there's no reading
if (rssi == 0) {
self.meters = 0;
return;
}
self.meters = [self metersFromRssi:rssi];
NSInteger* pidx = self.rssiBuffer;
*(pidx+self.bufferIndex++) = rssi;
if (self.bufferIndex >= RSSIBUFFERSIZE) {
self.bufferIndex %= RSSIBUFFERSIZE;
self.bufferFull = YES;
}
if (self.bufferFull) {
// Only calculate trailing mean and Std Dev when we have enough data
double accumulator = 0;
for (NSInteger i = 0; i < RSSIBUFFERSIZE; i++) {
accumulator += *(pidx+i);
}
self.meanRssi = accumulator / RSSIBUFFERSIZE;
self.meanMeters = [self metersFromRssi:self.meanRssi];
accumulator = 0;
for (NSInteger i = 0; i < RSSIBUFFERSIZE; i++) {
NSInteger difference = *(pidx+i) - self.meanRssi;
accumulator += difference*difference;
}
self.stdDeviationRssi = sqrt( accumulator / RSSIBUFFERSIZE);
self.meanMetersVariance = ABS(
[self metersFromRssi:self.meanRssi]
- [self metersFromRssi:self.meanRssi+self.stdDeviationRssi]
);
}
}
The class continues with more code and functions which are not important and what I do not understand are these two lines
NSInteger* pidx = self.rssiBuffer;
*(pidx+self.bufferIndex++) = rssi;
Variable pidx is initialized to the size of a buffer which was previously defined and then in the next line the size of that buffer and buffer plus one is equal to the RSSI variable which is passed as a parameter in the function.
I assume that * has something to do with reference but I just can't figure out the purpose of this line. Variable pidx is used only in this function for calculating trailing mean and standard deviation.
Let explain those code:
NSInteger* pidx = self.rssiBuffer; means that you are getting pointer of the first value of the buffer.
*(pidx+self.bufferIndex++) = rssi; means that you are setting the value of the buffer at index 0+self.bufferIndex to rssiand then increase bufferIndex by 1. Thanks to #Jakub Vano point it out.
In C++, it will look like that
int self.rssiBuffer[1000]; // I assume we have buffer like that
self.rssiBuffer[self.bufferIndex++] = rssi
I have a sorted array of times like so
[0.0, 1.2, 4.3, 5.9, 7.2, 8.0]
While an audio file plays, I want to be able to take the current time and find what the nearest, lower number is in the array.
My approach would be to traverse the array, possible in reverse order as it feels like it should be faster. Is there a better way?
The playback SHOULD be linear, but might be fast-forwarded/rewound, so I would like to come up with a solution that takes that into account, but I'm not really sure how else to approach the problem.
The method you are looking for is -[NSArray indexOfObject:inSortedRange:options:usingComparator:]. It performs a binary search. With the options:NSBinarySearchingInsertionIndex option, if the value isn't found exactly, it returns the index where the object would be inserted, which is the index of the least larger element, or the count of items in the array.
NSTimeInterval currentTime = ...;
NSUInteger index = [times indexOfObject:#(currentTime)
inSortedRange:NSMakeRange(0, times.count)
options:NSBinarySearchingInsertionIndex
usingComparator:^(id object0, id object1) {
NSTimeInterval time0 = [object0 doubleValue];
NSTimeInterval time1 = [object1 doubleValue];
if (time0 < time1) return NSOrderedAscending;
else if (time0 > time1) return NSOrderedDescending;
else return NSOrderedSame;
}];
// If currentTime was not found exactly, then index is the next larger element
// or array count..
if (index == times.count || [times[index] doubleValue] > currentTime) {
--index;
}
The fastest* way to find something in a sorted array is binary search: if there are n items, check the element at index n/2. If that element is greater than what you're looking for, check the element at index n/4; otherwise, if it's less than what you're looking for, check the element at index 3n/4. Continue subdividing in this fashion until you've found what you want, i.e. the position where the current time should be. Then you can pick the preceding element, as that's the closest element that's less than the current time.
However, once you've done that once, you can keep track of where you are in the list. As the user plays through the file, keep checking to see if the time has passed the next element and so on. In other words, remember where you were, and use that when you check again. If the user rewinds, check the preceding elements.
*Arguably, this isn't strictly true -- there are surely faster ways if you can make a good guess as to the probable location of the element in question. But if you don't know anything other than that the element appears somewhere in the array, it's usually the right approach.
I'm not sure if it's the best approach, but I think it'll get the job done (assuming your array is always ascending order).
- (NSNumber *) incrementalClosestLowestNumberForNumber:(NSNumber *)aNumber inArray:(NSArray *)array {
for (int i = 0; i < array.count; i++) {
if ([array[i] floatValue] == [aNumber floatValue]) {
return aNumber;
}
else if ([array[i] floatValue] > [aNumber floatValue]) {
int index = (i > 0) ? i - 1 : 0;
return array[index];
}
}
return #0;
}
Then call it like this:
NSArray * numbArray = #[#0.0, #1.2, #4.3, #5.9, #7.2, #8.0];
NSNumber * closestNumber = [self closestLowestNumberForNumber:#2.4 inArray:numbArray];
NSLog(#"closest number: %#", closestNumber);
I'm not sure if someone else knows a special way that is much faster.
Based on some of the other answers / comments, I came up with this, perhaps one of them can point out if a whole is somewhere.
- (NSNumber *) quartalClosestLowestNumberForNumber:(NSNumber *)compareNumber inArray:(NSArray *)array {
int low = 0;
int high = array.count - 1;
NSNumber * lastNumber;
int currentIndex = 0;
for (currentIndex = low + (high - low) / 2; low <= high; currentIndex = low + (high - low) / 2) {
NSNumber * numb = array[currentIndex];
if (numb.floatValue < compareNumber.floatValue) {
low = currentIndex + 1;
}
else if (numb.floatValue > compareNumber.floatValue) {
high = currentIndex - 1;
}
else if (numb.floatValue == compareNumber.floatValue) {
return numb;
}
lastNumber = numb;
}
if (lastNumber.floatValue > compareNumber.floatValue && currentIndex != 0) {
lastNumber = array[currentIndex - 1];
}
return lastNumber;
}
I'm really bored right now, so I'm trying to test the fastest method. Here's how I did it.
NSMutableArray * numbersArray = [NSMutableArray new];
for (int i = 0; i < 100000; i++) {
float floater = i / 100.0;
[numbersArray addObject: #(floater)];
}
// courtesy #RobMayoff
NSDate * binaryDate = [NSDate date];
NSNumber * closestNumberBinary = [self binaryClosestLowestNumberForNumber:#4.4 inArray:numbersArray];
NSLog(#"Found closest number binary: %# in: %f seconds", closestNumberBinary, -[binaryDate timeIntervalSinceNow]);
// The Quartal Version
NSDate * quartalDate = [NSDate date];
NSNumber * closestNumberQuartal = [self quartalClosestLowestNumberForNumber:#4.4 inArray:numbersArray];
NSLog(#"Found closest number quartal: %# in: %f seconds", closestNumberQuartal, -[quartalDate timeIntervalSinceNow]);
// The incremental version
NSDate * incrementalDate = [NSDate date];
NSNumber * closestNumberIncremental = [self incrementalClosestLowestNumberForNumber:#4.4 inArray:numbersArray];
NSLog(#"Found closest number incremental: %# in: %f seconds", closestNumberIncremental, -[incrementalDate timeIntervalSinceNow]);
And here's the output:
Found closest number binary: 4.4 in: 0.000030 seconds
Found closest number quartal: 4.4 in: 0.000015 seconds
Found closest number incremental: 4.4 in: 0.000092 seconds
And another test case:
Found closest number binary: 751.48 in: 0.000030 seconds
Found closest number quartal: 751.48 in: 0.000016 seconds
Found closest number incremental: 751.48 in: 0.013042 seconds
Through the code below, I can get an output such as :
0
1
1
What I want is to output the sum of these booleans values, in my case the result will be : 2 because we have 0+1+1
The code [Update] :
-(void)markers{
CLLocationCoordinate2D tg = CLLocationCoordinate2DMake(location.latitude, location.longitude);
GMSCoordinateBounds *test = [[GMSCoordinateBounds alloc]initWithPath:path];
BOOL test3 = [test containsCoordinate:tg];
{
if (test3 == 1)
{
marker.position = CLLocationCoordinate2DMake(location.latitude, location.longitude);
}else if (test3 == 0)
{
marker.position = CLLocationCoordinate2DMake(0, 0);
}
}
}
}
Rather than sum BOOLs, which is counterintuitive, loop over whatever you are using to get the BOOL values, and if you get YES, increment a counter. This will be the number of YESs that you have.
If you have an array of BOOLs, you could just filter the array with a predicate to get the YES values and the length of the resulting array is the number of YESs that you have.
Edited to add code samples following OP comments
Incrementing a counter
NSUInteger numberOfBools = 0;
CLLocationCoordinate2D tg = CLLocationCoordinate2DMake(location.latitude, location.longitude);
GMSCoordinateBounds *test = [[GMSCoordinateBounds alloc]initWithPath:path];
if ([test containsCoordinate:tg1]) { ++numberOfBools; }
if ([test containsCoordinate:tg2]) { ++numberOfBools: }
... // other tests here;
// numberOfBools now contains the number of passing tests.
Edited Again, after the full code was added
// snipped code above here
// This is where you add the counter and initialise it to 0
NSUInteger numberOfBools = 0;
for (NSDictionary *dictionary in array)
{
// Snip more code to this point
BOOL test3 = [test containsCoordinate:tg];
{
if (test3)
{
// This is where you increment the counter
++numberOfBools;
// Snip more code to the end of the for block
}
// Now numberOfBools shows how many things passed test3
int sum = (test3 ? 1 : 0) + (testX ? 1 : 0) + (testY ? 1 : 0);
And not so weird variant:
#define BOOL_TO_INT(val) ((val) ? 1 : 0)
int sum = BOOL_TO_INT(test3) + BOOL_TO_INT(testX) + BOOL_TO_INT(testY);
You can just add BOOLs since bools are just integers. e.g. :
int sum = 0;
CLLocationCoordinate2D tg = CLLocationCoordinate2DMake(location.latitude, location.longitude);
GMSCoordinateBounds *test = [[GMSCoordinateBounds alloc]initWithPath:path];
BOOL test3 = [test containsCoordinate:tg];
//Obtain bolean values :
BOOL testX = /* other test */;
BOOL testY = /* other test */;
sum = test3 + testX + testY
This is a bad idea however, as BOOLs aren't necessarily 1 or 0. They are 0 and not 0
BOOL is just a typedef-ed char: typedef signed char BOOL; YES and NO are 1 and 0, but BOOL variable = 2 is perfectly valid
For example:
- (int) testX
{
if(inState1) return 1;
if(inState2) return 2;
else return 0;
}
BOOL textXResult = [self testX]; //Might return 2, this is still equivalent to YES.
The best solution is to iterate your BOOLs and instead count the number of YESes.
Another way to do this is to assume that if any one value is false, then the entire array is false, so, loop over the array until a false value is found, then break:
BOOL retval = true; //return holder variable
/*'boolsNumArray' is an NSArray of NSNumber instances, converted from BOOLs:
//BOOL-to-NSNumber conversion (makes 'boolsNumArray' NSArray, below)!
'[myNSArray addObject:[NSNumber numberWithBool:yourNextBOOL]]'
*/
for(NSNumber* nextNum in boolsNumArray) {
if([nextNum boolValue] == false) {
retval = false;
break;
}
}
return retval;
Below is a method I wrote that takes a random number and makes sure that a sprite does repeat consecutively at the same position. I want to change it so that every new sprite takes a different position of the other two. I am not really getting it right. Please help.
- (float)randomlyChooseXValue {
CGSize s = [[CCDirector sharedDirector] winSize];
int randX = arc4random() % 3;
if (oldRandX != randX) {
if (randX == 0) {
xPos = xPos1*(s.width/480.0);
} else if (randX == 1) {
xPos = xPos2*(s.width/480.0);
} else {
xPos = xPos3*(s.width/480.0);
}
oldRandX = randX;
} else {
[self randomlyChooseXValue];
}
return xPos;
}
If I understand this correctly you need to find 3 random values and the 3rd one should be different then the 1st 2. If this is true you need to store last 2 random values and compare them in the 1st if statement:
- (float)randomlyChooseXValue {
CGSize s = [[CCDirector sharedDirector] winSize];
int randX = arc4random() % 3;
if ((oldRandX1 != randX) && (oldRandX2 != randX)) { //check for 2 values
if (randX == 0) {
xPos = xPos1*(s.width/480.0);
} else if (randX == 1) {
xPos = xPos2*(s.width/480.0);
} else {
xPos = xPos3*(s.width/480.0);
}
oldRandX2 = oldRandX1; //store 1st value to 2nd place
oldRandX1 = randX; //store new value to 1st place
} else {
[self randomlyChooseXValue];
}
return xPos;
}
Since you explained that you are okay with the sequence repeating, then you only need to really make two random choices: the first position, and the direction.
// somewhere, initialize global oldRandX = -1, dir = -1
- (float)randomlyChooseXValue {
CGSize s = [[CCDirector sharedDirector] winSize];
if (oldRandX < 0) {
oldRandX = arc4random() % 3;
dir = arc4random() % 2;
} else if (dir) {
oldRandX = (oldRandX + 1) % 3;
} else {
oldRandX = (oldRandX + 2) % 3;
}
if (randX == 0) {
xPos = xPos1*(s.width/480.0);
} else if (randX == 1) {
xPos = xPos2*(s.width/480.0);
} else {
xPos = xPos3*(s.width/480.0);
}
return xPos;
}
This can generate every possible sequence of the three positions:
0, 1, 2
0, 2, 1
1, 2, 0
1, 0, 2
2, 0, 1
2, 1, 0
and repeat them.
The other answer will achieve the same results, but like your original method, it might take several tries to get it. Your random function can keep choosing the wrong value an unbounded number of times; it becomes a worse problem when there's only one right number to pick.