How to draw infinitely long line in SCENEKIT? - ios

I want to draw axes as that in SketchUp which are infinitely long. I already drew lines that are of fixed length but I want it infinitely long.

Fake it with fixed length lines that extend from beyond the camera's view (called the frustum), through it, and then beyond it again.
You can create beginning and ending SCNNode instances for each axis. Then every time the camera changes its view, call
func isNodeInsideFrustum(_ node: SCNNode,
withPointOfView pointOfView: SCNNode) -> Bool
on each of your 6 endpoints. If an endpoint is within the frustum, move it farther out until it's not.
Methods in the SCNSceneRendererDelegate protocol might be helpful to you.

Depending on the context of what you mean, you check for when the size of the line is about to cross some x or y axis in the screen. You can detect the size of the screen by using size.frame. Alternatively, you can use CGRectGetMidX, CGRectGetMidY, etc.
For example, I would do something like this:
var x = CGRectGetMaxX(self.frame)
//Where y is the max size of the line you have
if x <= y {
//Code where you make the line shape extend or add another line over it to make it look continous
}

Related

Check if coordinate rectangle contains CLLocationCoordinate2D

I am using a special Map SDK for iOS and I am adding a custom shape to the map. The shape is always a different size and it could be a circle, square, star etc. the point being it is always dynamic whenever the app is run.
After adding this shape to the map, I can access it's property called overlayBounds which is described as: This property contains the smallest rectangle that completely encompasses the overlay.
The overlay is my shape that I'm adding to the map.
Whenever a location update is generated by CLLocationManager, I want to check and see if the most recent coordinate is inside of that overlayBounds property of the shape.
When accessing overlayBounds, it has an ne property and a sw property. Both of these are just CLLocationCoordinate2D's
So, if the overlayBounds is made up of two CLLocationCoordinate2D's and the CLLocationManager is always updating the user's location and giving me the most recent coordinate(CLLocationCoordinate2D), how can I check if that most recent coordinate is within the overlayBounds?
After doing a lot of research I have only found one potential solution to go off of which is this: https://stackoverflow.com/a/30434618/3344977
But that answer assumes that my overlayBounds property has 4 coordinates(CLLocationCoordinate2D's), when I only have 2.
Your description seems much harder then the actual question. So if I am getting this correctly your question is only to check if the point is inside the rectangle described in overlayBounds.
You have only 2 points as it is enough to define a rectangle. So NE and SW are the two points where the other two are received as (NE.x, SE.y) and (SE.x, NE.y). With this you may use the answer you linked or you may simply construct a MKMapRect where origin is NE and size is SE-NE. So in this case you may simply use MKMapRectMake and then use MKMapRectContainsPoint. BUT watch out when computing size as SE-NE might produce negative results in which cases you need to add degrees to the size. That is 180 to x (latitude) and 360 to y (longitude)...
MKMapRect rect = MKMapRectMake(NE.latitude, NE.longitude, SE.latitude-NE.latitude, SE.longitude-NE.longitude);
if(rect.width < .0) rect.width += 180.0;
if(rect.height < .0) rect.height += 360.0;
BOOL pointInside = MKMapRectContainsPoint(rect, pointOnMap);
Something like this should do the trick.
Now if you are trying to check if the point is inside the shape itself it really depends on how your shape is defined. If this is some form of analytic representation you might find some method already made for you to return the value but if not then your best shot would most likely be drawing the shape to some canvas and checking the color of canvas at the location you need to check. In any case the bigger problem here is converting the point and the rect to a Cartesian coordinate system. If that is the case then just add a comment and I will try to help you on that...

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)

Equivalent to CGRectIntersectsRect

Is there an equivalent to CGRectIntersectsRect that would be something more along the lines of points intersecting... I'm making a game and RectIntersectsRect works for what I want it to do but it looks bad because sometimes the corner of the one object will intersect the corner of the other and it will call the method, and you can barely see that the two objects touched, so it looks like it just glitches. Is there a CGPointIntersectsPoint or something along the lines of that? Thanks.
You can use CGRectContainsPoint to see if one of your rectangle contains a corner of the other, but you will get the same issue.
You can look for the intersection of the two rectangles using CGRectIntersection. It will give you an other CGRect, which represents the area in common from your two rectangles. From this rectangle, you can check width and height to see if the intersection is "big enough"
CGRect intersection = CGRectIntersection(rect1, rect2);
if (CGRectGetWidth(intersection) > kHorizontalThreshold || CGRectGetHeight (intersection) > kVerticalThreshold)
{
// call your intersection method here
}
Try CGRectContainsPoint. If you want to just compare two points use CGPointEqualToPoint.
You can't really have a point intersecting another point as they're two exact points in space. The only way they can "intersect" is by being equal.

Intersect Nodes ---- Objective-C - Swift - iOS - SpriteKit Node

I'm wondering why the following thing does not work correctly.
Before the nodes are drawn, I analyze if two specific nodes intersect by using:
[[self playerSpriteNode] intersectsNode: [self pSKLabelNode]]
When pSKLabelNode touches desiredSpriteNode it works perfect! (By returning true, or false when it doesn't intersect)
But when it "passes" by a few pixels away from the SKLabel it still intersects and returns true.
Is there some setup that are recommended to fix the frame size of the nodes, or solutions that you think that will fix the problem?
I have the same problem when I try to intersects static node (that located left) with node that have rotation (and flying from the right side). I fix it like this
if ([ninja intersectsNode:node] &&
CGRectGetMinX(node.frame) <= CGRectGetMaxX(ninja.frame) &&
CGRectGetMaxX(node.frame) >= CGRectGetMinX(ninja.frame))
{
//and here I have intersects
}
So I fix it by adding additional parameters
The intersectNode method is optimized for running fast on devices with lots of iterations per second. Due to this, it actually "estimates" collision based on math, which sometimes goes wrong at a margin of a few pixels, specially when we are speaking of square corners of PNGs.
I had this problem once too, and since i used circles I calculated distance between circles as a second verification.
So, what you can do is a custom verification INSIDE the intersectsNode if case. Assuming you handle squares, you could verify wether the x or y collides after the intersectNode. It could be something like like:
if([[self playerSpriteNode] intersectsNode: [self pSKLabelNode]]){
if(distance between x1 and x2 < size1.width/2 + size2.width/2 || distance between y1 y2 < size1.height/2 + size2.height/2){
//Your code goes here
}
}
Note that we compare central x distances with half each widths summed. This is only an example that works with squares, and most generic sprites.
I would like to point out that, while intersectsNode is slightly imprecise, this is NEEDED in order to run your game swiftly, as perfect and precise calculations per update can be very exhaustive to your device.
So, should you do a custom verification, ALWAYS call it after intersectsNode returns true, as a second verification rather than the only one.
The answer provided above by Roman pretty much does what i said, in shorter code; I just wanted to leave an explanation about why.
Swift 2.1:
For increased results do your check in the update( _:) loop, is where things happen before the next drawing:
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if goodDude.intersectsNode(badDude){
print("bad dude v.s. Ninja")
}else{
print("not dude at all")
}
}

Repeating 2d world

How to make a 2d world with fixed size, which would repeat itself when reached any side of the map?
When you reach a side of a map you see the opposite side of the map which merged togeather with this one. The idea is that if you didn't have a minimap you would not even notice the transition of map repeating itself.
I have a few ideas how to make it:
1) Keeping total of 3x3 world like these all the time which are exactly the same and updated the same way, just the players exists in only one of them.
2) Another way would be to seperate the map into smaller peaces and add them to required place when asked.
Either way it can be complicated to complete it. I remember that more thatn 10 years ago i played some game like that with soldiers following each other in a repeating wold shooting other AI soldiers.
Mostly waned to hear your thoughts about the idea and how it could be achieved. I'm coding in XNA(C#).
Another alternative is to generate noise using libnoise libraries. The beauty of this is that you can generate noise over a theoretical infinite amount of space.
Take a look at the following:
http://libnoise.sourceforge.net/tutorials/tutorial3.html#tile
There is also an XNA port of the above at: http://bigblackblock.com/tools/libnoisexna
If you end up using the XNA port, you can do something like this:
Perlin perlin = new Perlin();
perlin.Frequency = 0.5f; //height
perlin.Lacunarity = 2f; //frequency increase between octaves
perlin.OctaveCount = 5; //Number of passes
perlin.Persistence = 0.45f; //
perlin.Quality = QualityMode.High;
perlin.Seed = 8;
//Create our 2d map
Noise2D _map = new Noise2D(CHUNKSIZE_WIDTH, CHUNKSIZE_HEIGHT, perlin);
//Get a section
_map.GeneratePlanar(left, right, top, down);
GeneratePlanar is the function to call to get the sections in each direction that will connect seamlessly with the rest of your world.
If the game is tile based I think what you should do is:
Keep only one array for the game area.
Determine the visible area using modulo arithmetics over the size of the game area mod w and h where these are the width and height of the table.
E.g. if the table is 80x100 (0,0) top left coordinates with a width of 80 and height of 100 and the rect of the viewport is at (70,90) with a width of 40 and height of 20 you index with [70-79][0-29] for the x coordinate and [90-99][0-9] for the y. This can be achieved by calculating the index with the following formula:
idx = (n+i)%80 (or%100) where n is the top coordinate(x or y) for the rect and i is in the range for the width/height of the viewport.
This assumes that one step of movement moves the camera with non fractional coordinates.
So this is your second alternative in a little bit more detailed way. If you only want to repeat the terrain, you should separate the contents of the tile. In this case the contents will most likely be generated on the fly since you don't store them.
Hope this helped.

Resources