Track Distance Traveled Without Using .magnitude or Vector3.Distance()? - unity3d

I have a missile in my game and I want to keep track of the distance it has traveled to compare against a maximum range.
As it could conceivably travel along a curved path, just comparing its current position against its starting position won't work for me.
I know I can use .magnitude or Vector3.Distance each time through the Update loop, but I also know that's a pretty big performance hit.
I'd appreciate any suggestions.

Thanks Taelsin. For the moment I'm just going to update the distance traveled using magnitude every x number of seconds using Invoke Repeating. It's not exactly performant, but it's simple. Once I get a little more time, I might do what you suggest and perform some simple physics calculations to figure out how long it takes to travel the maximum distance.

Related

SpriteKit Detect Ranges

I am making small/mid RTS game, I have the following need:
I want Enemy Players to Attack allies and vice versa when they are in each attack range.
My question is: what would be a better approach finding if enemy units are in attack range of allied or vice versa of course ?
What have I tried:
For now I tried to add SKNodes with SKPhysicsBodies for each unit Node.
I can see that FPS are going down when the contact happens... I guess it wasn't the best way to know detect whether enemies are in range.
I guess my alternative is to run some Nested Loop within Update method and check if there are enemy units within the Radius.
I am not sure if it is the best approach, however with this approach I may play with some parameters and maybe optimize the routine for my own needs.
I would like to know if there is some better alternatives.
Look into GamePlayKit,
It may have some things you want.
Otherwise I would just use the Euclidiean Distance Formula https://math.stackexchange.com/questions/139600/euclidean-manhattan-distance without the square root, and use this value based on squads, not individual troops. (So if a group of 4 soldiers is attacking an enemy of 5 soldiers, only 1 distance check is done).
The reason why you do not square root, is because you should know the squared allowable distance. If an enemy 10 pixels away attracts soldiers, then use 100.
The best way to treat your soldiers like squads, add them all to an SKNode (sub class to add better functionality), then you just need to compare those squad SKNodes
If you want to reduce the number of checks you make, consider turning your play area into a grid (Like a chess board). Since you know the size of your tiles, you could easily check to see if the units are close enough to warrant a distance check. E.G. You have a unit at a1, and an enemy at i9, then you know just by tile distance that the units are too far apart to attack each other

Calculate fall time in SpriteKit

I am using SpriteKit and I need to calculate the fall time of an object (since it changes depending on the screen size). The problem is that the gravity of the scene is given in m/s^2, but all distances are measured in points.
I have tried to find the conversion between points and meters, but it was not very successful.
Any suggestions in how to deal with it?
You may be able to use something like this (A distance calculator written by another on StackOverflow) to calculate the distance between your node and the point directly below it near the ground or another empty node, then plug that distance into an equation to calculate the time.
Unfortunately, I can't give you any code because I've never tried this myself.

How to get a ball/sphere to stop

I got a field in unity3d that has some depressions in it (like small holes). The field's slope always leads towards the nearest depression.
A sphere is dropped at random somewhere in the field, rolls around a bit until it stops in one of the depressions.
The problem is, this is taking too long. It could roll around for 5-10 seconds until it stops. I'd like to stop faster.
Any ideas how I can achieve this?
Edit: The main issue is when the ball is next to the depression, but it has speed that is 90 degrees from the hole, then it starts going in circles and takes a while to stop.
Ok, after getting some advice in the comments, and experimenting, this is the way I solved it:
Apply a small measure of strength towards the depression
If the current velocity is more than 30 degrees away from the center of the depression, slow the ball (apply strength in the opposite direction of the velocity)
IF the ball gets very near the center of the depression, stop it and place it in the center
Thanks for all the tips. If anyone comes up with a better way, I'm still open to suggestions.

iPhone pathfinding implementation

I am trying to create a Pacman AI for the iPhone, not the Ghost AI, but Pacman himself. I am using A* for pathfinding and I have a very simple app up and running which calculates the shortest path between 2 tiles on the game board avoiding walls.
So running 1 function to calculate a path between 2 points is easy. Once the function reaches the goalNode I can traverse the path backwards via each tiles 'parentNode' property and create the animations needed. But in the actual game, the state is constantly changing and thus the path and animations will have to too. I am new to game programming so I'm not really sure the best way to implement this.
Should I create a NSOperation that runs in the background and constantly calculates a goalNode and the best path to it given the current state of the game? This thread will also have to notify the main thread at certain points and give it information. The question is what?
At what points should I notify the main thread?
What data should I notify the main thread with?
...or am I way off all together?
Any guidance is much appreciated.
What I would suggest for a pacman AI is that you use a flood fill algorithm to calculate the shortest path and total distance to EVERY tile on the grid. This is a much simpler algorithm than A*, and actually has a better worst case than A* anyway, meaning that if you can afford A* every frame, you can afford a flood fill.
To explain the performance comparison in a in a little bit more detail, imagine the worst case in A*: due to dead ends you end up having to explore every tile on the grid before you reach your final destination. This theoretical case is possible if you have a lot of dead ends on the board, but unlikely in most real world pacman boards. The worst case for a flood fill is the same as the best case, you visit every tile on the map exactly once. The difference is that the iterative step is simpler for a flood fill than it is for an A* iteration (no heuristic, no node heap, etc), so visiting every node is faster with flood fill than with A*.
The implementation is pretty simple. If you imagine the grid as a graph, with each tile being a node and each edge with no wall between neighboring tiles as being an edge in the graph, you simply do a breadth first traversal of the graph, keeping track of which node you came from and how many nodes you've explored to get there. You mark a node as visited when you visit it, and never visit a node twice.
Here's some pseudo code to get you started:
openlist = [ start_node ]
do
node = openlist.remove_first()
for each edge in node.edges
child = node.follow_edge(edge)
if not child.has_been_visited
child.has_been_visited = true
child.cost = node.cost + 1
child.previous = node
openlist.add(child)
while openlist is not empty
To figure out how to get pacman to move somewhere, you start with the node you want and follow the .previous pointers all the way back to the start, and then reverse the list.
The nice thing about this is that you can make constant time queries about the cost to reach any tile on the map. For example, you can loop over each of the power pellets and calculate which one is closest, and how to get there.
You can even use this for the ghosts to know the fastest way to get back to pacman when they're in "attack" mode!
You might also consider flood fills from each of the ghosts, storing in each tile how far away the nearest ghost is. You could limit the maximum distance you explore, not adding nodes to the open list if they are greater than some maximum cost (8 squares?). Then, if you DID do A* later, you could bias the costs for each tile based on how close the ghosts are. But that's getting a little beyond what you were asking in the question.
It should be fast enough that you can do it inline every frame, or multithread it if you wish. I would recommend just doing it in your main game simulation thread (note, not the UI thread) for simplicity's sake, since it really should be pretty fast when all is said and done.
One performance tip: Rather than going through and clearing the "has_been_visited" flag every frame, you can simply have a search counter that you increment each frame. Something like so:
openlist = [ start_node ]
do
node = openlist.remove_first()
for each edge in node.edges
child = node.follow_edge(edge)
if child.last_search_visit != FRAME_NUMBER
child.last_search_visit = FRAME_NUMBER
child.cost = node.cost + 1
child.previous = node
openlist.add(child)
while openlist is not empty
And then you just increment FRAME_NUMBER every frame.
Good luck!
Slightly unrelated, but have you seen the ASIPathFinder framework? Might help if you have more advanced pathfinding needs.
I would recommend just pre-computing the distance between all pairs of points in the map. This takes n^2/2 space where there are n traversable points in the map. According to this link there are 240 pellets on the board which means there are about 57k combinations of points that you could query distances between. This is pretty small, and can be compressed (see here) to take less space.
Then, at run time you don't have to do any real computation except look at your possible moves and the distance to reach that location.

Detect the iPhone rotation spin?

I want to create an application could detect the number of spin when user rotates the iPhone device. Currently, I am using the Compass API to get the angle and try many ways to detect spin. Below is the list of solutions that I've tried:
1/ Create 2 angle traps (piece on the full round) on the full round to detect whether the angle we get from compass passed them or not.
2/ Sum all angle distance between times that the compass is updated (in updateHeading function). Let try to divide the sum angle to 360 => we could get the spin number
The problem is: when the phone is rotated too fast, the compass cannot catch up with the speed of the phone, and it returns to us the angle with latest time (not continuously as in the real rotation).
We also try to use accelerometer to detect spin. However, this way cannot work when you rotate the phone on a flat plane.
If you have any solution or experience on this issue, please help me.
Thanks so much.
The iPhone4 contains a MEMS gyrocompass, so that's the most direct route.
As you've noticed, the magnetometer has sluggish response. This can be reduced by using an anticipatory algorithm that uses the sluggishness to make an educated guess about what the current direction really is.
First, you need to determine the actual performance of the sensor. To do this, you need to rotate it at a precise rate at each of several rotational speeds, and record the compass behavior. The rotational platform should have a way to read the instantaneous position.
At slower speeds, you will see a varying degree of fixed lag. As the speed increases, the lag will grow until it approaches 180 degrees, at which point the compass will suddenly flip. At higher speeds, all you will see is flipping, though it may appear to not flip when the flips repeat at the same value. At some of these higher speeds, the compass may appear to rotate backwards, opposite to the direction of rotation.
Getting a rotational table can be a hassle, and ensuring it doesn't affect the local magnetic field (making the compass useless) is a challenge. The ideal table will be made of aluminum, and if you need to use a steel table (most common), you will need to mount the phone on a non-magnetic platform to get it as far away from the steel as possible.
A local machine shop will be a good place to start: CNC machines are easily capable of doing what is needed.
Once you get the compass performance data, you will need to build a model of the observed readings vs. the actual orientation and rotational rate. Invert the model and apply it to the readings to obtain a guess of the actual readings.
A simple algorithm implementation will be to keep a history of the readings, and keep a list of the difference between sequential readings. Since we know there is compass lag, when a difference value is non-zero, we will know the current value has some degree of inaccuracy due to lag.
The next step is to create a list of 'corrected' readings, where the know lag of the prior actual values is used to generate an updated value that is used to create an updated value that is added to the last value in the 'corrected' list, and is stored as the newest value.
When the cumulative correction (the difference between the latest values in the actual and corrected list exceed 360 degrees, that means we basically don't know where the compass is pointing. Hopefully, that point won't be reached, since most rotational motion should generally be for a fairly short duration.
However, since your goal is only to count rotations, you will be off by less than a full rotation until the accumulated error reaches a substantially higher value. I'm not sure what this value will be, since it depends on both the actual compass lag and the actual rate of rotation. But if you care only about a small number of rotations (5 or so), you should be able to obtain usable results.
You could use the velocity of the acceleration to determine how fast the phone is spinning and use that to fill in the blanks until the phone has stopped, at which point you could query the compass again.
If you're using an iPhone 4, the problem has been solved and you can use Core Motion to get rotational data.
For earlier devices, I think an interesting approach would be to try to detect wobbling as the device rotates, using UIAccelerometer on a very fine reporting interval. You might be able to get some reasonable patterns detected from the motion at right angles to the plane of rotation.