I have code that lerps Sphere instance positions from the vertices of a 1st mesh, to the vertices of a 2nd mesh.
The sphere instances are moved via a Lerp that uses transform data positions. The problem is that apparently moving the instances this way does not work with Unity's Physics very well, so other objects that collide with the sphere instances don't collide with them properly.
How can I change the code to correctly make the Sphere instances move with maybe Vector3 velocity (or whatever would make Unity physics work right), rather than just moving via setting explicit transform positions?
here is the code. I have these variables:
public List<TransformData> meshVertices1 = new List<TransformData>();
public List<TransformData> meshVertices2 = new List<TransformData>();
which are then being filled later with data like:
meshVertices1.Add(new TransformData(position, rotation, scaleVector));
meshVertices2.Add(new TransformData(position, rotation, scaleVector));
then I instantiate sphere instances based on above data:
spheres = new GameObject[24];
for (int i = 0; i < mesh.vertexCount; i++)
{
spheres[i] = Instantiate(spherePrefab, meshVertices1[i].position, Quaternion.identity, transform);
}
and lastly put a Lerp for the sphere instance positions in Update method:
for (int i = 0; i < 24; i++)
{
spheres[i].transform.localPosition = Vector3.Lerp(meshVertices1[i].position, meshVertices2[i].position, t);
}
Thanks. One of the things I tried was changing the Update method to say
Vector3 convert = spheres[i].transform.InverseTransformPoint(transform.localPosition);
convert = Vector3.Lerp(meshVertices1[i], meshVertices2[i].position, t);
but upon hitting play it just made the sphere instances all drop to the floor and roll around. Whereas I want the instances to move and stay in the formation of the 2nd Mesh vertices.
One approach is getting a reference to the Rigidbody of each sphere and calling Rigidbody.MovePosition (make sure this is done in FixedUpdate):
for (int i = 0; i < 24; i++)
{
Rigidbody rb = spheres[i].GetComponent<Rigidbody>();
rb.MovePosition(Vector3.Lerp(meshVertices1[i].position, meshVertices2[i].position, t));
}
In the interest of performance, you may want to create a list of each sphere's Rigidbody once, and then loop through that list so you don't have to call GetComponent 24 times every frame.
Related
I would like some help with figuring this out as my brain is having a funny day today at what is the best way to go about this.
I have an OnDrawGizmos as follows
Transform parentBounds;
void OnDrawGizmos()
{
parentBounds = this.gameObject.transform;
Vector3 from;
Vector3 to;
for (int a = 0; a < parentBounds.childCount; a++)
{
from = parentBounds.GetChild(a).position;
to = parentBounds.GetChild((a + 1) % parentBounds.childCount).position;
Gizmos.color = new Color(1, 0, 0);
Gizmos.DrawLine(from, to);
}
}
This code is attached on a "parent" object which contains 4 empty game objects as follows
Which produces the following Gizmo (Drawing a square based on where I put the empty objects within the parent)
I can even add more points if I desire.
SO WHAT IS THE PROBLEM ?
What I need is that if the player is not within this box area, I want the player to be destroyed. I'm not sure what the best practice is for this , should I make an array to hold the xmin, ymax, etc. ? or should I generate a new position vector on every loop ? I've tried a few ways that are not giving me the results I want and I taught to ask for some assistance.
Thank you all in advance !
If this is a 2D game (which I assume it is), how about having a script, that has reference to the player object and...
a) game is not using physics
... a public Rect boundaries. On each Update() check if player is within the boundaries and if not - destroy it.
void Update()
{
if (!boundaries.Contains(playerObject.transform.position))
{
Destroy(playerObject);
}
}
b) game is using physics
... a BoxCollider2D with the following script
void OnColliderExit2D(Collider2D collider)
{
// If collider is player object -> destroy collider.gameObject
}
I have one problem. I want my prefabs to spawn every time my player picks them up. I did research on Google and YouTube and I tried to use the random function and instantiate. I don't know how to use them. I wrote this code I saw on YouTube and my prefab Sphere moves like 1cm to z position. I want to every time when I pick up object or my player go to spawn more of this on the z position. How do I do this?
My smaller script:
public GameObject Sphere;
public float zrange;
// Use this for initialization
void Start () {
RandomPosition();
}
void RandomPosition()
{
zrange = Random.Range(0f, 2f);
this.transform.position = new Vector3(0, 0, zrange);
}
You achieve that by not messing with the x and y values (your code sets them both to 0).
Vector3 p = transform.position;
p.z = zrange;
transform.position = p;
This assumes that your code to instantiate the object is already correctly placing the object. If not, more information is needed.
I have created a game in which you can control X characters at the same time in the same form and they can die at any time. My problem is when I want the game camera to include all these gameobjects.
I thought that a good option is to calculate the central point between the gameobjects in the scene and make the camera follow that point at a certain distance.
I already have the camera code, but I still need to know how to get that central point or another way of doing it. In addition, the camera does not follow any of the axes (X, Y, Z) linearly, since it is placed in such a way that is the view is isometric (the game is in 3D).
As a last important fact, it is that all gameobjects that are running in the game (that are alive), are stored in a public static List <GameObject> to be able to access the components of these gameobjects at any time. Also, if a character (gameobject) dies or is born, the list is updated without problems.
I leave you a graphic example with three different cases, being the black points, the characters that are in the scene (gameobjects) and the red points, the central point (vector) that I would like to find.
Also, I leave the camera code so you can test if you have any solution:
public class Camera_Movement : MonoBehaviour {
Vector3 newPos;
public static List<GameObject> playersInGame = new List<GameObject>();
void Update() {
// Get Central Vector
// Replace playersInGame[0].transform.position with central vector
//newPos = Vector3.Lerp(gameObject.transform.position, "central vector", Time.deltaTime);
newPos = Vector3.Lerp(gameObject.transform.position, playersInGame[0].transform.position, Time.deltaTime);
gameObject.transform.position = new Vector3(newPos.x, newPos.y, newPos.z);
}
}
Thank you very much in advance!
You need to take the average x and and average y.
That would look like the following:
var totalX = 0f;
var totalY = 0f;
foreach(var player in playersInGame)
{
totalX += player.transform.position.x;
totalY += player.transform.position.y;
}
var centerX = totalX / playersInGame.Count;
var centerY = totalY / playersInGame.Count;
Let me know if this works for you (don't have access to Unity at the moment), but I put together an example here: https://dotnetfiddle.net/jGd99I
To have a solution that your camera can be best positioned to see all of your objects, then try this:
public Vector3 FindCenterOfTransforms(List<Transform> transforms)
{
var bound = new Bounds(transforms[0].position, Vector3.zero);
for(int i = 1; i < transforms.Count; i++)
{
bound.Encapsulate(transforms[i].position);
}
return bound.center;
}
So I created a turrent model in blender an imported into unity everything was looking good I got a little rotation script put togeather for my hub scene and rotation works good
Now moving into the code trying to rotate the barrel to look torwards the enemy doesnt look so good
Heres a short gameplay video to demonstrate the issue
Demonstration
the barrel of the turrent is facing a completly different place then the enemy I would much prefer to fix the issue in code rather then rebuilding the model from scratch so heres what Im doing currently(thats not working)
private void Update(){
FlameForgedTime.UpdateTime ();
if (isInGame) {
RegenerateHitpoint ();
//Look for enemy
if (FlameForgedTime.Time - lastAttack > StatsHelper.Instance.GetStatValue (Stat.Speed)) {
Collider[] col = Physics.OverlapSphere(transform.position,StatsHelper.Instance.GetStatValue (Stat.Range),LayerMask.GetMask("Enemy"));
if (col.Length != 0) {
//find closest enemy
int closestIndex = 0;
float dist = Vector3.SqrMagnitude (col [closestIndex].transform.position - transform.position);
for (int i = 1; i < col.Length; i++) {
float newDistance = Vector3.SqrMagnitude (col [i].transform.position - transform.position);
if (newDistance < dist) {
dist = newDistance;
closestIndex = i;
}
}
//shoot enemy
//Rotate turrent to look at enemy GameObject.FindGameObjectWithTag("Player").transform.LookAt(col[closestIndex].transform);
ShootEnemy(col[closestIndex].transform);
lastAttack = Time.time;
}
}
}
}
So on my turrent(parent gameobject) i have the tag "Player" as the turrent is loaded in a preloader scene and is not accessible by a public GameObject field
For some reason the Y is the axis the turrent rotates on
Anyways I get the closest enemy to the tower and then do a LookAt to try to get the turret to look at the enemy and then shoot at the enemy however that is not working correctly as you can see by the video
The "forward" axis on your model (that is, the direction the gun barrels point) doesn't line up with what Unity says is the forward axis.
"Forward" in Unity is along the positive Z direction, so your model doesn't line up with its transform's local forward (which is what points towards things when using LookAt()). Looks like your model is aligned with forward along the positive X axis instead.
There are three ways to fix this:
rotate it in Blender and reexport (best option)
create an empty parent GameObject that "becomes" the gun object (that is, all references point to this new object, any scripts move from where they are now to here, etc), but you put the current object inside and rotate the now-child transform by 90 degrees. This is also called "recentering" sometimes. With assets that aren't yours, this is sometimes the only option.
script-wise rotate by 90 degrees after performing a LookAt() (not recommended)
First, I'd like to apologize because this is a very basic and repetitive question, but I am completely new to game development.
I understand that I can find a distance between two objects using:
float dist = Vector3.Distance(other.position, transform.position);
However, how can I find the distance between a point of one object to other object?
For instance let's say my object is this sphere
Now, how can I return an array that says that there are no objects to the left (null), in the front there is an object at 1, and to the right there is an object at 0.5?
Thank you for your patience and understanding
I'm not exactly sure what you wan't to achieve...
If you wan't to get potential objects at 0.5, 1, 1.5, etc. on lets say the Z Axis you probably would want to do this with raycasting.
If you wish to check for any objects returning the direction dependant to the Z Axis (0.5, 0.856, 1.45, etc) in contrast, you probably would either
use a scaled sphere collider and add the colliding object with the OnCollisionEnter Callback to the array/List
iterate through every object of the scene and check it's relative pos
Use Raycast Probes procedurally (using a density float and Raycasting every density offset on the Z Axis and checking if the ray hit anything ...)
...
Totally dependant on your case of use, and whether you use 2D or 3D.
Seneral
EDIT: Here's what you would want in 2D to get a wall withing range maxRange on the layer optionalWallLayer in direction y 1 (up in unity 2D)
float maxRange = 10.0f;
RaycastHit hit;
Vector3 dir = transform.TransformDirection(new Vector3 (0, 1, 0));
if (Physics.Raycast(transform.position, dir, maxRange, out hit, LayerMask optionalWallLayer))
{
Debug.Log ("Wall infront of this object in Range" + hit.distance);
// hit contains every information you need about the hit
// Look into the docs for more information on these
}
This would likely go into the Update Function of your Sphere's MonoBehaviour.
The option with the Sphere collider is useful if you are not sure if you are going to hit your obstacles. If these are small, you would likely want to add the said Sphere Collider as a component to your sphere, scale it up to your maximum distance, and add a MonoBehaviour script to the sphere, which would contain something like this:
public List<Transform> allObjectsInRange; // GameObjects to enclose into calculations, basically all which ever entered the sphere collider.
public List<float> relatedDistances;
void Update () {
// basic loop to iterate through each object in range to update it's distance in the Lists IF YOU NEED...
for (int cnt = 0; cnt < allObjectsInRange.Count; cnt++) {
relatedDistances[cnt] = Vector2.Distance (transform.position, allObjectsInRange[cnt].position);
}
}
// Add new entered Colliders (Walls, entities, .. all Objects with a collider on the same layer) to the watched ones
void OnCollisionEnter (Collision col) {
allObjectsInRange.Add (col.collider.transform);
relatedDistances.Add (Vector2.Distance (transform.position, col.collider.transform));
}
// And remove them if they are no longer in reasonable range
void OnCollisionExit (Collision col) {
if (allObjectsInRange.Contains (col.collider.transform)) {
relatedDistances.RemoveAt (allObjectsInRange.IndexOf (col.collider.transform));
allObjectsInRange.Remove (col.collider.transform);
}
}
That should do it, either of the options, based on your exact case, again:) Note both are pseudo-codes... Hope it helps!