Gauge animation on iphone - iphone

I'm trying to implement a gauge animation using (+ and - buttons) on iphone, but i have no idea where to start? Any help is really welcome. See the image below (this is what I'm trying to do). Thanks for your help.

Here is some open source code (with an example) that implements the gauge view. You of course would still need to do the buttons yourself, and possible add a different visual style.
http://www.cocoacontrols.com/platforms/ios/controls/meterview

You need to rotate the needle based on the angle... Here is the logic
You can refer my answer here... Rotating a UIImageView around a point over 10 seconds?
fireInterval = 10;
//Adjust starting and ending angle
mStartingAngle = 45;
mEndingAngle = 180;
//Implementation
-(void) startTimer
{
mPreviousTime = [NSDate timeIntervalSinceReferenceDate];
}
In the loop
-(void) updateFunction
{
NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate];
//NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
//Mapping values between mStartAngle and mEndAngle
mCurrentAngle = (((timeNow - mPreviousTime) * (mEndingAngle - mStartingAngle)) / (previousTime+fireInterval - mPreviousTime)) + mStartingAngle;
if( mPreviousTime + fireInterval <= timeNow )
{
NSLog(#"10 seconds completed");
mPreviousTime = timeNow;
}
}
And rotate the needle based on mCurrentAngle....

Related

iOS Accelerometer-Based Gesture Recognition

I want to create a project that reads the user's gesture (accelerometer-based) and recognise it, I searched a lot but all I found was too old, I neither have problems in classifying nor in recognition, I will use 1 dollar recogniser or HMM, I just want to know how to read the user's gesture using the accelerometer.
Is the accelerometer data (x,y,z values) enough or should i use other data with it like Attitude data (roll, pitch, yaw), Gyro data or magnitude data, I don't even understand anyone of them so explaining what does these sensors do will be useful.
Thanks in advance !
Finally i did it, i used userAcceleration data which is device acceleration due to device excluding gravity, i found a lot of people use the normal acceleration data and do a lot of math to remove gravity from it, now it's already done by iOS 6 in userAcceleration.
And i used 1$ recognizer which is a 2D recongnizer (i.e. point(5, 10), no Z).Here's a link for 1$ recognizer, there's a c++ version of it in the downloads section.
Here are the steps of my code...
Read userAcceleration data with frequancy 50 HZ.
Apply low pass filter on it.
Take a point into consideration only if its x or y values are greater than 0.05 to reduce noise. (Note: The next step depends on your code and on the recognizer you use).
Save x and y points into array.
Create a 2D path from this array.
Send this path to the recognizer to weather train it or recongize it.
Here's my code...
#implementation MainViewController {
double previousLowPassFilteredAccelerationX;
double previousLowPassFilteredAccelerationY;
double previousLowPassFilteredAccelerationZ;
CGPoint position;
int numOfTrainedGestures;
GeometricRecognizer recognizer;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
previousLowPassFilteredAccelerationX = previousLowPassFilteredAccelerationY = previousLowPassFilteredAccelerationZ = 0.0;
recognizer = GeometricRecognizer();
//Note: I let the user train his own gestures, so i start up each time with 0 gestures
numOfTrainedGestures = 0;
}
#define kLowPassFilteringFactor 0.1
#define MOVEMENT_HZ 50
#define NOISE_REDUCTION 0.05
- (IBAction)StartAccelerometer
{
CMMotionManager *motionManager = [CMMotionManager SharedMotionManager];
if ([motionManager isDeviceMotionAvailable])
{
[motionManager setDeviceMotionUpdateInterval:1.0/MOVEMENT_HZ];
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue]
withHandler: ^(CMDeviceMotion *motion, NSError *error)
{
CMAcceleration lowpassFilterAcceleration, userAcceleration = motion.userAcceleration;
lowpassFilterAcceleration.x = (userAcceleration.x * kLowPassFilteringFactor) + (previousLowPassFilteredAccelerationX * (1.0 - kLowPassFilteringFactor));
lowpassFilterAcceleration.y = (userAcceleration.y * kLowPassFilteringFactor) + (previousLowPassFilteredAccelerationY * (1.0 - kLowPassFilteringFactor));
lowpassFilterAcceleration.z = (userAcceleration.z * kLowPassFilteringFactor) + (previousLowPassFilteredAccelerationZ * (1.0 - kLowPassFilteringFactor));
if (lowpassFilterAcceleration.x > NOISE_REDUCTION || lowpassFilterAcceleration.y > NOISE_REDUCTION)
[self.points addObject:[NSString stringWithFormat:#"%.2f,%.2f", lowpassFilterAcceleration.x, lowpassFilterAcceleration.y]];
previousLowPassFilteredAccelerationX = lowpassFilterAcceleration.x;
previousLowPassFilteredAccelerationY = lowpassFilterAcceleration.y;
previousLowPassFilteredAccelerationZ = lowpassFilterAcceleration.z;
// Just viewing the points to the user
self.XLabel.text = [NSString stringWithFormat:#"X : %.2f", lowpassFilterAcceleration.x];
self.YLabel.text = [NSString stringWithFormat:#"Y : %.2f", lowpassFilterAcceleration.y];
self.ZLabel.text = [NSString stringWithFormat:#"Z : %.2f", lowpassFilterAcceleration.z];
}];
}
else NSLog(#"DeviceMotion is not available");
}
- (IBAction)StopAccelerometer
{
[[CMMotionManager SharedMotionManager] stopDeviceMotionUpdates];
// View all the points to the user
self.pointsTextView.text = [NSString stringWithFormat:#"%d\n\n%#", self.points.count, [self.points componentsJoinedByString:#"\n"]];
// There must be more that 2 trained gestures because in recognizing, it gets the closest one in distance
if (numOfTrainedGestures > 1) {
Path2D path = [self createPathFromPoints]; // A method to create a 2D path from pointsArray
if (path.size()) {
RecognitionResult recongnitionResult = recognizer.recognize(path);
self.recognitionLabel.text = [NSString stringWithFormat:#"%s Detected with Prob %.2f !", recongnitionResult.name.c_str(),
recongnitionResult.score];
} else self.recognitionLabel.text = #"Not enough points for gesture !";
}
else self.recognitionLabel.text = #"Not enough templates !";
[self releaseAllVariables];
}

Setting interval value for UISlider

I need to set the interval value for an UISlider.
Please help..
yourSlider.value = x;
You should really read the documentation, lots of great resources in the iOS Developer Center.
Edit: With regards to your more specific question in the comments:
yourSlider.minimumValue = -10;
yourSlider.maximumValue = 10;
[yourSlider addTarget:self action:#selector(roundValue) forControlEvents:UIControlEventValueChanged];
- (void)roundValue{
yourSlider.value = round(yourSlider.value);
}
A flexible solution:
// define MIN_VALUE, MAX_VALUE and INTERVAL somewhere, such as 3, 18 and 3
slider.TouchUpInside += delegate {
touchUpInside();
};
/// <summary>
/// set value to one of intervals
/// </summary>
void touchUpInside(){
// get the nearest interval value
for(int i=MIN_VALUE; i<=MAX_VALUE; i=i+INVERVAL){
if(slider.Value > i && slider.Value < i + INVERVAL){
if(slider.Value - i < i + INVERVAL - slider.Value){
slider.Value = i;
}else{
slider.Value = i + INVERVAL;
}
break;
}
}
}
I know this question is old but I just want to share how I did this.
Assuming that the UISlider object has already been initialized, first, the minimum and maximum values of the UISlider object must be set:
mySlider.minimumValue = -2.0;
mySlider.maximumValue = 2.0;
Then, set the selector that will handle the changes in the slider:
[mySlider addTarget:self action:#selector(sliderDidChangeValue:) forControlEvents:UIControlEventValueChanged];
Also, set the interval (to a property). It is important that the interval is positive. (And, really, the INTERVAL MUST BE POSITIVE.)
self.interval = 0.5 //_interval is float
Declare the method(s):
- (void)sliderDidChangeValue:(id)sender
{
UISlider *slider = (UISlider *)sender;
//Round the value to the a target interval
CGFloat roundedValue = [self roundValue:slider.value];
//Snap to the final value
[slider setValue:roundedValue animated:NO];
}
- (float)roundValue:(float)value
{
//get the remainder of value/interval
//make sure that the remainder is positive by getting its absolute value
float tempValue = fabsf(fmodf(value, _interval)); //need to import <math.h>
//if the remainder is greater than or equal to the half of the interval then return the higher interval
//otherwise, return the lower interval
if(tempValue >= (_interval / 2.0)){
return value - tempValue + _interval;
}
else{
return value - tempValue;
}
}
int sliderValue = kSliderInterval * floor((slider.value / kSliderInterval) + 0.5);
UISliders do not 'increment' their value, they increase or decrease their value according to how they're touched. You can use these properties to set the slider limits:
slider.minimumValue = 0.0;
slider.maximumValue = 0.5;
i would suggest is that put the level just below the slider where you want to put value and set maximum and minimum value then the in between value can be calculated by no of point and by division and finally display in uilabel the values.
hope this will help
good luck

Rotating a UIImageView around a point over 10 seconds?

I have a UIImageView setup called needleImageView which i need to rotate 360degrees over 10 seconds the point 20.00 20.00 of the ImageView.
Anybody able to show me sample code for this functionality?
Thanks,
-Code
Here is the logic... Try implementing.
On starting timer
//in header file
fireInterval = 10;
mStartingAngle = 0;
mEndingAngle = 360;
//Implementation
-(void) startTimer
{
mPreviousTime = [NSDate timeIntervalSinceReferenceDate];
}
In the loop
-(void) updateFunction
{
NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate];
//NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
//Mapping values between mStartAngle and mEndAngle
mCurrentAngle = (((timeNow - mPreviousTime) * (mEndingAngle - mStartingAngle)) / (previousTime+fireInterval - mPreviousTime)) + mStartingAngle;
if( mPreviousTime + fireInterval <= timeNow )
{
NSLog(#"10 seconds completed");
mPreviousTime = timeNow;
}
}

flowCover - find out which item is in the centre (being displayed) iPhone

I am using http://www.chaosinmotion.com/flowcover.m and would like to know how I may display a label for each image when it is displayed in the flowcover (the current image)
Thanks,
:)
I suggest reading the documentation before posting questions. With no familiarity with this library at all, in 30 seconds, I downloaded the source, found the docs, and skimmed until I found - (void)flowCover:(FlowCoverView *)view didSelect:(int)cover, which appears to be a delegate method.
At a glance, it looks like you're not meant to know what's front and center, only what the user picked (which may very well mean "what just became front and center"). Test it and see.
You can easily get this notification by changing the Delegate Protocol in FlowCoverView.h like this:
#protocol FlowCoverViewDelegate
- (int)flowCoverNumberImages:(FlowCoverView *)view;
- (UIImage *)flowCover:(FlowCoverView *)view cover:(int)cover;
- (void)flowCover:(FlowCoverView *)view didSelect:(int)cover;
- (void)flowCover:(FlowCoverView *)view highlighted:(int)cover; //<-- Added
#end
And replacing your -[FlowCoverView driveAnimation] method in FlowCoverView.m with this:
- (void)driveAnimation
{
double elapsed = CACurrentMediaTime() - startTime;
if (elapsed >= runDelta) [self endAnimation];
else [self updateAnimationAtTime:elapsed];
/*
* Change by Uppfinnarn <uppfinnarn#gmail.com>.
* This will give the Delegate a message every time the highlighted cover (eg. the one in the center) changes.
* Can be used to display subtitles for example.
*/
if (delegate) [delegate flowCover:self highlighted:(int)floor(offset + 0.01)]; // make sure .99 is 1
}
Create a UILabel somewhere and place it on top of the FlowCoverView (make sure it's opaque is NO so that it doesn't create a black box behind it), then monitor -[flowCover:highlighted:] to know which cover is currently in the center and change the text accordingly.
Note that this won't give you a notification for when the view is first created, only once the animation moves. You have to figure out the first title yourself.
Also, this won't give you notifications while the user is dragging with their finger, only when it's "gliding freely".
EDIT:
Replace your -[FlowCoverView touchesMoved:withEvent:] method with this to get callbacks when the user is dragging with their fingers too:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect r = self.bounds;
UITouch *t = [touches anyObject];
CGPoint where = [t locationInView:self];
double pos = (where.x / r.size.width) * 10 - 5;
if (touchFlag) {
// determine if the user is dragging or not
int dx = fabs(where.x - startTouch.x);
int dy = fabs(where.y - startTouch.y);
if ((dx < 3) && (dy < 3)) return;
touchFlag = NO;
}
int max = [self numTiles]-1;
offset = startOff + (startPos - pos);
if (offset > max) offset = max;
if (offset < 0) offset = 0;
/*
* Change by Uppfinnarn <uppfinnarn#gmail.com>.
* Based on Ilkka Pirttimaa <ilkka.pirttimaa#gmail.com>'s solution for notifications.
* when the animation stops.
*
* This will give the Delegate a message every time the highlighted cover (eg. the one in the center) changes.
* Can be used to display subtitles for example.
*/
if(delegate) [delegate flowCover:self highlighted:(int)floor(offset + 0.01)];
[self draw];
double time = CACurrentMediaTime();
if (time - startTime > 0.2) {
startTime = time;
lastPos = pos;
}
}

Can we change dynamically the interval of "schedule"?

I'm making a game on iPhone using cocos2d, and I have a question.
In my init method I'm doing this :
[self schedule:#selector(newMonster:) interval:1];
It create a new monster every second.
But I'd like that the interval change over time. For example :
The 10 first seconds of the game: a new monster appears every 1 second.
Then for 10 seconds: a new monster appears every 0.8 second.
And after every 0.5 second...
How can I do that?
Thanks !
You may try this- (I have copied some code from #bddckr)
Initial time:
self.monsterSpawnStartDate = [NSDate date];
self.lastTimeScheduledBefore = 0;//new var
Scheduled Method to create monster
- (void)scheduledMethod {
NSTimeInterval seconds = [[NSDate date] timeIntervalSinceDate:monsterSpawnStartDate];
[self newMonster]; // Let a new monster spawn
if (seconds >= 20.0 && lastTimeScheduledBefore == 10){
[self unschedule:#(scheduledMethod)];
[self unschedule:#(scheduledMethod) interval:0.5];
lastTimeScheduledBefore = 20;
}
else if (seconds >= 10.0 && lastTimeScheduledBefore == 0){
[self unschedule:#(scheduledMethod)];
[self unschedule:#(scheduledMethod) interval:0.8]
lastTimeScheduledBefore = 10;
}
}
You can modify it as your need. You can use mod if it goes through a cycle.
Make an instance variable and property of NSDate called monsterSpawnStartDate, make it an retaining property and synthesize it.
As soon as your first monster should be created, set it:
self.monsterSpawnStartDate = [NSDate date]; // Current date and time
And replace your code by this:
[self schedule:#selector(adjustMonsterSpawnRate) interval:0.1]; // Seems like you want it to fire every 0.1 seconds
Implement adjustMonsterSpawnRate like this:
- (void)adjustMonsterSpawnRate {
NSTimeInterval seconds = [[NSDate date] timeIntervalSinceDate:monsterSpawnStartDate];
if (((seconds <= 10.0) && (seconds % 1.0)) || ((seconds <= 20.0) && (seconds % 0.8)) ((seconds > 20.0) && (seconds % 0.5)))
[self newMonster]; // Let a new monster spawn
}
I think a better option would be to use a scheduled function for timing and use accumulated time to trigger the enemy creation as follows
self.time_since_last_monster = 0
[self schedule:#selector(new_monster:) interval:0.3];
-(void) new_monster:(ccTime)dt{
self.time_since_last_monster += dt;
if(self.time_since_last_monster > monster_interval){
self.time_since_last_monster -= monster_interval;
[self create_new_monster];
// at this point based on some condition, you can now change monster_interval
}
}
This would give more flexibility.
I'm pretty dumb, so here's what I'd do:
in the .h set a float
float nextMonsterIn;
then in the body
nextMonsterIn = 1.0;
[self scheduleOnce:#selector(newMonster:) interval:nextMonsterIn];
[self schedule:#selector(kickUpDifficulty:) interval:10];
- (void) newMonster : (ccTime) dt
{
[self scheduleOnce:#selector(newMonster:) interval:nextMonsterIn];
//-----make a monster-----
}
- (void) kickUpDifficulty : (ccTime) dt
{
if(nextMonsterIn == 1.0)
nextMonsterIn = 0.8;
else if(nextMonsterIn == 0.8)
{
nextMonsterIn = 0.5;
[self unschedule:#selector(kickUpDifficulty:)];
}
}
Basically every time I call newMonster i'd recursively re-schedule the newMonster based on my current delay, then I can adjust the delay in a timer or every time a monster is killed or wherever.