set images in circle view with rotation in ios - ios

I am trying to achieve a view in which Images will placed on edge of circle.I tried to make it with CAShapeLayer and added UIImageViews but I want to create it dynamically. Any help will be appreciated.I am adding one image for example.

I would suggest you to refer this answer given by #rob_mayoff
You should create a circular bezier path with the image you want to display.Please not that this method only works if you want to have same image distributed evenly on the circle.If you want to have different image distributed evenly on circle, then you should do put more effort .
You can try in two ways:
Draw every circular bezier path by calculating their centers . And arrange them in a circular manner. You should do a little math. Please note that you have the center point (x,y) for the main circle, and place the sub circles around the center point (x,y) in such a way that distance from each sub circle center to main circle center should be same. To get the exact coordinates of lines which divide the circle , please refer to the answer. Once you get the exact coordinate, you can place the subcircle at these positions.
I will try to give a rough idea about doing this:
Consider you have a main circle whose center is at (x0,y0). And you wish to place images on this circle by dividing the circle into 'n' parts. so that you can place 'n' number of imageViews on this main circle. The 'n' parts are denoted by green lines in the below picture.
The angle between each of the green lines is 360deg/n
No we need the end point of the each green line. Which can be obtained from:
sub.x = x0 + r * cos(angle);
sub.y = y0 + r * sin(angle);
where r is the radius of main circle.
This is for one sub circle. In yoour case you have 'n' number of sub circles, so let's do a loop to get all sub circle centerpoints:
for(i = 1 to n)
{
angle = i * (360/n);
sub.x = x0 + r * cos(angle);
sub.y = y0 + r * sin(angle);
}
Now you can draw a circular bezier path at each of the 'n' sub (x,y) points
using the addArcWithCenter:center where center would be the calculated sub (x,y)
I think 1 is again the best way if you want to do everything dynamically.

Related

Center a generated Row in a SpriteKit Scene

I am making a Breakout Game and the Game generates rows from how ever many bricks I want in that row. But I cannot get the rows to start in the center. How would I achieve this, here is my current code.
I've tried numerous things, but the closest I got was to get them all to be in the middle, but the should spread out from the middle.
What I would like to achieve should look something like this.
If you have the maximum row size available, a simple way is to include an offset when you calculate the x coordinate.
let maxRow = ... // whatever the maximum row size is
let padding = (maxRow - row) / 2 // how many blocks to skip on the left
for i in 1...row {
// your block creation loop
let x = 15 + (i + padding) * Int(brick.size.width)
// make the brick at x, y
}
If things might not divide evenly (e.g., if maxRow is 15 like it seems to be in your pictures, but row could be 4) then you have to decide on what behavior you'd like. The above will keep bricks aligned because the integer division in calculating padding will truncate; the left and right padding won't be the same. If you use floating division and get a padding like 3.5, you'd get perfectly centered rows but odd rows and even rows would have different alignment.
If your problem is that you want things to appear in an animated way (like in your picture), then things are more complicated. Instead of generating based on the sequence 1, 2, ..., row, it's probably easier to think about generating from the sequence 0, +1, -1, +2, -2, ... After generating the center brick, you'd do the generation of additional bricks in pairs. The x coordinates would be calculated as xCenter + i * Int(brick.side.width).
You're adding the bricks into a parent SKNode (using addChild(_:)). Everything added in that parent node is relative to its coordinate space.
Try adding a brick at y: 0 and see where will it be positioned. If your scene has the anchorPoint at 0.5, you will likely see the brick in the center of the screen. From there, you go up or down (positive or negative y values) to show other rows.
To better understand how the coordinate system works, see About SpriteKit Coordinate Systems.
It's the same for the x axis. If your bricks start from left to right, that means the parent node has its origin to the left of the screen.
To start from the middle, you need to know the middle point. One option is to make a container node, position that in the center of the screen, and add all the bricks there. Like that, the bricks can start at (0, 0).
let middle = CGPoint(x: scene!.size.width / 2, y: scene!.size.height / 2)
let container = SKNode()
container.position = middle
// inside makeBricks(), add everything inside container:
container.addChild(brick)
It really depends on how you set up your node hierarchy.

Pixel-perfect collisions in Monogame, with float positions

I want to detect pixel-perfect collisions between 2 sprites.
I use the following function which I have found online, but makes total sense to me.
static bool PerPixelCollision(Sprite a, Sprite b)
{
// Get Color data of each Texture
Color[] bitsA = new Color[a.Width * a.Height];
a.Texture.GetData(0, a.CurrentFrameRectangle, bitsA, 0, a.Width * a.Height);
Color[] bitsB = new Color[b.Width * b.Height];
b.Texture.GetData(0, b.CurrentFrameRectangle, bitsB, 0, b.Width * b.Height);
// Calculate the intersecting rectangle
int x1 = (int)Math.Floor(Math.Max(a.Bounds.X, b.Bounds.X));
int x2 = (int)Math.Floor(Math.Min(a.Bounds.X + a.Bounds.Width, b.Bounds.X + b.Bounds.Width));
int y1 = (int)Math.Floor(Math.Max(a.Bounds.Y, b.Bounds.Y));
int y2 = (int)Math.Floor(Math.Min(a.Bounds.Y + a.Bounds.Height, b.Bounds.Y + b.Bounds.Height));
// For each single pixel in the intersecting rectangle
for (int y = y1; y < y2; ++y)
{
for (int x = x1; x < x2; ++x)
{
// Get the color from each texture
Color colorA = bitsA[(x - (int)Math.Floor(a.Bounds.X)) + (y - (int)Math.Floor(a.Bounds.Y)) * a.Texture.Width];
Color colorB = bitsB[(x - (int)Math.Floor(b.Bounds.X)) + (y - (int)Math.Floor(b.Bounds.Y)) * b.Texture.Width];
if (colorA.A != 0 && colorB.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision
{
return true;
}
}
}
//If no collision occurred by now, we're clear.
return false;
}
(all the Math.floor are useless, I copied this function from my current code where I'm trying to make it work with floats).
It reads the color of the sprites in the rectangle portion that is common to both sprites.
This actually works fine, when I display the sprites at x/y coordinates where x and y are int's (.Bounds.X and .Bounds.Y):
View an example
The problem with displaying sprites at int's coordinates is that it results in a very jaggy movement in diagonals:
View an example
So ultimately I would like to not cast the sprite position to int's when drawing them, which results in a smooth(er) movement:
View an example
The issue is that the PerPixelCollision works with ints, not floats, so that's why I added all those Math.Floor. As is, it works in most cases, but it's missing one line and one row of checking on the bottom and right (I think) of the common Rectangle because of the rounding induced by Math.Floor:
View an example
When I think about it, I think it makes sense. If x1 is 80 and x2 would actually be 81.5 but is 81 because of the cast, then the loop will only work for x = 80, and therefore miss the last column (in the example gif, the fixed sprite has a transparent column on the left of the visible pixels).
The issue is that no matter how hard I think about this, or no matter what I try (I have tried a lot of things) - I cannot make this work properly. I am almost convinced that x2 and y2 should have Math.Ceiling instead of Math.Floor, so as to "include" the last pixel that otherwise is left out, but then it always gets me an index out of the bitsA or bitsB arrays.
Would anyone be able to adjust this function so that it works when Bounds.X and Bounds.Y are floats?
PS - could the issue possibly come from BoxingViewportAdapter? I am using this (from MonoExtended) to "upscale" my game which is actually 144p.
Remember, there is no such thing as a fractional pixel. For movement purposes, it completely makes sense to use floats for the values and cast them to integer pixels when drawn. The problem is not in the fractional values, but in the way that they are drawn.
The main reason the collisions are not appearing to work correctly is the scaling. The colors for the new pixels in between the diagonals get their colors by averaging* the surrounding pixels. The effect makes the image appear larger than the original, especially on the diagonals.
*there are several methods that may be used for the scaling, bi-cubic and linear are the most common.
The only direct(pixel perfect) solution is to compare the actual output after scaling. This requires rendering the entire screen twice, and requires the scale factor more computations. (not recommended)
Since you are comparing the non-scaled images your collisions appear to be off.
The other issue is movement speed. If you are moving faster than one pixel per Update(), detecting per pixel collisions is not enough, if the movement is to be restricted by the obstacle. You must resolve the collision.
For enemies or environmental hazards your original code is sufficient and collision resolution is not required. It will give the player a minor advantage.
A simple resolution algorithm(see below for a mathematical solution) is to unwind the movement by half, check for collision. If it is still colliding, unwind the movement by a quarter, otherwise advance it by a quarter and check for collision. Repeat until the movement is less than 1 pixel. This runs log of Speed times.
As for the top wall not colliding perfectly: If the starting Y value is not a multiple of the vertical movement speed, you will not land perfectly on zero. I prefer to resolve this by setting the Y = 0, when Y is negative. It is the same for X, and also when X and Y > screen bounds - origin, for the bottom and right of the screen.
I prefer to use mathematical solutions for collision resolution. In your example images, you show a box colliding with a diamond, the diamond shape is represented mathematically as the Manhattan distance(Math.Abs(x1-x2) + Math.Abs(y1-y2)). From this fact, it is easy directly calculate the resolution to the collision.
On optimizations:
Be sure to check that the bounding Rectangles are overlapping before calling this method.
As you have stated, remove all Math.Floors, since, the cast is sufficient. Reduce all calculations inside of the loops not dependent on the loop variable outside of the loop.
The (int)a.Bounds.Y * a.Texture.Width and (int)b.Bounds.Y * b.Texture.Width are not dependent on the x or y variables and should be calculated and stored before the loops. The subtractions 'y-[above variable]` should be stored in the "y" loop.
I would recommend using a bitboard(1 bit per 8 by 8 square) for collisions. It reduces the broad(8x8) collision checks to O(1). For a resolution of 144x144, the entire search space becomes 18x18.
you can wrap your sprite with a rectangle and use its function called Intersect,which detedct collistions.
Intersect - XNA

Convert Scene's (x, y) to screen's (x, y)

I have an application built with SceneKit that is currently displaying several nodes. I can figure out which node is pressed and want to use that to make a label appear below the Node that was touched. Now, when I set the label's center the following way...
nameLabel.center = CGPointMake(CGFloat(result.node.position.x), CGFloat(result.node.position.y+20)
…it appears in the upper left corner since the node is on (1, 0). What I figured is that the sceneView's (0, 0) is in the center of the screen while the actual physical display's (0, 0) is in the top left corner.
Is there a way to convert the two different numbers into each other? (I could hardcode since I know where the Node's are or create a separate label for each Node but that is not really a perfect solution.)
Thanks in advance :)
You can use the projectPoint: method:
var projected = view.projectPoint(result.node.position))
//projected is an SCNVector3
//projected.x and y are the node's position in screen coordinates
//projected.z is its depth relative to the near and far clipping planes
nameLabel.center = CGPointMake(CGFloat(projected.x), CGFloat(projected.y+20)

How to create Random Geo-Points within a distance d from another Geo-point?

How to get Random Geo-points[ lat/long in decimal], placed anywhere inside a 100 meter radius circle? The center of the circle is another reference GeoPoint.
Is there any Function/Formulae that implements this?
Basically I am reading the GPS input of my android device and need to generate random Geo-Points around the device [In a circle of radius 100 meters centered at my device].
Please note : There are no Geo-Points pre-stored in Database. I need to create all the Geo-points on the fly as mentioned above.
I just wrote a a Ruby method which extends Random to provide this.
Caveat: The points all lay within a box, not a circle.
class Random
def location(lat, lng, max_dist_meters)
This is called with Random.new.location(mid_lat, mid_lng, dist). It will return a point which is probably within max_dist_meters of a the mid point.
max_radius = Math.sqrt((max_dist_meters ** 2) / 2.0)
Without adjusting to max_radius we'd get points inside a square outside the circle (i.e. in the corners), where the distance would be greater than max_dist_meters. This constrains us to a square inside the circle which is probably more what you want.
lat_offset = rand(10 ** (Math.log10(max_radius / 1.11)-5))
lng_offset = rand(10 ** (Math.log10(max_radius / 1.11)-5))
The 1.11 and 5 come from here.
lat += [1,-1].sample * lat_offset
lng += [1,-1].sample * lng_offset
lat = [[-90, lat].max, 90].min
lng = [[-180, lng].max, 180].min
We should probably wrap around here instead of just clamping the value, fixes welcome.
[lat, lng]
end
end
Comments / clean up welcome!
Sample output here which you can see nicely if you paste the lat/lngs here.
Pick random points on a square (i.e. pairs of uniform random numbers), then discard any that don't lie within a circle inscribed in that square. Given (x,y) pairs, a point is within your circle if:
(x - c_x)^2 + (y - c_y)^2 < r,
where (c_x, c_y) is the centre of your circle and r is its radius.
Start here: Generate a random point within a circle (uniformly). Then figure out how to center that circle at the reference lat/long. Then figure out how to map the randomly generated points to lat/long values. Hint: you want to add the individual components (say, x and y on your circle) to the circle's center.

Problem rotating simple line image

It is stated, that to rotate a line by a certain angle, you multiply its end point coordinates by the matrix ({Cos(a), Sin(a)} {-Sin(a) Cos(a)}), where a is rotation angle. The resulting two numbers in matrix will be x and y coordinates of rotated line's end point. Rotation goes around line's start point.
Simplifying it, new coordinates will be {x*Cos(a) - y*Sin(a)} for x and {x*Sin(a) + y*Cos(a)} for y.
Task is to rotate a triangle, using this method. But the following code that uses this method, is giving out some crap instead of rotated image (twisted form of original triangle, rotated by "random" angle):
x0:=200;
y0:=200;
bx:=StrToInt(Edit1.Text);
by:=StrToInt(Edit2.Text);
cx:=StrToInt(Edit4.Text);
cy:=StrToInt(Edit5.Text);
a:=StrToInt(Edit3.Text);
//Original triangle
Form1.Canvas.Pen.Color:=clBlue;
Form1.Canvas.MoveTo(x0,y0);
Form1.Canvas.LineTo(bx,by);
Form1.Canvas.LineTo(cx,cy);
Form1.Canvas.LineTo(x0,y0);
//New triangle
Form1.Canvas.Pen.Color:=clGreen;
Form1.Canvas.MoveTo(x0,y0);
b1x:=Round(bx*cos(a*pi/180)-by*sin(a*pi/180));
b1y:=Round(bx*sin(a*pi/180)+by*cos(a*pi/180));
c1x:=Round(cx*cos(a*pi/180)-cy*sin(a*pi/180));
c1y:=Round(cx*sin(a*pi/180)+cy*cos(a*pi/180));
Form1.Canvas.LineTo(b1x,b1y);
Form1.Canvas.MoveTo(x0,y0);
Form1.Canvas.LineTo(c1x,c1y);
Form1.Canvas.LineTo(b1x,b1y);
end;
Well, I'm out of ideas. What am I doing wrong?
Thanks for your time.
The formula you are using rotates a point around (0, 0). To achieve the required result change your calculation to:
b1x:=x0 + Round((bx-x0)*cos(a*pi/180)-(by-y0)*sin(a*pi/180));
b1y:=y0 + Round((bx-x0)*sin(a*pi/180)+(by-y0)*cos(a*pi/180));
c1x:=x0 + Round((cx-x0)*cos(a*pi/180)-(cy-y0)*sin(a*pi/180));
c1y:=y0 + Round((cx-x0)*sin(a*pi/180)+(cy-y0)*cos(a*pi/180));
You appear to be rotating each individual line round its initial start point coordinates. So line 1 will get rotated about its start point (x0,y0); then line 2 will get rotated about bx,by; then line 3 will get rotated round cx. This will result in a twisted triangle. Instead you will need to rotate all three lines round the start point of the first line.

Resources