I was wondering if there would be a way to delete the last couple of positions/indexes of a trail renderer. I am trying to stop the trail render emission after a bullet collision, but the trail renderer always spawns a couple of indexes too much, and I was wondering if there was a way to delete those indexes.
I have tried setting the positions of newer indexes to equal older indexes, and that worked to some extent but not to the extent that I wanted.
tR = GetComponent<TrailRenderer>();
int positions = tR.positionCount;
for (int i = 0; i < vertsToDelete; i++) {
if (positions - 1 - i - (int)vertsToDelete > 0) {
tR.SetPosition(positions - 1 - i, tR.GetPosition(positions - 1 - i - (int)vertsToDelete));
}
}
This code works mostly except for certain instances when the positions screw up. Thats why i think being able to delete an index would make the process much easier.
It is more efficient to use one single GetPositions call, manipulate the array and write it back completely using one single AddPositions call.
In order to alternate the array you could go through a list which allows dynamically changing the amount of elements more easily.
Start by converting the array to a list using Linq IEnumerable.ToList()
var positions = new Vector3[tr.positionCount];
tr.GetPositions(positions);
var positionsList = positions.ToList();
then remove an element by index using List<T>.RemoveAt(int index)
positionsList.RemoveAt(indexToRemove);
or remove multiple sequential elements using List<T>.RemoveRange(int startIndex, int amount)
positionsList.RemoveRange(startIndex, amountToRemove);
And finally convert it back to the required arrays using List<T>.ToArray()
tR.Clear();
tR.AddPositions(positionsList.ToArray());
For anyone still searching for this.
I had an issue just like that, my Trail Renderer was drawing some artifact when I used the Floating Origin on it (even when I turned emission off, it was like it had a delay on turning off).
After 2 weeks trying many things and searching I solved this in the most ridiculous way:
//I have this at the beginning os my class:
//public TrailRenderer trailRenderer;
//and this declared at start:
//trailRenderer = trailRenderer.GetComponent<TrailRenderer>();
int trailSize = trailRenderer.positionCount;
float distance = Vector3.Distance(trailRenderer.GetPosition(trailSize - 1), (trailRenderer.GetPosition(trailSize - 2)));
Debug.Log("Distance: " + distance);
if (distance > 90f)
{
trailRenderer.SetPosition(trailSize - 1, trailRenderer.transform.position);
}
This verify the wrong Draw (in my case is just the last point) and get it back to my trail renderer transform, preventing any artifacts my floating origin may cause if it causes any. That's way better than use a for to verify every position since I only have an issue with the last one. Just adapt that to your needs :)
Related
I am trying to make a 2D game engine, but I can't seem to get collisions to work all the time (Often times things get stuck or pass through each other). Without getting into the code too much, here is the order in which I am updating.
Get user input and update the player velocity
Save the position for each entity, then move the velocity / update interval units
Check each movable entity for collisions against all other entities. If the entity collides with something, it is moved to its old position and the new velocities are set for both colliding entities.
The collision impulse is calculated in this function:
private static void CollisionImpulse(PhysicsEntity a, PhysicsEntity b)
{
var relative = b.Velocity.Vector - a.Velocity.Vector;
var normal = Vector2.Normalize(relative);
var e = Math.Min(a.Material.Elasticity, b.Material.Elasticity);
var j = (-(1 + e) * Vector2.Dot(relative, normal)) /
(Vector2.Dot(normal, normal) * (a.InverseMass + b.InverseMass));
if (double.IsNaN(j)) return;
var velocityA = normal * (float) (j / a.Mass);
var velocityB = normal * (float) (j / b.Mass);
a.Velocity.X -= velocityA.X;
a.Velocity.Y -= velocityA.Y;
if (!b.Movable) return;
b.Velocity.X += velocityB.X;
b.Velocity.Y += velocityB.Y;
b.Position = b.OldPosition;
}
and this is the function to check for the collisions:
public override void Update()
{
foreach (var entity in Universe.PhysicsEntities)
{
if (entity.Equals(this) || entity.Collided) continue;
CollisionResolution.ResolveCollision(this, entity);
if (!Collided) continue;
Position = OldPosition;
break;
}
}
I have been trying to tweak the code for a few days, but I cannot figure out what is wrong. I was hoping some fresh eyes could shed some light on my dilemma.
There is a fundamental issue with step 3 "If the entity collides with something, it is moved to its old position..." - because you are now moving this entity again, you need to re-run the collision detection for all previous entities against this entity, otherwise you might cause an overlap.
E.g. if you had 3 pool balls (A,B,C), you move all 3 to their desired new positions to A',B',C' (in your step 2). Now for step 3 you check and A'B' and A'C' don't collide, and they don't, but then you check B'C' and they do collide, so in your solution you move B',C' back to B,C - BUT now technically you may have moved B and/or C so it's now intersecting with A.
To make your step 3 work you either need to:
1) Ensure that no objects overlap at the start, and whenever you detect a collision in your step 3 either (a) re-run the collision on every previous object that we'd previously said didn't collide with these objects, OR keep rerunning the whole of step 3 until no objects were reset on the last loop. This can become expensive if you have a lot of objects and they all start resetting each other.
or:
2) Instead of resetting objects to their last frame's "safe" position each time, the resultant force (so acceleration, not velocity) is related to how much the objects interpenetrate. This is common in 3D physics engines, and can result in objects exploding if they interpenetrate too much.
Also note that if you ever move an object very far in 1 frame (e.g. further than half it's size), it could potentially pass through another object without the collision overlap detection firing. This is often known as the bullet-through-paper problem
I trying to make a game where player only move forward in an infinity map, and the path (just thing of them like points, the path is only the visual) is procedurally generated. I want those path to have different length (something like the tree of life, but only branches of the selected path are generated).
This is how I generate branches without overlap:
List<Vector3> everyPos; //predetermined position
public void Spawn(int amount)
{
List<Vector3> possiblePos = new List<Vector3>(everyPos);
for (int i = 0; i < amount; i++)
{
int index = Random(0, possiblePos.Count); //Find a random position
SpawnObjectAt(currentPosition+possiblePos[index]));//Create a point there
possiblePos.RemoveAt(index); //Remove that position from the list
}
}
The problem is , look at this image(I can't embed image yet):
Red is where player start, green is possible spawn position in the first move.
If there are 2 point spawned at 1 and 2, player choose point1, then the possible position in the second time will be a point in the black zone, which include point2, so if I keep continue there will eventually overlap.
How can I avoid this? I'm making a mobile game so I don't want to cache every single point. Any help would be really appreciated! Thanks!
This is a small web game that have somewhat similar mechanic to what I trying to achieve: newgrounds.com/portal/view/592325/
This is an attempt here to answer, but honestly, you need to provide more information.
Depending on the language you are writing in, you can handle this differently. You may need dynamic allocation, but for now lets assume, since your idea is quite small, that you can just do one large array predefined before compile time.
I assume you know how to make an array, so create one with say, 500 length to start. If you want to 'generate' a link like they did in that game, you simply need a random function, (there is a built in library in pretty much every language I think) and you need to do a little math.
Whatever language you use will surely have a built in graphics library, or you can use a popular easy to use one. I'll just draw a picture to make this clear.
There are a number of ways you can do this mathematically as shown in the image, using angles for example, the simplest way, however, is just to follow the boxes.
If you have worked with graphics before, you know what a vector is, if not, you will need to learn. The 9 vectors presented in this image (0,1) (1,0) (1,1) etc. can be created as vector objects, or even stored as individual ints.
To make your nodes 'move' into another path, you can simply do a rand 1-9 and then correlated the result to one of 9 possible vectors, and then add them to your position vector. It is easiest to do this in array and just use the rand int as the index. In most c derived languages you do that like this:
positionVector += changeVectorArray[rand(1,9)];
You then increment your position vector by one of the 9 vectors as shown above.
The simplest way of making the 'path' is to copy the position before you add the change vector, and then store all of the changes sequentially in another 'path' array.
To show the path on screen, simply draw a line between the first and second, second and third, third and forth elements of your path array. This formula (of joining lines) is discrete mathematics if I'm not mistaken, and you can do much more complicated path shapes if you want, but you get the gist.
That should at least start you off. Without more info I can't really help you.
I could go off on a tangent describe a bunch of different ways you can make this happen differently but its probably easier if you just ask for specifics.
EDIT>>>
Continuing with this answer, yes, looking at it now, the nodes can definitely overlap. To solve this problem you could use collision detection, every time you generate a new 'position', before adding it and drawing the line you have to loop through your array like this:
boolean copy = true;
for(int i = 0; i < getLength(pathArray); i++){
if( newVector == pathArray[i]){
copy=false;
}
}
Then of course, if copy still is true, copy the new position int the pathArray. NOTE: this whole solution is sloppy as hell, and as your array gets larger, your program is going to take longer and longer to search through that loop. This may not also guarantee that the path goes in one direction, but it is likely. And note that the lines will still be able to overlap each other, even though the position vectors can't be on top of one another.
All this considered, I think it will work, the optimization is up to you. I would suggest that there is probably a much more efficient solution using a discrete formula. You can also use such a formula to make the path go in particular directions and do other more complicated things.
You could also quite easily apply constraints on your random rolls if you want to make the path go in a particular direction. But there are so many ways of doing this I can't begin to explain. You could google path-finding algorithms for that.
Good luck.
So, this seems to be a strange one (to me). I'm relatively new to Unity, so I'm sure this is me misunderstanding something.
I'm working on a VSEPR tutorial module in unity. VSEPR is the model by which electrons repel each other and form the shape (geometry) of atoms.
I'm simulating this by making (in this case) 4 rods (cylinder primitives) and using rigidbody.AddForce to apply an equal force against all of them. This works beautifully, as long as the force is equal. In the following image you'll see the rods are beautifully equi-distant at 109.47 degrees (actually you can "see" their attached objects, two lone pairs and two electron bonds...the rods are obscured in the atom shell.)
(BTW the atom's shell is just a sphere primitive - painted all pretty.)
HOWEVER, in the real world, the lone pairs actually exert SLIGHTLY more force...so when I add this additional force to the model...instead of just pushing the other electron rods a little farther away, it pushes the ENTIRE 4-bond structure outside the atom's shell.
THE REASON THIS SEEMS ODD IS...two things.
All the rods are children of the shell...so I thought that made them somewhat immobile compared to the shell (I.e. if they moved, the shell would move with them...which would be fine).
I have a ConfiguableJoint holding the rods to the center of the atoms shell ( 0,0,0). The x/y/z-motion is set to fixed. I thought this should keep the rods fairly immutably attached to the 0,0,0 center of the shell...but I guess not.
POINTS OF INTEREST:
The rods only push on each other, by a script attached to one rod adding force to an adjacent rod. they do not AddForce to the atom shell or anything else.
CODE:
void RepulseLike() {
if (control.disableRepulsionForce) { return; } // No force when dragging
//////////////////// DETERMINE IF FORCE APPLIED //////////////////////////////
// Scroll through each Collider that this.BondStick bumps
foreach (Collider found in Physics.OverlapSphere(transform.position, (1f))) {
// Don't repel self
if (found == this.collider) { continue; }
// Check for charged particle
if (found.gameObject.tag.IndexOf("Charge") < 0) { continue; }// No match "charge", not a charged particle
/////////////// APPLY FORCE ///////////////
// F = k(q1*q2/r^2)
// where
// k = Culombs constant which in this instance is represented by repulseChargeFactor
// r = distance
// q1 and q2 are the signed magnitudes of the charges, in this case -1 for electrons and +1 for protons
// Swap from local to global variable for other methods
other = found;
/////////////////////////////////
// Calculate pushPoints for SingleBonds
forceDirection = (other.transform.position - transform.position) * magnetism; //magnetism = 1
// F = k(q1*q2/distance^2), q1*q2 ia always one in this scenario. k is arbitrary in this scenario
force = control.repulseChargeFactor * (1 / (Mathf.Pow(distance, 2)));
found.rigidbody.AddForce(forceDirection.normalized * force);// * Time.fixedDeltaTime);
}//Foreach Collider
}//RepulseLike Method
You may want to use spheres to represent electrons, so apply forces onto them and re-orient(rotate) rods according to this sphere.
I think I found my own answer...unless someone has suggestions for a better way to handle this.
I simply reduced the mass of the electron rods, and increased the mass of the sphere. I'm not sure if this is the "best practices" solution or a kluge...so input still welcomed :-)
I've been looking at this for far too long, hopefully someone can help.
The general jist is;
I have a SortedSet of player objects (sorted by Y position), each player contains a sortedset of 'Polygon' objects which in turn contain a list of three point objects, obviously forming a triangle.
This polygon set is sorted by area of said polygon, smallest to largest.
What I want to do is iterate through the set of players and;
I. Assign the point at index[1] (the 'peak' of the triangle) from the first object in the polygon SortedSet to another variable inside the player.
II. Once the point at index[1] has been assigned to a player, I need to iterate through every player and remove any instance of a polygon that contains the current point at ElementAt(1) so no subsequent players in the 'parent' iteration can be assigned a polygon that contains that Point.
It's probably important to note that the point at polygonPoints[1] is based on the enemy position so they're consistent across all players, this is why I'm trying to use it as my 'reference' point to remove any polygon objects that contain said point.
It's a convoluted explanation but hopefully you've been able to follow.
Right now I've got the first part working, but the second part is proving to be a serious pain - I've tried remove and removewhere (using criteria that should remove everything) and the set stubbornly stays the same length no matter what I do.
For reference here's the latest iteration of code that I'm wrangling with.
List<PointF> duplicates = new List<PointF>();
foreach (Player p in playerSet)
{
//Assign lowest cost polygon to current player, then remove all polygons containing the point at p.triangleSet.ElementAt(0).polygonPoints[1] from every other player so it can't be assigned to any subsequent player.
p.currentAttackingPoint = p.triangleSet.ElementAt(0).polygonPoints[1];
//I use this method to keep track of which 'attacking points' have been assigned.
add(p.currentAttackingPoint);
//Then, in theory, I use this method to remove all polygons that contain any point in the duplicates list from every other player. Obviously this is proving to be the troublesome aspect.
remove(duplicates);
}
...
private void add(PointF i)
{
duplicates.Add(i);
}
private void remove(List<PointF> dupes)
{
foreach(PointF p in dupes)
{
foreach (Player l in playerSet)
{
//Outputs 100
textBox3.AppendText(l.triangleSet.Count.ToString() + "\r\n");
l.triangleSet.RemoveWhere(e => e.polygonPoints[1] == p);
//l.pressingTriangleSet.RemoveWhere(e => e.polygonPoints[1].X > 0); --Doesn't work either, despite it being true of every point in the set.
//Still 100
textBox3.AppendText(l.triangleSet.Count.ToString() + "\r\n");
}
}
}
Please bear in mind that the set of polygons inside each player, whilst the same length all have largely different content, they're based on the position of the player the position of the enemy and another arbitrary fact about the game state - so I can't just remove the first polygon from each player's set.
I'm thinking about converting each set to a list once they've been created because this is bizarre, it's got to be some order of operations issue that I'm overlooking.
Purely for my own sanity I knocked this out http://pastie.org/private/ikq5lhhacxxvfaoervauw and it works exactly as you'd expect it to.
EDIT - For anyone who finds this looking for a solution to a similar problem, don't waste your time using sortedsets to sort a collection of objects, you can use OrderBy to achieve the same thing with lists.
This is a longshot but sometimes comparing floats and double is a bit tricky because of precision. For example a point 1.0 might be represented as 1.0000001 because of rounding errors. It is possible that your points are not compared correctly
Try something like
e.polygonPoints[1].X - p.X < 0.00001
&& p.X - e.polygonPoints[1].X < 0.00001
&& e.polygonPoints[1].Y - p.Y < 0.00001
&& p.Y - e.polygonPoints[1].Y < 0.00001
I would have assumed that PointF equality operator would take care of that but it may not
I am making a grid based game where characters can move their units turn by turn. Each character has a move amount (for example 4 - where they can move 4 tiles).
I've implemented a DLS (which is limited to their move amount). Using this, all available tiles that the player can move to are highlighted.
This works fine. However, I would like modify the algorithm (or implement a specific one) to work out the route. For example, the player wants to G3 - what route should the character take (forward 1, left 1 etc).
Bearing in mind that each tile can have different properties (such as some may be blocked).
Code
private void DLS(int x, int z, int depth, float jump, float previousHeight)
{
int resistance=1;
if (depth >=0)
{
tiles[x,z].GetComponentInChildren<CheckIfClicked>().Selected();
if (x+1 < 25)
{
CheckTile(x+1, z, depth, jump, previousHeight);
}
if (x-1 >= 0)
{
CheckTile(x-1, z, depth, jump, previousHeight);
}
if (z+1 <25)
{
CheckTile(x, z+1, depth, jump, previousHeight);
}
if (z-1 >=0)
{
CheckTile(x, z-1, depth,jump, previousHeight);
}
}
}
private void CheckTile(int x, int z, int depth, float jump, float previousHeight)
{
float tileHeight = tiles[x, z].GetComponent<TileDimensions>().height;
float difference = tileHeight - previousHeight;
if (difference<0) difference*=-1;
if (!tiles[x, z].GetComponentInChildren<CheckIfClicked>().occupied && difference<jump)
{
int resistance = tiles[x, z].GetComponent<TileDimensions>().getResistance();
if (resistance<0) resistance=1;
DLS(x, z, depth-resistance, jump, tileHeight);
}
}
My code takes advantage of the different tile properties (such as the tiles resistance (some tiles limit the movement) and height (you can only climb so far up)).
If you wish to use a more efficient algorithm there are two suggested implementations:
A star. A star is best used when you know the destination you want to travel to but you need to find the way of getting there. e.g if you clicked in tile G3, and were in G1, you know where you need to go. A star takes advantage of a heuristic which tries to "guess" how much further you have to go. This means that when searching for potential routes, A star will attempt to take what should be the shortest route before attempting to look at other routes. There's a fantastic tutorial here: Link
Djikstra's algorithm. This is better used when you don't know where you're going but you want to find the nearest node that contains a certain "thing", i.e. you might want your A.I to search for the nearest health pack in an FPS. I've not implemented Djikstra's algorithm before but there are plenty of tutorials available online.
With both you can add properties such as resistance on certain tiles and whatever else.
Since your algorithm is working, I would like to give you a few suggestions to enhance your code, both involve using list/dictionary.
Perform path searching once
If you can highlight every movable tiles, that means you are able to traverse paths originating from a source tile to different destination tiles, which implies you are validating the tiles one by one until the character cannot make additional moves. Therefore, you can store the results into a dictionary of "destination tile - lists" pairs. Whenever you need to retrieve a path going to a particular tile, just get the previously stored path.
Perform path searching twice
As the aforementioned approach may take up a lot of memory usage, you can run your path-searching algorithm once more when the player makes a move. Time spent for the second execution should be less than the first one, as the player has specified certain tile to be the destination of the path. During the second search, keep updating a list/dictionary while recursively executing the path-searching functions. Have every valid intermediate tile saved to the list/dictionary, then you can get the path after the search.
If you are developing games on mobile platforms, even a little bit of memory usage does matter. I would then suggest to perform path searching twice as long as the time spent for searching is acceptable to players.
Of course, it is always a good practice to monitor the performance via the Unity Profiler to check which approach suits your needs in a better manner.