Vector 3 array ,how to assign positions to Vector3 array - c#

We're trying to put positions in Vector3 array by taking their position in another vector and putting it in as an index in the Vector3 array. We're trying to make a board game,and we want to move the player to one of the positions of the Vector3 array.
public static Vector3[] Steps;
public static void Position()
{
Vector3 step = GameObject.Find("Step").transform.position;
Steps[0] = step;
Vector3 step1 = GameObject.Find("Step (1)").transform.position;
Steps[1] = step1;
and so on

Before assigning values to the array you will have to initialize it with a size like e.g.
public static Vector3[] Steps;
public static void Position()
{
Steps = new Vector3[someSize];
Vector3 step = GameObject.Find("Step").transform.position;
Steps[0] = step;
Vector3 step1 = GameObject.Find("Step (1)").transform.position;
Steps[1] = step1;
}
that someSize ofcourse has to match the amount of positions you are going to add.
Or instead rather do it dynamically using a list like
public static List<Vector3> Steps = new List<Vector3>();
public static void Position()
{
// optionally remove current values first
Steps.Clear();
Steps = new Vector3[someSize];
Vector3 step = GameObject.Find("Step").transform.position;
Steps.Add(step);
Vector3 step1 = GameObject.Find("Step (1)").transform.position;
Steps.Add(step1);
}
you access later exactly the same way
Steps[index]
Easier would be if you already can reference your GameObjects in the Scene beforehand you should do rather something like
[SerializeField] private List<Transform> _steps = new List<Transform>();
and simply reference all your GameObjects in this list via the inspector in Unity. This way you don't even need to get the positions directly but could simply publish this list like
[SerializeField] private List<Transform> _steps = new List<Transform>();
public static List<Transform> Steps;
private void Awake()
{
Steps = _steps;
}
and access them like
Steps[index].position

You could use a multi array:
List<List<Vector3>> Positions;
Then you will have a "2D board" and the positions look like so:
Positions[1][4];
Plus, your question is a bit confusing and hard to understand what you actually want.

Okay so guessing by your stated question I am guessing you are somewhat new to Unity right? So I will go over this a bit more detailed.
First thing I would fix is to make an instance of your class and not a static one. (Instanced one is the script that you can drog onto a game object) This is done so you can reference all objects much easily and actually make interacting of objects work. (If you wish to learn more about the use for this i can recommend you this video: https://www.youtube.com/watch?v=Rgvq8MUtfTo)
Next mistake would be that you did not initialize zhe array. Arrays in object oriented are a bit more tricky then in other languages like let's say Python for example. Here you need to explicitly either set the contents of the array when you initialize it, or at least define its length. This is something that you CANNOT change later on. If you wish to take a more dynamic approach at storing variables for C# I would take a look at Lists. (Check this out if you are unsure as to what exactly is different: https://www.educba.com/c-sharp-array-vs-list/)
And the final thing that is really bad if you get used to doing it is getting references to game object using the find method. While it works for sure and I'm guessing its fast for your example, once you fill your scene with game object it WILL grind to a halt. Its better to just drag refs to the object at the start OR if you are instantiating objects at runtime, you can keep track then.
So overall ASSUMING you have all the objects in the scene, I would solve your issue this way:
using UnityEngine;
public class GameManager : MonoBehaviour
{
public GameObject[] figures;
void Start(){
foreach(GameObject figure in figures){
//this is where you get all of their positions
Debug.log(figure.transform.position)
}
}
}
Bear in mind that you will have to assign the figure before the start to the component variable. You can read more about this here: https://docs.unity3d.com/Manual/VariablesAndTheInspector.html
Hope this helpsyou with your game!

Related

Weird Wheel spinning in unity

i was working on a simple car controller script and a humvee model i downloaded. the script works as its supposed to but the car wheels are out of place and are spinning crazy. i tried searching everywhere but didn't found any solution.
here's the code:
using UnityEngine;
public class GroundVehicleController : MonoBehaviour {
public void GetInput()
{
m_horizontalInput = Input.GetAxis("Horizontal");
m_verticalInput = Input.GetAxis("Vertical");
}
private void Steer()
{
m_steeringAngle = maxSteerAngle * m_horizontalInput;
frontDriverW.steerAngle = m_steeringAngle;
frontPassengerW.steerAngle = m_steeringAngle;
}
private void Accelerate()
{
frontDriverW.motorTorque = m_verticalInput * motorForce;
frontPassengerW.motorTorque = m_verticalInput * motorForce;
}
private void UpdateWheelPoses()
{
UpdateWheelPose(frontDriverW, frontDriverT);
UpdateWheelPose(frontPassengerW, frontPassengerT);
UpdateWheelPose(rearDriverW, rearDriverT);
UpdateWheelPose(rearPassengerW, rearPassengerT);
}
private void UpdateWheelPose(WheelCollider _collider, Transform _transform)
{
Vector3 _pos = _transform.position;
Quaternion _quat = _transform.rotation;
_collider.GetWorldPose(out _pos, out _quat);
_transform.position = _pos;
_transform.rotation = _quat;
}
private void FixedUpdate()
{
GetInput();
Steer();
Accelerate();
UpdateWheelPoses();
}
private float m_horizontalInput;
private float m_verticalInput;
private float m_steeringAngle;
public WheelCollider frontDriverW, frontPassengerW;
public WheelCollider rearDriverW, rearPassengerW;
public Transform frontDriverT, frontPassengerT;
public Transform rearDriverT, rearPassengerT;
public float maxSteerAngle = 30;
public float motorForce = 50;
}
The error on Unity console is telling you the problem:
UnassignedReferenceException: The variable frontDriverW of
groundVehicleController has not been assigned. You problably need to
assign the frontDriverW variable of the GroundVehicleController script
in the inspector.
Well, when your script runs, it tries to access the field frontDriverW, but since it was never assigned a value, it throws the mentioned exception.
You need to go in the inspector for the object that contains the GroundVehicleController script and add a value for the frontDriverW field. While you're there, make sure all the other fields have values too, because if they don't, those will also cause the same error.
From the pictures you've show us, it is not possible to know in which object you added the GroundVehicleController script, but just check all of the Humvee objects until you find it in the inspector. My guess is that it will probably be in the object Wheels, or the object Humvee.
a) Check the prefab you've created to see if these offsets are there even on the prefab.
b) You're updating the wheel pose with global positions and rotations. this is probably what is causing the offsets. try setting the pose local, or just make the wheel meshes follow whatever the wheel colliders are doing, make sure they're all under the same co-ordinate space. Why not just child each individual wheel to it's corresponding wheel collider? theyre just meshes after all.
c) You haven't assigned your wheel meshes at all in your script.
c) play around with different mass values on the RigidBody (keep it heavy), and also consider attaching a physic material to your wheel colliders to reduce slip and spinning (If the car controller already doesnt have a slip setting)

Create animations programmatically in Unity?

In my game I have a big catalog of gear: Armors, weapons and shields. The combinations between these can be really immense.
Besides that, the player has the option of switching in-game to a different set of armor-weapon combination. In the end to solve this, I have used the following object structure.
Whenever I switch the weapons, I activate/deactivate the necessary GameObjects. The animations are set in this way:
Now, the problem is creating the animation. I first considered pre-rendering programatically all the combinations, but my catalog is so huge, that it would create 100s, if not 1000s of animations. So I opted for a different solution. Create in playtime the animation, once I knew what gear would the player select. For that, I created a script to take care of that. The problem is that I have been using APIs from UnityEditor, and now I have realized the build will not work. Specifically because of 2 different classes: EditorCurveBinding and ObjectReferenceKeyframe.
This is a couple snippets of how I was using this classes when creating the animations:
static EditorCurveBinding GetEditorCurveBinding(string path = "")
{
EditorCurveBinding spriteBinding = new EditorCurveBinding();
spriteBinding.type = typeof(SpriteRenderer);
spriteBinding.path = path;
spriteBinding.propertyName = "m_Sprite";
return spriteBinding;
}
static ObjectReferenceKeyframe GetKeyframe(float time, Sprite sprite)
{
ObjectReferenceKeyframe keyframe = new ObjectReferenceKeyframe();
keyframe.time = time / FRAMERATE;
keyframe.value = sprite;
return keyframe;
}
Now, the problem with the Curve, I think I managed to solve, replacing it with this code, replacing EditorCurveBinding with AnimationCurve:
AnimationClip clip = ...
AnimationCurve curve = new AnimationCurve();
clip.SetCurve(path, typeof(SpriteRenderer), "m_Sprite", curve);
But I have no idea how to set the sprites for each animation. I thought that using curve.AddKeycould be helpful, but I have seen no way to add a sprite there.
How could I rewrite that code to avoid using UnityEditor?
Full code
Personally, I would completely avoid built-in Animator and Animations, since this tool is for the very narrow purpose of animating a single object in a predefined way (eg: for a cutscene).
Offtopic - performance
Besides that, the player has the option of switching in-game to a different set of armor-weapon combination. In the end to solve this, I have used the following object structure.
As you probably know this is very inefficient memory-wise and will decrease performance (disabled objects still have marginal CPU overhead). And will incread load time and instantiation time of new objects.
Can I use Animator or Animation?
Because Animator has no API to access it's internals and animation type and overall you cannot do pretty mutch nothing with it except from telling it to Play or Stop.
Since I understand that your animation is "Sprite based" and not "Transform based" any sane idea is just inefficient!
Best solution that I vow against is as follows:
Create "trigger points" that you would "animate"
Based on trigger point - change sprite
public class AnimationController : MonoBehaviour
{
public int AnimationIndex;
public Sprite[] AnimationSprites;
public SpriteRenderer SpriteRenderer;
private void Update()
{
SpriteRenderer.sprite = AnimationSprites[AnimationIndex];
}
}
Better solution?
Since we already need to have custom structure that manages our sprites we might want to optimize the whole thing, since we are not using almost any of the features of Animator we could write custom controller that would replace Animator in this case. This should improve performance significantly since Animator is very heavy!
// MonoBehaviour is optional here
public class SpriteRendererAnimationHandler
{
// More fields that would control the animation timing
public Sprite[] AnimationSprites;
public SpriteRenderer SpriteRenderer;
public void OnAnimationUpdate(int index)
{
var resolvedIndex = ResolveIndex(index);
SpriteRenderer.sprite = AnimationSprites[resolvedIndex];
}
private int ResolveIndex(int index)
{
// Resolve animation index to sprite array index
}
}
// One controller per character - or global per game that synchronize all animations to locked FPS 12.
public class AnimationController : MonoBehaviour
{
private List<SpriteRendererAnimationHandler> Handlers = new List<SpriteRendererAnimationHandler>();
public void FixedUpdate()
{
foreach (var handler in Handlers)
{
// Calculate animation index
int calculatedAnimationIndex = ...;
handler.OnAnimationUpdate(calculatedAnimationIndex);
}
}
}
Add a public field named animation index to Tomasz last example, then create the animations in animator as youd normal do for animation pieces, then animate that animation index field. simple if(currentAnimationyion != lastAnimationIndex) to check if need to send to handlers and ya rocking

Unity 2D: Gravitational Pull

I'm working on a small game: I want all GameObjects to be pulled into the middle of the screen where they should collide with another GameObject.
I tried this attempt:
using UnityEngine;
using System.Collections;
public class Planet : MonoBehaviour
{
public Transform bird;
private float gravitationalForce = 5;
private Vector3 directionOfBirdFromPlanet;
void Start ()
{
directionOfGameObjectFromMiddle = Vector3.zero;
}
void FixedUpdate ()
{
directionOfGameObjectFromMiddle = (transform.position-bird.position).normalized;
bird.rigidbody2D.AddForce (directionOfGameObjectFromMiddle * gravitationalForce);
}
}
sadly I can't get it to work. I've been told that I have to give the object that is being pulled another script but is it possible to do this just with one script that is used on the object that pulls?
So first you have a lot of typos / code that doesn't even compile.
You use e.g. once directionOfBirdFromPlanet but later call it directionOfGameObjectFromMiddle ;) Your Start is quite redundant.
As said bird.rigidbody2D is deprecaded and you should rather use GetComponent<Rigidbody2D>() or even better directly make your field of type
public Rigidbody2D bird;
For having multiple objects you could simply assign them to a List and do
public class Planet : MonoBehaviour
{
// Directly use the correct field type
public List<Rigidbody2D> birds;
// Make this field adjustable via the Inspector for fine tuning
[SerializeField] private float gravitationalForce = 5;
// Your start was redundant
private void FixedUpdate()
{
// iterate through all birds
foreach (var bird in birds)
{
// Since transform.position is a Vector3 but bird.position is a Vector2 you now have to cast
var directionOfBirdFromPlanet = ((Vector2) transform.position - bird.position).normalized;
// Adds the force towards the center
bird.AddForce(directionOfBirdFromPlanet * gravitationalForce);
}
}
}
Then on the planet you reference all the bird objects
On the birds' Rigidbody2D component make sure to set
Gravity Scale -> 0
you also can play with the Linear Drag so in simple words how much should the object slow down itself while moving
E.g. this is how it looks like with Linear Drag = 0 so your objects will continue to move away from the center with the same "energy"
this is what happens with Linear Drag = 0.3 so your objects lose "energy" over time

Trying to create a list of Transforms of objects that enter a sphere in Unity 3D

I'm trying to both align my object with the surrounding objects and have the object try and get the average position of it's surrounding objects,I am trying to do this by creating a list of all the objects that enter a sphere and using there transform to do the calculations however unity only accepts lists of colliders. I would really appreciate some help or advice, further info is that this script is on 200 clones of the same gameobject and the script below gives the error
Cannot implicitly convert type 'UnityEngine.Collider[]' to 'System.Collections.Generic.List'
IEnumerator Flock()
{
Collider[] NearbyBoids = Physics.OverlapSphere(BoidVec, VisionRange, BoidMask, QueryTriggerInteraction.Collide);
foreach (Collider Boid in NearbyBoids)
{
List<Transform> context = NearbyBoids;
}
yield return null;
}
To reduce the number of iterations your Boids have to make, it might make sense to just have them keep a context list of other Boids that enter or leave a trigger volume you set up in the inspector as an "area of sight". Then you can have each Boid evaluate it's own up to date context in Update.
Something along the lines of:
using System.Collections.Generic;
using UnityEngine;
public class Boid : MonoBehaviour
{
private List<Transform> context = new List<Transform>();
private void OnTriggerEnter(Collider other)
{
// good if you want to call the other Boid component
Boid boid = other.gameObject.GetComponent<Boid>();
if (boid != null)
{
context.Add(other.transform);
}
}
private void OnTriggerExit(Collider other)
{
// Pretty efficient, requires tagging of boid objects
if (other.CompareTag("boidTag"))
{
context.Remove(other.transform);
}
}
private void Update()
{
foreach(Transform otherBoid in context)
{
// doing some stuff here based on boids within context
}
}
}
Two ways to go about this.
Quick way is to use LINQ. To do this you need the using namespace declaration
using System.Linq;
Collider[] arrayOfNearbyTransforms = Physics.OverlapSphere(BoidVec, VisionRange, BoidMask, QueryTriggerInteraction.Collide);
List<Transform> listOfAllNearbyTransforms = arrayOfNearbyTransforms.Select(x => x.transform).ToList();
The issue with the code you've posted is that you're creating a list within your loop. Variables declared within a loop only exist within that loop's execution, so you're essentially creating as many lists as there are colliders, while using none of them.
Instead, you should create the list outside your loop, and add transform components from within the loop
void Flock()
{
// This is the array of colliders you've gathered from nearby objects
Collider[] NearbyBoids = Physics.OverlapSphere(BoidVec, VisionRange, BoidMask, QueryTriggerInteraction.Collide);
// This is a brand new list. It's empty at the moment
List<Transform> listOfAllNearbyTransforms = new List<Transform>();
// We're looping through every collider in the array.
foreach (Collider currentColliderReference in NearbyBoids)
{
// Everything that happens in here happens once for every collider.
// The variable currentColliderReference refers to the collider we're looking at during this part of the loop. So throughout the loops execution, it will change to refer to every collider in your array, one at a time.
// We get a reference to the current collider's transform component
Transform transformOfCurrentCollider = currentColliderReference.transform;
// We add that to the list of transform component
listOfAllNearbyTransforms.Add(transformOfCurrentCollider);
}
// At this point listOfAllNearbyTransforms will be a list of all transforms within the area specified in your OverlapSphere() call
}
As you can tell, I've also changed the return type to void. There's no reason for this function to be a coroutine
While I wouldnt do this as a CoRoutine at this stage, Ive kept your code as similar as possible. Unless you really imagine a lot of units 1000's the longest part of the code to run is the overlapsphwere.
List<Transform> context = new List<Transform>();
IEnumerator Flock()
{
context.Clear(); // if there are 1000s this could be costly
Collider[] NearbyBoids = Physics.OverlapSphere(BoidVec, VisionRange, BoidMask, QueryTriggerInteraction.Collide);
foreach (Collider Boid in NearbyBoids)
{
context.Add(NearbyBoids.transform);
}
yield return null;
}
this gives you a class level list of context, which you can access from elsewhere.
Then your context list will have current transforms, but I wouldnt want to run this too often, personally Id use a list and triggers... So, add to list onenter, and remove from list onleave..

How can I swap the positions of two objects at different speeds, instead of an instant swap?

I have a script that currently swaps the position of 2 objects. The objects are the same size and shape so that when they swap positions, it's instant and you don't see them move toward the position. How can I make it so there is a movement speed when the two objects swap places, so that you can see them actually moving positions. I also need to figure out how to add a third object so that they all switch positions randomly. Something like this is my final goal: http://i249.photobucket.com/albums/gg240/OldNewby4507/shell-game-animated.gif
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour
{
public float movementSpeed = 10;
public GameObject g1;
public GameObject g2;
public Vector3 vec1;
public Vector3 vec2 = new Vector3(2F, 2F, 2F);
public bool swapBack = false;
void Start()
{
g1 = GameObject.Find("object1");
g2 = GameObject.Find("object2");
vec1 = new Vector3(g1.gameObject.transform.position.x, g1.gameObject.transform.position.y, g1.gameObject.transform.position.z);
vec2 = new Vector3(g2.gameObject.transform.position.x, g2.gameObject.transform.position.y, g2.gameObject.transform.position.z);
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
vec1 = g1.gameObject.transform.position;
vec2 = g2.gameObject.transform.position;
g1.gameObject.transform.position = vec2;
g2.gameObject.transform.position = vec1;
}
}
}
right now my movementSpeed variable is unused.
The way i would tackle this is the following:
You need to create a function which is called, for example, MovePath. MovePath will be governed by a formula that determines how the object moves from point A to point B (this can be linearly, exp, log, etc). MovePath takes three parameters, vector Start, vector End and int or double MoveSpeed. To get from point A to point B will take steps equal to MoveSpeed. So you are calculating positions at each step of the way.
Update will need to be modified so that it takes int MoveSpeed as a parameter. Update will keep updating by using the movepath method until vector start becomes vector end. You will be calling MovePath twice (one for each object thats moving) until for g1's position becomes g2's and g2's position becomes g1's. Update will track when G1 == G2 and G2 == G1 with respect to the positions and stop updating once that is complete.
You will need to implement async and await so that the UI can update. There might be a way to do this synchronously but i think going the async and await path will be much cleaner in the long run.
Please let me know if you have questions when you try to implement this. Once you try to implement this edit your question and I think people (and myself) will be able to chime in with issues you are running into when implementing this.
Edit: there are a lot of ways to implement this. An other example is you can change the MovePath so that it calls itself recursively until the end condition is met. I just wanted to provide you with an idea on how to tackle it.
You can Lerp the transition at difference rates, which is quite linear, if you would like you can also use Slerp or any of the other Vector3 methods.
You can also use libraries that offer Tweening operations such as iTween amongst a bunch of other ones on the asset store which will take care of the transition for you.
I would use Lerp, or Slerp. These are interpolation methods using math, and are quite simple and seamless. Your code would look something like this:
void Update() {
if (Input.GetMouseButtonDown(0)) {
vec1 = g1.gameObject.transform.position;
vec2 = g2.gameObject.transform.position;
g1.gameObject.transform.position = Vector3.Lerp(vec1, vec2, 0.5f);
g2.gameObject.transform.position = Vector3.Lerp(vec2, vec1, 0.5f);
}
}
Here is an excellent explanation of Lerp, it may help you in this case!

Categories