3 interconnected sliders - iphone

I've been racking my brains over this problem for two days, I've tried different things but none of them work. I'm building an app which is a kind of quizz. There are three subjects which contain questions. I would like to use 3 sliders to define the percentage of questions they want on each subject.
ex : slider one = History
slider two = Maths
slider three = Grammar
If I choose to have more history, I slide the history slider up and the other sliders should decrease according to the values they have to reach 100% for the 3 sliders...
Any idea for an algorithm ? And what happens when one slider reach a zero value ?
Maths has never been my scene.
Any Help would be very much appreciated.
Thanks in advance.
Mike

Though Snowangelic's answer is good, I think it makes more sense to to constrain the ratio between the unchanged values as follows.
Let s1, s2, s3 be the current values of the sliders, so that s1+s2+s3=100. You want to solve for n1, n2, n3 the new values of the sliders, so that n1+n2+n3=100. Assume s1 is changed to n1 by the user. Then this adds the following constraint:
n2/n3 = s2/s3
So the solution to the problem, with n1+n2+n3=100, is
n2 = (100-n1)/(s3/s2 + 1) or 0 (if s2=0) and
n3 = (100-n1)/(s2/s3 + 1) or 0 (if s3=0)

Start all three sliders at 33.333...%
When the users moves a slider up say 10% : move the two other sliders down of 5%. But if one of two slider reaches 0 => only move the other one of ten percent. So it gives something like this :
User moved slider of x (my be positive or negative)
for first slider
if slider -x/2 > 0 and x/2 < 100
move this slider of -x/2
else
move the other slider of -x/2
for second slider
if slider -x/2 > 0 and x/2 < 100
move this slider of -x/2
else
move the other slider of -x/2
end
Another possibility would be to consider that the sum os the available ressources is 100, the ressources are separated into n buckets (in your case 3). When the user moves a slider, he fixes the number of ressources in the corresponding bucket. And so you may either take ressources from other bucket or put ressources in these other buckets.
You have something like :
state 1 ; modified bucket ; new number of ressources in that bucket
modification = new number of ressources in the bucket - number of rescources in the state 1
for (int i=0 ; modification > 0 ; i++){
i=i%nbr of buckets;
if(bucket i != modified bucket){
if(number of ressources in bucket i-- > 0 && number of ressources in bucket i-- < 100){
number of ressources in bucket i--;
modification --;
}
}
}
That is assuming the modification is positive (new number in the modified bucket is higher than before). This small algorithm would work with any number of buckets (sliders in your case).

The following algorithm should be reviewed and of course optimized. It is only something that I have put together and I've not tested it.
initialize each slider with a max and minimum value and set the inital value as desired, but respecting that x + y + z = 1.
[self.slider1 setMinimumValue:0.0];
[self.slider1 setMaximumValue:1.0];
[self.slider1 setValue:0.20];
[self.slider2 setMinimumValue:0.0];
[self.slider2 setMaximumValue:1.0];
[self.slider2 setValue:0.30];
[self.slider3 setMinimumValue:0.0];
[self.slider3 setMaximumValue:1.0];
[self.slider3 setValue:0.50];
Set the three slider to the same selector:
[self.slider1 addTarget:self action:#selector(valueChanged:) forControlEvents:UIControlEventValueChanged];
[self.slider2 addTarget:self action:#selector(valueChanged:) forControlEvents:UIControlEventValueChanged];
[self.slider3 addTarget:self action:#selector(valueChanged:) forControlEvents:UIControlEventValueChanged];
The selector should do something like that:
- (void)valueChanged:(UISlider *)slider {
UISlider *sliderX = nil;
UISlider *sliderY = nil;
UISlider *sliderZ = nil;
if (slider == self.slider1) {
sliderX = self.slider1;
sliderY = self.slider2;
sliderZ = self.slider3;
} else if (slider == self.slider2) {
sliderY = self.slider1;
sliderX = self.slider2;
sliderZ = self.slider3;
} else {
sliderY = self.slider1;
sliderZ = self.slider2;
sliderX = self.slider3;
}
float x = sliderX.value;
float y = sliderY.value;
float z = sliderZ.value;
// x + y + z = 1
// Get the amout x has changed
float oldX = 1 - y - z;
float difference = x - oldX;
float newY = y - difference / 2;
float newZ = z - difference / 2;
if (newY < 0) {
newZ += y + newY;
newY = 0;
}
if (newZ < 0) {
newY += z + newZ;
newZ = 0;
}
[sliderY setValue:newY animated:YES];
[sliderZ setValue:newZ animated:YES];
}
If there is something wrong with this code, please let me know, and I can fix it!

Related

Procedural structure generation

I have a voxel based game in development right now and I generate my world by using Simplex Noise so far. Now I want to generate some other structures like rivers, cities and other stuff, which can't be easily generated because I split my world (which is practically infinite) into chunks of 64x128x64. I already generated trees (the leaves can grow into neighbouring chunks), by generating the trees for a chunk, plus the trees for the 8 chunks surrounding it, so leaves wouldn't be missing. But if I go into higher dimensions that can get difficult, when I have to calculate one chunk, considering chunks in an radius of 16 other chunks.
Is there a way to do this a better way?
Depending on the desired complexity of the generated structure, you may find it useful to first generate it in a separate array, perhaps even a map (a location-to-contents dictionary, useful in case of high sparseness), and then transfer the structure to the world?
As for natural land features, you may want to google how fractals are used in landscape generation.
I know this thread is old and I suck at explaining, but I'll share my approach.
So for example 5x5x5 trees. What you want is for your noise function to return the same value for an area of 5x5 blocks, so that even outside of the chunk, you can still check if you should generate a tree or not.
// Here the returned value is different for every block
float value = simplexNoise(x * frequency, z * frequency) * amplitude;
// Here it will return the same value for an area of blocks (you should use floorDiv instead of dividing, or you it will get negative coordinates wrong (-3 / 5 should be -1, not 0 like in normal division))
float value = simplexNoise(Math.floorDiv(x, 5) * frequency, Math.floorDiv(z, 5) * frequency) * amplitude;
And now we'll plant a tree. For this we need to check what x y z position this current block is relative to the tree's starting position, so we can know what part of the tree this block is.
if(value > 0.8) { // A certain threshold (checking if tree should be generated at this area)
int startX = Math.floorDiv(x, 5) * 5; // flooring the x value to every 5 units to get the start position
int startZ = Math.floorDiv(z, 5) * 5; // flooring the z value to every 5 units to get the start position
// Getting the starting height of the trunk (middle of the tree , that's why I'm adding 2 to the starting x and starting z), which is 1 block over the grass surface
int startY = height(startX + 2, startZ + 2) + 1;
int relx = x - startX; // block pos relative to starting position
int relz = z - startZ;
for(int j = startY; j < startY + 5; j++) {
int rely = j - startY;
byte tile = tree[relx][rely][relz]; // Get the needing block at this part of the tree
tiles[i][j][k] = tile;
}
}
The tree 3d array here is almost like a "prefab" of the tree, which you can use to know what block to set at the position relative to the starting point. (God I don't know how to explain this, and having english as my fifth language doesn't help me either ;-; feel free to improve my answer or create a new one). I've implemented this in my engine, and it's totally working. The structures can be as big as you want, with no chunk pre loading needed. The one problem with this method is that the trees or structures will we spawned almost within a grid, but this can easily be solved with multiple octaves with different offsets.
So recap
for (int i = 0; i < 64; i++) {
for (int k = 0; k < 64; k++) {
int x = chunkPosToWorldPosX(i); // Get world position
int z = chunkPosToWorldPosZ(k);
// Here the returned value is different for every block
// float value = simplexNoise(x * frequency, z * frequency) * amplitude;
// Here it will return the same value for an area of blocks (you should use floorDiv instead of dividing, or you it will get negative coordinates wrong (-3 / 5 should be -1, not 0 like in normal division))
float value = simplexNoise(Math.floorDiv(x, 5) * frequency, Math.floorDiv(z, 5) * frequency) * amplitude;
if(value > 0.8) { // A certain threshold (checking if tree should be generated at this area)
int startX = Math.floorDiv(x, 5) * 5; // flooring the x value to every 5 units to get the start position
int startZ = Math.floorDiv(z, 5) * 5; // flooring the z value to every 5 units to get the start position
// Getting the starting height of the trunk (middle of the tree , that's why I'm adding 2 to the starting x and starting z), which is 1 block over the grass surface
int startY = height(startX + 2, startZ + 2) + 1;
int relx = x - startX; // block pos relative to starting position
int relz = z - startZ;
for(int j = startY; j < startY + 5; j++) {
int rely = j - startY;
byte tile = tree[relx][rely][relz]; // Get the needing block at this part of the tree
tiles[i][j][k] = tile;
}
}
}
}
So 'i' and 'k' are looping withing the chunk, and 'j' is looping inside the structure. This is pretty much how it should work.
And about the rivers, I personally haven't done it yet, and I'm not sure why you need to set the blocks around the chunk when generating them ( you could just use perlin worms and it would solve problem), but it's pretty much the same idea, and for your cities too.
I read something about this on a book and what they did in these cases was to make a finer division of chunks depending on the application, i.e.: if you are going to grow very big objects, it may be useful to have another separated logic division of, for example, 128x128x128, just for this specific application.
In essence, the data resides is in the same place, you just use different logical divisions.
To be honest, never did any voxel, so don't take my answer too serious, just throwing ideas. By the way, the book is game engine gems 1, they have a gem on voxel engines there.
About rivers, can't you just set a level for water and let rivers autogenerate in mountain-side-mountain ladders? To avoid placing water inside mountain caveats, you could perform a raycast up to check if it's free N blocks up.

make object move from 1 point to another at a custom speed

I made an app which there is an object that moves towards a moving point all the time - that is why I didn't use any animated function. The problem is that I made this function:
CGPoint center = self.im.center; // "i" is a CGPoint, im is an imageview.
if (!CGPointEqualToPoint(self.im.center, i))
{
a = (i.y-center.y)/(i.x-center.x);
//Y = a*X+b - this is a linear function in math
b = (center.y-(a*center.x));
if (i.y>center.y) {
self.im.center = CGPointMake(((center.y+1)-b)/a, center.y+1);
}
else
{
self.im.center = CGPointMake(((center.y-1)-b)/a, center.y-1);
}
}
The problem is that the closer the functions is becoming a straight horizontal line its faster because the change is mostly to the X axis which means that if I add 1 to Y the change to X is bigger which means it will move faster..
If there is another way to do this i will be glad to try it so if you know other ways tell me!
Managed to find a different solution
CGPoint center = self.im.center;//im = the image view
x = center.x;//starting point
y = center.y;//starting point
double distance = sqrtf(powf(i.x - x, 2) + powf(i.y - y, 2));// i = cgpoint (ending point)
float speedX = (2 * (i.x - x)) / distance;//(the 2 is the speed)
float speedY = (2 * (i.y - y)) / distance;//(the 2 is the speed)
self.im.center = CGPointMake(center.x+speedX, center.y+speedY);//im = the image view

laying out images in UIScrollView automatically

i have a list of images retrieved from xml i want to populate them to a uiscrollview in an order such that it will look like this.
1 2 3
4 5 6
7 8 9
10
if there is only 10 images it will just stop here.
right now my current code is this
for (int i = 3; i<[appDelegate.ZensaiALLitems count]-1; i++) {
UIButton *zenbutton2 =[UIButton buttonWithType:UIButtonTypeCustom];
Items *ZensaiPLUitems = [appDelegate.ZensaiALLitems objectAtIndex:i];
NSURL *ZensaiimageSmallURL = [NSURL URLWithString:ZensaiPLUitems.ZensaiimageSmallURL];
NSLog(#"FVGFVEFV :%#", ZensaiPLUitems.ZensaiimageSmallURL);
NSData *simageData = [NSData dataWithContentsOfURL:ZensaiimageSmallURL];
UIImage *itemSmallimage = [UIImage imageWithData:simageData];
[zenbutton2 setImage:itemSmallimage forState:UIControlStateNormal];
zenbutton2.frame=CGRectMake( (i*110+i*110)-660 , 300, 200, 250);
[zenbutton2 addTarget:self action:#selector(ShowNextZensaiPage) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:zenbutton2];
}
notice the CGRectMake , i have to manually assign fixed values to position them.
Is there any way to populate them out without manually assigning.
for e.g the images will automatically go down a position once the first row has 3 images and subsequently for the rest.
If I understand what you are saying, you should be able to write a simple block of code that assigns a position based on the image number.
Something like this (where i is the image number, starting from 0):
- (CGPoint)getImageOrigin:(NSInteger)imageNumber {
CGFloat leftInset = 30;
CGFloat xOffsetBetweenOrigins = 80;
CGFloat topInset = 20;
CGFloat yOffsetBetweenOrigins = 80;
int numPerRow = 3;
CGFloat x = leftInset + (xOffsetBetweenOrigins * (imageNumber % numPerRow));
CGFloat y = topInset + (yOffsetBetweenOrigins * floorf(imageNumber / numPerRow));
CGPoint imageOrigin = CGPointMake(x, y);
return imageOrigin;
}
The origin being calculated here is the upper left corner of each image.
To calculate the x value, I start with the minimum distance from the left side of the screen (leftInset). Then, I add the distance from the left side of one image to the next image, multiplied by the column (imageNumber % numPerRow).
Y is calculated in a similar fashion, but to calculate the row, I use the imageNumber / numPerRow rounded down.
Edit:
You asked me to explain further, so I'll see what I can do.
OK, so I want to be able to input the image number (starting at 0) into my function, and I want the origin (upper left corner point) back.
leftInset is the distance between the left edge of the view, and the left edge of the first image.
xOffsetBetweenOrigins is the distance from the left edge of one image to the left edge of the next image on the same row. So, if I set it to 80 and my image is 50px wide, there will be a 30px gap between two images in the same row.
topInset is like left inset. It is the distance from the top edge of the view to the top edge of the images in the top row.
yOffsetBetweenOrigins is the distance from the top edge of an image to the top edge of the image below it. If I set this to 80, and my image is 50px tall, then there will be a 30px vertical gap between rows.
numPerRow is straightforward. It is just the number of images per row.
To calculate the x value of the upper left corner of the image, I always start with the leftInset, because it is constant. If I am on the first image of a row, that will be the entire x value. If I am on the second image of the row, I need to add xOffsetBetweenOrigins once, and if I am on the third, I need to add it twice.
To do this, I use the modulus (%) operator. It gives me the remainder of a division operation, so when I say imageNumber % numPerRow, I am asking for the remainder of imageNumber/numPerRow.
If I am on the first image (imageNumber = 0), then 3 goes into 0 no times, and the remainder is 0. If I am on the second image (imageNumber = 1), then I have 1/3. 3 goes into 1 0 times, but the remainder is 1, so I get xOffsetBetweenOrigins*1.
For the y value, I do something similar, but instead of taking the modulus, I simply divide imageNumber/numPerRow and round down. Doing this, I will get 0 for 0, 1, and 2. I will get 1 for 3, 4, and 5.
Edit:
It occurred to me that you might actually have been asking how to use this method. In your code, you would say something like
CGRect newFrame = zenbutton2.frame;
newFrame.origin = [self getImageOrigin:i];
zenbutton2.frame = newFrame;
Another Edit:
Maybe you could try this?
CGPoint origin = [self getImageOrigin:i];
zenbutton2.frame = CGRectMake(origin.x, origin.y, width, height);
If that doesn't work, throw in
NSLog("Origin Values: %f,%f", origin.x, origin.y);
to make sure that you are actually getting something back from getImageOrigin.
I think you probably want to wrap your loop in another loop, to get what I'm going to call a 2D loop:
for (int row = 0; row < num_rows; row++) {
for (int col = 0; col < num_cols; col++) {
// code before
zenButton2.frame = CGRectMake(origin x dependent on col,
origin y dependent on row,
width,
height);
// code after
}
}
Where the x and y of the CGRectMake() are multiples of the width and height of your image times the row and column respectively. Hope that makes sense.

How do I improve the accuracy of this pedometer algorithm?

I've tried several ways of measuring the steps a user makes with an iPhone by reading the accelerometer, but none have been very accurate. The most accurate implementation I've used is the following:
float xx = acceleration.x;
float yy = acceleration.y;
float zz = acceleration.z;
float dot = (mOldAccX * xx) + (mOldAccY * yy) + (mOldAccZ * zz);
float a = ABS(sqrt(mOldAccX * mOldAccX + mOldAccY * mOldAccY + mOldAccZ * mOldAccZ));
float b = ABS(sqrt(xx * xx + yy * yy + zz * zz));
dot /= (a * b);
if (dot <= 0.994 && dot > 0.90) // bounce
{
if (!isChange)
{
isChange = YES;
mNumberOfSteps += 1;
} else {
isChange = NO;
}
}
mOldAccX = xx;
mOldAccY = yy;
mOldAccZ = zz;
}
However, this only catches 80% of the user's steps. How can I improve the accuracy of my pedometer?
Here is some more precise answer to detect each step. But yes in my case I am getting + or - 1 step with every 25 steps. So I hope this might be helpful to you. :)
if (dot <= 0.90) {
if (!isSleeping) {
isSleeping = YES;
[self performSelector:#selector(wakeUp) withObject:nil afterDelay:0.3];
numSteps += 1;
self.stepsCount.text = [NSString stringWithFormat:#"%d", numSteps];
}
}
- (void)wakeUp {
isSleeping = NO;
}
ok, I'm assuming this code is within the addAcceleration function...
-(void)addAcceleration:(UIAcceleration*)accel
So, you could increase your sampling rate to get a finer granularity of detection. So for example, if you are currently taking 30 samples per second, you could increase it to 40, 50, or 60 etc... Then decide if you need to count a number of samples that fall within your bounce and consider that a single step. It sounds like you are not counting some steps due to missing some of the bounces.
Also, what is the purpose of toggling isChange? Shouldn't you use a counter with a reset after x number of counts? If you are within your bounce...
if (dot <= 0.994 && dot > 0.90) // bounce
you would have to hit this sweet spot 2 times, but the way you have set this up, it may not be two consecutive samples in a row, it may be a first sample and a 5th sample, or a 2nd sample and an 11th sample. That is where you are loosing step counts.
Keep in mind that not everyone makes the same big steps. So the dot calculation should be adjusted according to someone's length, step size.
You should adjust the bounce threshold accordingly. Try to make the program learn about it's passenger.

Making a visual bar timer for iPhone

I've looked up all results for progress bars and changing the width of an image but it only refers to scaling, and the progress bars aren't customizable so that they fit other functions or design schemes... unless I missed that part.
I'm trying to make a bar timer that crops off of the right over a period of time. I tried using an NStimer so that it would subtract from a value each time its function is called.
the Timerbar function gets called as a result of another timer invalidating and it works.
What doesn't work is that the width isn't changing just the position. further more I keep getting values like Inf and 0 for power and pwrBarWidth I was sure that the changes would occur when Mult was plugged into the equation. it seems like casting mult as an int is causing problems but i'm not sure exactly how.
int pwrBarMaxWidth = 137;
int pwrBarWidth 0;
int limit = 1;
float mult;
float power = 0;
-(void) Timerbar:(NSTimer *)barTimer {
if(!waitForPlayer) {
[barTimer invalidate];
}
if(mult > 0.0) {
mult -= 0.001 * [colorChoices count];
if(mult < 0.0) {
mult = 0.0;
}
}
power = (mult * 10) / pwrBarMaxWidth;
pwrBarWidth = (int)power % limit; // causes the bar to repeat after it reaches a certain point
//At this point however the variable Power is always "inf" and PwrBarWidth is always 0.
[powerBar setBounds:CGRectMake(powerBar.frame.origin.x,
powerBar.frame.origin.y,pwrBarWidth,20)]; //supposed to change the crop of the bar
}
Any reason why I'm getting inf as a value for power, 0 as a value for pwrBarWidth, and the bar itself isn't cropping? if this question is a bit vague i'll provide more information as needed.
incorrect formatting, used state icons for bar width