Check how close UILabels are to each other - objective-c

I am trying to make a game which has a jumbled up algebra equation. I have assigned an outlet to each component of the equation. For example, if the equation was:
x2 + y = 2(a+b)
Then x2 (which is x squared), +, y, = and 2(a+b) would all be its own outlet. But the equation is going to be jumbled up and I want the user to move the label outlets to the correct order. I have enabled touchesMoved, but my problem lies in checking if the equation is in the correct order. I would wrap the code into an IBAction button action, but how do I analyze the text? Would I check for the offset between each label? Is there an easy way/API to do this? Thanks!

Assuming your labels are called xLabel,plusLabel, yLabel, equalsLabel, and abLabel, you could do something like this:
NSUInteger xLeftBorder = CGRectGetMinX(xLabel.frame);
NSUInteger plusLeftBorder = CGRectGetMinX(plusLabel.frame);
NSUInteger yLeftBorder = CGRectGetMinX(yLabel.frame);
NSUInteger equalsLeftBorder = CGRectGetMinX(equalsLabel.frame);
NSUInteger abLeftBorder = CGRectGetMinX(abLabel.frame);
if(xLeftBorder < plusLeftBorder && plusLeftBorder < yLeftBorder && yLeftBorder < equalsLeftBorder && equalsLeftBorder < abLeftBorder){
//Correct!
}
else{
//Incorrect
}
This is kind of clumsy, but it works. An even better way to do it would be to put this in a function with each parameter being a label to check. For example:
bool isCorrect = [self checkIf:xLabel isLessThan: plusLabel isLessThan: yLabel isLessThan:equalsLabel isLessThan:abLabel];
This is assuming the function you write returns a bool.
Hope this helped!

Related

Collision response for rectangles

I've been working on a physics engine for about a week now, being stuck for several days trying to work out how to resolve collisions.
My problem is that if there's a box stuck in the middle of 2 other boxes, or between a box and a wall, my application will get stuck in a while loop. It wont resolve the collisions.
This is my code (note: if collision is right side, it means that object A is colliding against object B with its right side. Distance is negative because the objects are inside eachother, and it's in x or y axis depending on side of collision. If you need more code, for example the collision class, which is simply a container of the 2 objects, i can provide that.):
edit: Code edited with new way of dealing with collisions:
//Move colliding objects so they don't collide anymore.
while (getCollidingAmount(objectVector)){
for (int i = 0; i < objectVector.size(); i++){
PhysicsObject* A = objectVector[i];
if (objectVector[i]->getPhysicsType() != PhysicsType::staticT && A->_collision.size() > 0){
Collision collision = A->_collision[A->getDeepestPenetrationCollisionIndex(A->_collision)];
PhysicsObject* B = collision.getObject();
switch (collision.getSide()){
case SideOfCollision::left:
case SideOfCollision::top:
//Opposite velocity
if (A->_saveVelocity.x < 0 && B->_saveVelocity.x > 0){
long double percentageOfVelocity = std::min(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x)) /
std::max(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x));
A->_position.x -= percentageOfVelocity*collision.getVectorPenetration().x;
A->_position.y -= percentageOfVelocity*collision.getVectorPenetration().y;
}
else{
A->_position.x -= collision.getVectorPenetration().x;
A->_position.y -= collision.getVectorPenetration().y;
}
break;
case SideOfCollision::right:
case SideOfCollision::bottom:
//Opposite velocity
if (A->_saveVelocity.x > 0 && B->_saveVelocity.x < 0){
long double percentageOfVelocity = 1 - std::min(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x)) /
std::max(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x));
A->_position.x -= percentageOfVelocity*collision.getVectorPenetration().x;
A->_position.y -= percentageOfVelocity*collision.getVectorPenetration().y;
}
else{
A->_position.x -= collision.getVectorPenetration().x;
A->_position.y -= collision.getVectorPenetration().y;
}
break;
}
updateCollisions(objectVector);
}
}
}
Update
Something wrong with my trigonometry in bottom and top collisions:
sf::Vector2<long double> Collision::getVectorPenetration() const{
long double x;
long double y;
long double velX = _object->getVelocity().x;
long double velY = _object->getVelocity().y;
long double angle = atan2(velY, velX);
if (_side == SideOfCollision::left || _side == SideOfCollision::right){
x = getDistance();
y = x * tan(angle);
return sf::Vector2<long double>(x, y);
}
else if (_side == SideOfCollision::top || _side == SideOfCollision::bottom){
y = getDistance();
x = y / tan(angle);
return sf::Vector2<long double>(x, y);
}
}
Update 2
Thanks to Aiman, i solved my issue. Updated my collisionResponse code aswell to match my new way of dealing with collisions. I'm having another issue now where gravity makes it so i can't move in X direction when touching another object. If anyone familiar with this issue wants to give any tips to solve it, i appreciate it :).
Update 3
So it seems gravity is not actually the problem since i can swap gravity to the x axis, and then be able to slide boxes along the walls. There seems to still be something wrong with the trigonometry.
I can think of many ways to approach the problem.
1-**The more complicated one is to **introduce friction. Here is how I'd implement it, though this is untested and there is a chance I missed something in my train of thought.
Every shape gets a friction constant, and according to those your objects slide when they collide.
First, you need to get the angle that is perpendicular to your surface. To do this, you just get the arctan of the the surface's normal slope. The normal is simply -1/m, where m is the slope of your surface (which you is the ratio/quotient of how much the surface extends in y to/by how much it extends in x). Let's call this angle sNormal for "surface normal". We may also need sAngle-"surface angle" for later (you find that by arctan(m)). There remains some ambiguity in the angle that has to do with whether you're talking about the 'front' or the 'back' of the surface. You'll have to deal with that manually.
Next, you need the angle of the trajectory your object flies in, which you already know how to find (atan2(y,x)). We'll call this angle oAngle for "object's surface angle". Next, you calculate deltaAngle = sNormal - oAngle. This angle represents how much momentum was not blocked completely by the surface. A deltaAngle of 0 means all momentum is gone, and a value of PI/2 or 90 means the 2 surfaces are in parallel touching each other not blocking any momentum at all. Anything in between, we interpolate:
newSpeed = objectSpeed * deltaAngle/(PI/2);
newVelocity.x = cos(sAngle) * objectSpeed;
newVelocity.y = sin(sAngle) * objectSpeed;
Now this assumes 0 friction. If we let a friction of 1 be the maximum friction which doesn't allow the object to "slide", we modify the newSpeed before we apply the newVelocity values, like so: newSpeed *= (1-friction);.
And there we have it! Just give your platform a friction value of less than 1 and your box will be able to slide. If you're dealing with upright boxes, then the surface angle is PI for top wall, 0 for the bottom, PI/2 for the right and -PI/2 for the left wall.
2-The simpler option is to subtract gravity from the object's y-velocity in the solver's calculation.

game maker random cave generation

I want to make a cave explorer game in game maker 8.0.
I've made a block object and an generator But I'm stuck. Here is my code for the generator
var r;
r = random_range(0, 1);
repeat(room_width/16) {
repeat(room_height/16) {
if (r == 1) {
instance_create(x, y, obj_block)
}
y += 16;
}
x += 16;
}
now i always get a blank frame
You need to use irandom(1) so you get an integer. You also should put it inside the loop so it generates a new value each time.
In the second statement, you are generating a random real value and storing it in r. What you actually require is choosing one of the two values. I recommend that you use the function choose(...) for this. Here goes the corrected statement:
r = choose(0,1); //Choose either 0 or 1 and store it in r
Also, move the above statement to the inner loop. (Because you want to decide whether you want to place a block at the said (x,y) location at every spot, right?)
Also, I recommend that you substitute sprite_width and sprite_height instead of using the value 16 directly, so that any changes you make to the sprite will adjust the resulting layout of the blocks accordingly.
Here is the code with corrections:
var r;
repeat(room_width/sprite_width) {
repeat(room_height/sprite_height) {
r = choose(0, 1);
if (r == 1)
instance_create(x, y, obj_block);
y += sprite_height;
}
x += sprite_width;
}
That should work. I hope that helps!
Looks like you are only creating a instance if r==1. Shouldn't you create a instance every time?
Variable assignment r = random_range(0, 1); is outside the loop. Therefore performed only once before starting the loop.
random_range(0, 1) returns a random real number between 0 and 1 (not integer!). But you have if (r == 1) - the probability of getting 1 is a very small.
as example:
repeat(room_width/16) {
repeat(room_height/16) {
if (irandom(1)) {
instance_create(x, y, obj_block)
}
y += 16;
}
x += 16;
}
Here's a possible, maybe even better solution:
length = room_width/16;
height = room_height/16;
for(xx = 0; xx < length; xx+=1)
{
for(yy = 0; yy < height; yy+=1)
{
if choose(0, 1) = 1 {
instance_create(xx*16, yy*16, obj_block); }
}
}
if you want random caves, you should probably delete random sections of those blocks,
not just single ones.
For bonus points, you could use a seed value for the random cave generation. You can also have a pathway random generation that will have a guaranteed path to the finish with random openings and fake paths that generate randomly from that path. Then you can fill in the extra spaces with other random pieces.
But in regards to your code, you must redefine the random number each time you are placing a block, which is why all of them are the same. It should be called inside of the loops, and should be an integer instead of a decimal value.
Problem is on the first line, you need to put r = something in the for cycle

Objective-C: Adding to variable before assignment

I have the following code:
NSInteger variableScene = 10;
NSInteger numberOfRowsXX = //an Integer value; <-- I would like replace XX with the value of 'variableScene'
So it'll look like this:
NSInteger numberOfRows10 == //an Integer value;
How can I replace XX with the value of variableScene?
*Update*
Why I'm trying accomplish this?
It's a bit complicated. I'm using Core Data with remote Database. In a nutshell: I have 10 Scenes that'll be presented based on the User selection order. For each Scene I need to assign the numberOfRows to present at the end of all the Scenes with a UITableViewController.
I have a variableScene that I pass around from Scene to Scene.
I need to assign numberOfRowsSceneXX = //an integer
XX will come from variableScene, which could be any number from 1 - 10.
So when we get to the last scene, we'll have a value for each Section (numberOfRowInSection) which will be represented by each Scene: numberOfRowScene1, numberOfRowsScene2, etc.
I tried to simplify the question. Hope it makes sense.
Use arrays.
set it up as:
#define MAX_SCENES 10
NSInteger numberOfRows[MAX_SCENES];
then when you want to set the value:
if (variableScene < MAX_SCENES) {
numberOfRows[variableScene] = variable;
}

Changing content of a matrix in c

How do you change just part of a matrix in c (I'm actually in Objective-C, but using matrices in c). For example:
NSInteger tempMapMatrix[100][100] =
{{0,0,1,1,2,2,1,1,0,2,4,4,4,0,0,1,2,2,1,0,0,0,0,0,0},
{0,1,1,2,3,2,1,1,4,4,3,4,4,0,0,1,2,2,1,0,0,0,0,0,0},
{1,1,2,3,3,2,1,4,1,3,3,4,4,0,0,1,2,2,1,0,0,0,0,0,0},
{1,1,3,3,3,2,4,1,1,1,4,4,4,0,0,1,2,2,1,0,0,0,0,0,0},
{0,1,1,2,2,2,4,4,4,4,4,4,4,0,0,1,1,1,1,0,0,0,4,4,0},
{0,0,1,1,2,2,1,0,0,2,3,4,4,0,0,0,0,0,0,0,0,0,4,4,0},
{4,4,1,1,2,2,1,1,0,1,1,0,4,0,0,0,0,0,0,0,0,0,4,4,4},
{0,4,1,2,2,2,1,1,0,4,4,4,4,4,4,4,0,0,0,0,1,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,0,3,3,3,3,3,3,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,4,3,2,2,2,2,2,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,4,3,2,3,3,3,2,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,4,3,2,3,2,2,2,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,3,3,2,3,2,3,3,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,4,4,1,2,2,3,2,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,4,3,3,3,3,3,0,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,4,4,0,0,0,0,0,0,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,0,1,0,0,0,0,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,0,1,0,0,0,1,1,1,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,1,0,0,0,0,0,1,1,0,0},
{0,0,1,2,2,2,1,0,0,0,4,4,4,0,0,1,1,0,0,0,0,0,1,0,0}};
then I want to change the first couple (x and y) of integers:
tempMapMatrix[100][100] =
{{5,5,5,5,5,1,2,3},
{5,5,5,5,5,1,2,3},
{5,5,1,1,1,1,2,3},
{5,5,1,5,5,1,2,3},
{5,5,1,1,1,1,2,3},
{5,5,5,5,5,5,5,5},
{5,5,5,5,5,1,2,3},
{5,2,2,2,5,1,2,3},
{5,2,5,2,5,1,2,3},
{5,2,2,2,5,1,2,3}};
but I'm getting an error (Expected Expression). I've tried
tempMapArray = stuff;
tempMapArray[][] = stuff;
but none work.
Any way to change the first couple of ints in the matrix?
You need to iterate over them, this is C, you don't have syntactic sugar to assingn pieces of arrays like you want. If you want to change, for example, every first element of each row you could do something like:
for (int = 0; i < 100; ++i) {
tempMatrix[i][0] = 5;
}
so for the first couple of every row you should do
for (int = 0; i < 100; ++i) {
tempMatrix[i][0] = 5;
tempMatrix[i][1] = 5;
}
and so on.
You have to access and change each element in the matrix individually.
I.e.:
tempMapMatrix[0][0] = 5;
tempMapMatrix[0][1] = //...
There is no way to "batch change" the contents of an array (one-dimensional or n-dimensional) in C.
The easiest way to achieve this effect is to write a for-loop and iterate over the contents of the two dimensional array and insert the required values in the required places.

How to Modify ZedGraphControl GraphPane Line?

How can I modify an existing line/curve in a ZedGraphControl's GraphPane?
I use the following to get the data for that line:
CurveList lineData = zgcControl.GraphPane.CurveList[i];
But I am stumped on what to do with the CurveList after that. I want to modify the contents of the curvelist but I do not know how.
Any help with this? Thanks!
What are you trying to modify?
Lets say you wanted to move the curve up by 100 units on the Y axis, it would look something like this:
CurveList lineData = zedGraphControl1.GraphPane.CurveList;
CurveItem curve = lineData[0];
for (int i = 0; i < curve.Points.Count; i++ )
{
PointPair point = curve.Points[i];
point.Y += 100;
}