Objective-C - Positioning an object according to two points on it - objective-c

Let's say I have a rectangle-shaped object. I want to move it along a path. Is it possible to position this object according to not only one point, but two points on it? For example, the point A on the object is at 125,220, in this case I want point B to be at 140,235.This way I want to set the direction of the object.
In Objective-c (and I assume in other languages too) when we say "Position of a graphical object" we think of only one point, which is usually the bottom-left corner. But positioning
an object according to only that point will just redraw the object with the lower left corner in another point, and the rest part will be determined according to the height and the width of the object, which does not do what I want.
EDIT:
As you can see (and probably it's what you naturally expect) the object will move as a box from one point to another, because there's only one point determining it's position. You ask why I need a different thing. Because I have a timer and a curved path. Each time the timer ticks I need my object to be at a different location(the next position in an array of dumped points). So, instead of adding to X and Y coordinates, I explicitly tell the object to be at certain place. This way I want to achieve normal movement of my object along the curved path. When the front part of the object moves to some point, I need the rear part to move to a certain point as well.

I finally found a way to do do it. I have to rotate the object according the prior and the next points. So, assume there are points A,B,C,D,E,F,G,H on the path that the object will travel along. If the car is at point D, to calculate the rotation angle I do the following:
myObject.rotation=-atan((D.y-C.y)/(D.x-C.x))/3.141592*180;
As you can see it's just maths. A fine tuning can be applied to get a better, smoother rotation. Here for instance I subtract the Y of the previous position from the Y of the current position, then I do the same thing for X and then I get the minus arctangance of their ratio. But you can do
-atan((E.y-C.y)/(E.x-C.x))/3.141592*180;
Choosing the right positions to subtract their x and y coordinates will result in the right and smooth rotation.
I think you can guess that 3.141592 is M_PI;

Related

Make an object reflect in correct angle

I am using vb.net for making a game. I have a ball (not actually, but supposedly) in the center of the screen. It moves towards another object, which has a circular surface and is supposed to reflect back in correct direction and angle.
Many games are based on the bouncing back of an object (most of them are based on advanced languages). But, I am not really able to make out how.
So, I tried to look at some things, like getting an angle from where it started by calculating the pixels from the initial point and sending it that many pixels in the opposite direction. A code which I tried for this is:
Dim x1, y1 as integer
x1 = object.left
y1 = object.top
This stores the object's co-ordinates at the starting, when it is in the center of the screen. While the following code tries to achieve what actually is required:
Dim a, b as integer
a = x1-object.left
b = x2-object.top
I have got the number of pixels it has moved, but I have no clue how to reflect back in the same angle using this, and whether this technique will even work or not.
So, basically what I want is:
Now, two situations arise:
How to reflect object from a plain surface?
How to reflect it from circular surface?
Bouncing a ball off of another ball works exactly as bouncing it off a flat surface. As the balls only touch at one point, there is no difference to the moving ball if that point is part of a curved or a flat surface.
The ball acts just as if it was bouncing off of a flat plane, which is the tangent of the reflecting objects curve at that point (and also the tangent of the moving objects curve):
The reflection movement is the angle mirrored around a line that is perpendicular to the plane, and goes through the center of the ball. (When the reflecting object is a ball, the line goes through the center of that too, which may help when you want to calculate it.)

Centring a CGAffineTransformScale around a given point

I'm animating objects falling onto a board from above, and I want to animate the board 'falling back' as the objects fall upon it. Objects can fall at any point on the board, and when the board 'falls back' I am scaling the board to a smaller scale.
When using CGAffineTransformScale objects scale based on their anchor point, the centre of the object; I want to scale the board and then line up the transformed board with the object that has fallen on it, so that the object that has fallen appears to stay in the same place relative to the board (or, more correctly, the board stays in the same place relative to the position of the board).
I spent hours, and hours changing the anchor point to the position that the object fell, but this revealed a fundamental misunderstanding on my part of how layer.anchorPoint actually works.
I imagine the solution is deriving a vector from the centre of the board to the given falling object and then somehow adjusting position of the board in the transformation so it's the same place. This is where I need help!
As you'd expect in these situations, an animated gif is required.
CALayer's anchorPoint property is the correct property to use for this, with the one minor annoyance that it works in the unit coordinate space, that is, it goes from 0 to 1, not in pixels:
You specify the value for this property using the unit coordinate space. The default value of this property is (0.5, 0.5), which represents the center of the layer’s bounds rectangle. All geometric manipulations to the view occur about the specified point. For example, applying a rotation transform to a layer with the default anchor point causes the layer to rotate around its center. Changing the anchor point to a different location would cause the layer to rotate around that new point.
Because of this, setting an anchor point in pixels would obviously result in some very strange behaviour. You would need to calculate your new anchor point in the unit coordinate space for it to work properly, so, instead of doing something like this:
board.layer.anchorPoint = CGPointMake(ball.x, ball.y);
you would do this:
board.layer.anchorPoint = CGPointMake(ball.x / board.layer.bounds.size.width,
ball.y / board.layer.bounds.size.height);
UPDATE: When you change the anchorPoint property, the view will move, because the anchorPoint, which is set relative to the layer in the unit coordinate space, is anchored to the layer's position property, which is set in the superview's coordinate space. In this way, when you change the value of the anchorPoint property, the view will move such that the point at the new anchor point is at the same place as the old one. You will need to compensate for this, as described in this answer.

Proper rotation with changing x/y coordinates

I'm trying to make a little archer game, and the problem I'm having has to do with 2 pixels in particular, I'll call them _arm and _arrow. When a real archer is pulling back an arrow, he doesn't immediately pull the arrow back as far as his strength allows him, the arrow takes a little bit of time to be pulled back.
The _arm's angle is equal to the vector from a point to where the user touched on the screen. The rotation is perfect, so the _arm is good. The _arrow needs to be on the same line as _arrow, they are 1 pixel wide each so it looks as though the _arrow is exactly on top of the _arm.
I tried to decrement from the x/y coordinates based on a variable that changes with time, and I set the _arrow's location equal to the _arm's location, and tried to make it look like the _arrow was being pulled back. however, if you rotated, the x/y would mess up because it is not proportional on the x and y axis, so basically _arrow will either be slightly above the arm or slightly below it depending on the angle of the vector, based on touch.
How could I used the x/y position of _arm and the vector of touch to make the arrow appear as though it was being pulled back by a small amount, yet keep the arrow on top of the _arm sprite so that it's position would be similar to the arm, but slightly off yet still on top of the _arm pixel at all times. If you need anymore info, just leave a comment.
I'm not sure I've fully understood, but I'll have a go at answering anyway:
To make the arrow move and rotate to the same place as the consider adding the arrow as a child of the arm. You can still render it behind if you like by making its z is less than one: [arm addChild:arrow z:-1]
To then make the arrow move away from the arm as the bow is drawn, you then just set the position of the arrow with respect to the arm.
The problem I do see with this solution however is that this grouping of the sprites may be a little unusual after the arrow leaves the bow. Here you probably don't want the arrow to be a child of the arm as the coordinate systems are no longer related.
Even though they're sure what I "suggested would have solved [the] problem" here is the
Poster's solution
I had to get the x and y coords of the arm based of angle, then I got the sin/cos of a number that was based of the same angle as the arm and subtraced from that.

How to code a random movement in limited area

I have a limited area (screen) populated with a few moving objects (3-20 of them, so it's not like 10.000 :). Those objects should be moving with a constant speed and into random direction. But, there are a few limitation to it:
objects shouldn't exit the area - so if it's close to the edge, it should move away from it
objects shouldn't bump onto each other - so when one is close to another one it should move away (but not get too close to different one).
On the image below I have marked the allowed moves in this situation - for example object D shouldn't move straight up, as it would bring it to the "wall".
What I would like to have is a way to move them (one by one). Is there any simple way to achieve it, without too much calculations?
The density of objects in the area would be rather low.
There are a number of ways you might programmatically enforce your desired behavior, given that you have such a small number of objects. However, I'm going to suggest something slightly different.
What if you ran the whole thing as a physics simulation? For instance, you could set up a Box2D world with no gravity, no friction, and perfectly elastic collisions. You could model your enclosed region and populate it with objects that are proportionally larger than their on-screen counterparts so that the on-screen versions never get too close to each other (because the underlying objects in the physics simulation will collide and change direction before that can happen), and assign each object a random initial position and velocity.
Then all you have to do is step the physics simulation, and map its current state into your UI. All the tricky stuff is handled for you, and the result will probably be more believable/realistic than what you would get by trying to come up with your own movement algorithm (or if you wanted it to appear more random and less believable, you could also just periodically apply a random impulse to a random object to keep things changing unpredictably).
You can use the hitTest: method of UIView
UIView* touchedView=[self.superview hitTest:currentOrigin withEvent:nil];
In This method you have to pass the current origin of the ball and in second argument you can pass nil.
that method will return the view with which the ball is hited.
If there is any hit view you just change the direction of the ball.
for border you can set the condition for the frame of the ball if the ball go out of the boundary just change the direction of the ball.

how to generate graphs using integer values in iphone

i want to show a grapph/bar chart in iphone how do i do this without custom API;s
You may want to investigate the Core Plot project [code.google.com]. Core Plot was the subject of this year's scientific coding project at WWDC and is pretty useable for some cases already. From its inception, Core Plot was intended for both OS X and iPhone uses. The source distribution (there hasn't been a binary release yet) comes with both OS X and iPhone example applications and there's info on the project wiki for using it as a library in an iPhone app. Here's an example of it's current plotting capabilities.
(source: googlecode.com)
Write your own. It's not easy, I'm in the process of doing the same thing right now. Here's how I'm doing it:
First, ignore any desire you may have to try using a UIScrollView if you want to allow zooming. It's totally not worth it.
Second, create something like a GraphElement protocol. I have a hierarchy that looks something like this:
GraphElement
GraphPathElement
GraphDataElement
GraphDataSupplierElement
GraphElement contains the basic necessary methods for a graph element, including how to draw, a maximum width (for zooming in), whether a point is within that element (for touches) and the standard touchBegan, touchMoved, and touchEnded functions.
GraphPathElement contains a CGPath, a line color and width, a fill color and a drawing mode. Whenever it's prompted to draw, it simply adds the path to the context, sets the colors and line width, and draws the path with the given drawing mode.
GraphDataElement, as a subclass of GraphPathElement, takes in a set of data in x-y coordinates, a graph type (bar or line), a frame, and a bounds. The frame is the actual size of the created output CGPath. The bounds is the size of the data in input coordinates. Essentially, it lets you scale the data to the screen size.
It creates a graph by first calculating an affine transform to transform the bounds to the frame, then it loops through each point and adds it as data to a path, applying that transform to the point before adding it. How it adds data depends on the type.
If it's a bar graph, it creates a rectangle of width 0, origin at (x,frame.size.height-y), and height=y. Then it "insets" the graph by -3 pixels horizontally, and adds that to the path.
If it's a line graph, it's much simpler. It just moves to the first point, then for each other point, it adds a line to that point, adds a circle in a rect around that point, then moves back to that point to go on to the next point.
GraphDataSupplierElement is the interface to my database that actually contains all the data. It determines what kind of graph it should be, formats the data into the required type for GraphDataElement, and passes it on, with the color to use for that particular graph.
For me, the x-axis is time, and is represented as NSTimeIntervals. The GraphDataSupplierElement contains a minDate and maxDate so that a GraphDateElement can draw the x-axis labels as required.
Once all this is done, you need to create the actual graph. You can go about it several ways. One option is to keep all the elements in an NSArray and whenever drawRect: is called, loop through each element and draw it. Another option is to create a CALayer for each element, and use the GraphPathElement as the CALayer's delegate. Or you could make GraphPathElement extend from CALayer directly. It's up to you on this one. I haven't gotten as far as trying CALayers yet, I'm still stuck in the simple NSArray stage. I may move to CALayers at some point, once I'm satisfied with how everything looks.
So, all in all, the idea is that you create the graph as one or many CGPaths beforehand, and just draw that when you need to draw the graph, rather than trying to actually parse data whenever you get a drawRect: call.
Scaling can be done by keeping the source data in your GraphDataElement, and just change the frame so that the scaling of the bounds to the frame creates a CGPath wider than the screen, or whatever your needs are. I basically re-implemented my own pinch-zoom for my Graph UIView subclass that only scales horizontally, by changing its transform, then on completion, get the current frame, reset the transform to identity, set the frame to the saved value, and set the frame of all of the GraphElements to the new frame as well, to make them scale. Then just call [self setNeedsDisplay] to draw.
Anyway, that's a bit ramble-ish, but it's an outline of how I made it happen. If you have more specific questions, feel free to comment.