Disable rigidbody on a specific gameobject using C# and Unity - c#

I'm having trouble in my pinch code because it also grabs my player. Here is my code:
using UnityEngine;
using System.Collections;
using Leap;
using Leap.Unity;
/**
* Detects pinches and grabs the closest rigidbody if it's within a given range.
*
* Attach this script to the physics hand object assinged to the HandController in a scene.
*/
public class MagneticPinch : MonoBehaviour {
public const float TRIGGER_DISTANCE_RATIO = 0.7f;
/** The stiffness of the spring force used to move the object toward the hand. */
public float forceSpringConstant = 100.0f;
/** The maximum range at which an object can be picked up.*/
public float magnetDistance = 0.5f;
protected bool pinching_;
protected Collider grabbed_;
public GameObject TrashAudio;
public GameObject myPlayer;
void Start() {
pinching_ = false;
grabbed_ = null;
}
/** Finds an object to grab and grabs it. */
void OnPinch(Vector3 pinch_position) {
pinching_ = true;
// Check if we pinched a movable object and grab the closest one that's not part of the hand.
Collider[] close_things = Physics.OverlapSphere(pinch_position, magnetDistance);
Vector3 distance = new Vector3(magnetDistance, 0.0f, 0.0f);
for (int j = 0; j < close_things.Length; ++j) {
Vector3 new_distance = pinch_position - close_things[j].transform.position;
if (close_things[j].GetComponent<Rigidbody>() != null && new_distance.magnitude < distance.magnitude &&
!close_things[j].transform.IsChildOf(transform)) {
grabbed_ = close_things[j];
distance = new_distance;
}
}
}
/** Clears the pinch state. */
void OnRelease() {
grabbed_ = null;
pinching_ = false;
TrashAudio.gameObject.SetActive (false);
//ActivateRigidbody ();
}
/**
* Checks whether the hand is pinching and updates the position of the pinched object.
*/
void Update() {
bool trigger_pinch = false;
HandModel hand_model = GetComponent<HandModel>();
Hand leap_hand = hand_model.GetLeapHand();
if (leap_hand == null)
return;
// Scale trigger distance by thumb proximal bone length.
Vector leap_thumb_tip = leap_hand.Fingers[0].TipPosition;
float proximal_length = leap_hand.Fingers[0].Bone(Bone.BoneType.TYPE_PROXIMAL).Length;
float trigger_distance = proximal_length * TRIGGER_DISTANCE_RATIO;
// Check thumb tip distance to joints on all other fingers.
// If it's close enough, start pinching.
for (int i = 1; i < HandModel.NUM_FINGERS && !trigger_pinch; ++i) {
Finger finger = leap_hand.Fingers[i];
for (int j = 0; j < FingerModel.NUM_BONES && !trigger_pinch; ++j) {
Vector leap_joint_position = finger.Bone((Bone.BoneType)j).NextJoint;
if (leap_joint_position.DistanceTo(leap_thumb_tip) < trigger_distance)
trigger_pinch = true;
}
}
Vector3 pinch_position = hand_model.fingers[0].GetTipPosition();
// Only change state if it's different.
if (trigger_pinch && !pinching_)
OnPinch(pinch_position);
else if (!trigger_pinch && pinching_)
OnRelease();
//this line of code is a self scripting for disabling the rigidbody from the player component
// Accelerate what we are grabbing toward the pinch.
if (grabbed_ != null) {
Vector3 distance = pinch_position - grabbed_.transform.position;
//DeactivateRigidbody (); //this is not to grab the rigidbody of the player
grabbed_.GetComponent<Rigidbody> ().AddForce (forceSpringConstant * distance);
TrashAudio.gameObject.SetActive (true);
//DeactivateRigidbody ();
}
}
}
Every object must have a rigidbody that is set to USE GRAVITY so my player as well so that it will not go through my terrain . My script is grabs the nearest object that has a rigidbody. The problem is when I grab some object its always grab itself I mean my player. I'm using a leap motion to grab.
So how can I obtain that if my script detects that it is grabbing my player it will stop grabbing but instead grab the object?

Really easy.
You can tag your player like player like in image:
then add to your code something like this into the method OnPinch
// Check if we pinched a movable object and grab the closest one that's not part of the hand.
Collider[] close_things = Physics.OverlapSphere(pinch_position, magnetDistance);
Vector3 distance = new Vector3(magnetDistance, 0.0f, 0.0f);
for (int j = 0; j < close_things.Length; ++j) {
if(close_things[j].gameobject.Tag.ToUppercase() == "PLAYER")
continue; //here you jump to a the next object
PS: Or you can simply use a different layer that ignore the player

By using
//attach this script to pinching
void DeactivateRigid(){
myPlayer.Getcomponent<Rigidbody>().isKenimatic == false;
myPlayer.Getcomponent<Rigidbody().detectCollision = true;
}
//attach this script to release
void ActivateRigid(){
...
}

My Unity is a bit rusted but you can attach a tag to GameObject, https://docs.unity3d.com/ScriptReference/GameObject-tag.html
Be sure to tag the player as a player, afterwards you could use a check whether the nearest gameobjects tag isn't "player".

Related

How can I use multiple enums (two enums) to control two axis the object will rotate at the same time?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotate : MonoBehaviour
{
public enum Axistorotate { Back, Down, Forward, Left, Right, Up, Zero };
public Vector3[] vectorAxises = new Vector3[7];
public Axistorotate[] myAxis;
public float angle;
public float speed;
private bool stopRotation = true;
// Start is called before the first frame update
void Start()
{
vectorAxises[0] = Vector3.back;
vectorAxises[1] = Vector3.down;
vectorAxises[2] = Vector3.forward;
vectorAxises[3] = Vector3.left;
vectorAxises[4] = Vector3.right;
vectorAxises[5] = Vector3.up;
vectorAxises[6] = Vector3.zero;
StartCoroutine(RotateObject());
}
public Vector3 GetAxis(Axistorotate axis)
{
return vectorAxises[(int)axis];
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.S))
{
stopRotation = false;
}
if (Input.GetKeyDown(KeyCode.C) && stopRotation == false)
{
stopRotation = true;
StartCoroutine(RotateObject());
}
}
IEnumerator RotateObject()
{
while (stopRotation == true)
{
for (int i = 0; i < myAxis.Length; i++)
{
transform.Rotate(GetAxis(myAxis[i]), angle);
}
yield return new WaitForSeconds(speed);
}
}
}
For some reason while the game is running and I'm changing one of the enums to forward or back or down each time it's rotating another direction. If I'm starting when both enums on back states and then changing one of them to down it looks like it's rotating to the left or right and then when changing back to back it's not rotating like it was when they were both set to back.
How can I update the vectorAxises array in real time while the game is running to show in the Inspector the current axis state for example : vectorAxises[0] -> 1, 0, -1 ..... vectorAxises[7] -> 0,-1, 0 I want that when I'm changing one of the enums that it will show it on the vectorAxises.
Maybe I need to create another vectorAxises array one for each enum ?
And maybe when doing two myAxis it's changing the same one the same angle so it's not realy two enums that change individual axis ?
transform.Rotate has an optional parameter
relativeTo
Determines whether to rotate the GameObject either locally to the GameObject or relative to the Scene in world space.
which by default is Space.Self.
So your
transform.Rotate(GetAxis(myAxis[i]), angle);
is always done in the local coordinate system of the GameObject. This local system is rotated along with the GameObject so the local transform.up, transform.forward etc axis change all the time.
Instead make it rotate around world axis
transform.Rotate(GetAxis(myAxis[i]), angle, Space.World);
How can I update the vectorAxises array in real time while the game is running to show in the Inspector the current axis state
This should already be the case. Or do you mean you want to see the currently "selected" value. You should use Debugging and Breakpoints for that. Since you do
for (int i = 0; i < myAxis.Length; i++)
{
transform.Rotate(GetAxis(myAxis[i]), angle);
}
without any further yield return the object will directly "jump" into the new rotation and in the inspector you would always only see the last GetAxis(myAxis[i]).
If you are looking for a smooth rotation then checkout Dest's answer slightly modified you could e.g. let the object rotate within 1 second
while (stopRotation == true)
{
// calculate the target rotation
Quaternion rotationQuaternion = Quaternion.identity;
for (int i = 0; i < myAxis.Length; i++)
{
rotationQuaternion *= Quaternion.AngleAxis(angle, GetAxis(myAxis[i]));
}
// before starting to rotate store initial and target rotation
var initialRotation = transform.rotation;
var targetRotation = initialRotation * rotationQuaternion;
// could also get this from the Inspector e.g.
var rotationDuration = 1;
// Do a smooth rotation from the initial to target rotation
// within the defined rotationDuration
var timePassed = 0f;
do
{
// additionally ease-in and -out the rotation
var lerpFactor = Mathf.SmoothStep(0, 1, timePassed / rotationDuration);
transform.rotation = Quaternion.Slerp(initialRotation, targetRotation, lerpFactor);
timePassed += Time.deltaTime;
// let this state be rendered
yield return null;
} while(timePassed < rotationDuration);
// if you still want the pause
yield return new WaitForSeconds(speed);
}
Just out of curiosity: Why even use an enum here? Couldn't you directly iterate through the vectorAxises index instead and only add those entries you will be using?
Use Quaternions for multiple rotations at the same time:
Quaternion rotationQuaternion = Quaternion.identity;
for (int i = 0; i < myAxis.Length; i++)
{
rotationQuaternion *= Quaternion.AngleAxis(angle, GetAxis(myAxis[i]));
}
transform.rotation *= rotationQuaternion;
It should fix your problem with wrong rotations

Unity 3D Collisiondetection

I generate an Gameobjct array of speheres and try to apply a collider to them to detect collision with my character controller.
i tried serverel methods, nothing worked. Why Unity doent detect the collision ?
Script for generating the array :
public GameObject[] Chunkzufall(float l, float b, int n)
{
GameObject chunk = new GameObject();
GameObject[] chunks = new GameObject[n];
chunkSpeed = new float[n];
chunkMaxH = new float[n];
chunkMinH = new float[n];
for (int j = 0; j < n; j++)
{
float h = 1;
float posX = Random.Range(0.0f, b);
float posZ = Random.Range(0.0f, l);
GameObject group = Chunk(h);
group.transform.Translate(posX, 0.0f, posZ);
group.transform.parent = chunk.transform;
chunk.tag = "reset";
chunk.name = "chunk";
chunkSpeed[j] = (float) Random.Range(-0.04f, 0.04f);
chunkMaxH[j] = (float) Random.Range(2.0f, 10.0f);
chunkMinH[j] = (float) Random.Range(-2.0f, -10.0f);
chunk.AddComponent<SphereCollider>();
chunk.GetComponent<SphereCollider>().isTrigger = true;
chunk.GetComponent<SphereCollider>().radius = 5.0f;
chunks[j] = chunk;
}
return chunks;
}
public void MoveChunks(GameObject[] chunks)
{
int i = 0;
foreach(GameObject chunk in chunks)
{
Vector3 position = chunk.transform.GetChild(i).position;
if (position.y >= chunkMaxH[i] || position.y <= chunkMinH[i])
{
chunkSpeed[i] = chunkSpeed[i] * -1;
}
position.y = position.y - chunkSpeed[i];
chunk.transform.GetChild(i).position = position;
chunk.GetComponent<SphereCollider>().center = position;
i++;
}
i = 0;
}
collision trigger function :
private void OnTriggerEnter(Collider col) {
if(col.gameObject.tag == "reset") {
transform.position = new Vector3(startX, startY, startZ);
Debug.Log("chunk");
}
}
To detect a trigger on the dynaimcally created object, you have to enable the IsTrigger flag, add collider to the object. The object must also have Rigidbody attached to it. It looks like you already have the IsTrigger flag and a collider but you are missing Rigidbody.
Replace this:
chunk.AddComponent<SphereCollider>();
chunk.GetComponent<SphereCollider>().isTrigger = true;
chunk.GetComponent<SphereCollider>().radius = 5.0f;
with
chunk.AddComponent<SphereCollider>();
chunk.AddComponent<Rigidbody>(); //ADDS RIGIDBODY COMPONENT
chunk.GetComponent<SphereCollider>().isTrigger = true;
chunk.GetComponent<SphereCollider>().radius = 5.0f;
Do you have Rigidbody attached? The objects need Rigidbody attached to it to be able to detect collision. And do note that for each pair of collider and collided objects, having one of them with Rigidbody attached is enough to capture the event. In your case, if you don't want to process the collision betweens spheres, then attach Rigidbody to your character object is good enough.
You could add a RigidBody to all of the spheres but that would be very inefficient if you want to have many of them. It is enough to have 1 RigidBody for every 2 objects that you want to check collision against.
So in your case it would be enough to put a RigidBody component on your character controller object.
Also, make sure the RigidBody is not set to Kinematic.

Switching between two or more cameras unity3D

I'm making a game in which the player controls two different characters (each one has its own empty object with a camera as child), and switchs one or another by pressing the control key. The thing is, I'm trying to make a little transition between both characters cameras by using another camera, so it doesn't just teleports between one and another but I can't seem to do it. I tried with lerp but I don't know if I got it right, so I read and tried Vector3.MoveTowards but still couldn't do it. This is my code so far (the while is because a last-moment-braindead I had):
public class CameraController : MonoBehaviour
{
public Camera cam1;
public Camera cam2;
public Camera movingCamera;
public bool isCurrentPlayer;
public Transform target1;
public Transform target2;
public float speed = 0.2f;
void FixedUpdate()
{
float step = speed * Time.deltaTime;
if (Input.GetButtonDown("Control"))
{
if (isCurrentPlayer)
{
movingCamera.enabled = true;
cam2.enabled = false;
while (transform.position != target1.position)
{
transform.position = Vector3.MoveTowards(transform.position, target1.position, step);
}
if (transform.position == target1.transform.position)
{
movingCamera.enabled = false;
cam1.enabled = true;
}
isCurrentPlayer = false;
}
else if (!isCurrentPlayer)
{
movingCamera.enabled = true;
cam1.enabled = false;
while (transform.position != target2.position)
{
transform.position = Vector3.MoveTowards(transform.position, target2.position, step);
}
if (transform.position == target2.transform.position)
{
movingCamera.enabled = false;
cam2.enabled = true;
}
isCurrentPlayer = true;
}
}
}
I'm curious about two things. Why did you use FixedUpdate to manage your updates? This isn't physics code. Is there a particular reason you are using multiple cameras? If I may, I propose the following changes.
You can simply make use of the main camera instead of multiple cameras. Additionally, you can increase the number of player objects you can toggle through by using an array of player GameObjects, and by changing the input parameters to left control and right control, you can toggle between next player and previous player to navigate bi-directionally through the array of players.
Here's my example code that implements these changes (tested and works, though improvements can be made.)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Attached to Main Camera
public class CameraController : MonoBehaviour {
// set manually in inspector
public GameObject[] players;
public float movementSpeed = 1.0f;
public float rotationSpeed = 1.0f;
private int currentPlayer;
private float startTime;
private float distanceToPlayer;
private Vector3 startPosition;
private Quaternion startOrientation;
// Use this for initialization
void Start () {
currentPlayer = 0;
ResetCamera();
}
// Update is called once per frame
void Update () {
float distanceCovered;
float rotationCovered;
float fractionTraveled;
// switch to previous
if (Input.GetButtonDown("left ctrl")) {
if (currentPlayer == 0) currentPlayer = players.Length - 1;
else currentPlayer--;
ResetCamera();
}
// switch to nextPlayer
if (Input.GetButtonDown("right ctrl")) {
if (currentPlayer == players.Length - 1) currentPlayer = 0;
else currentPlayer++;
ResetCamera();
}
// Keep moving camera
if (transform.position != players[currentPlayer].transform.position)
{
distanceCovered = (Time.time - startTime) * movementSpeed;
fractionTraveled = distanceCovered / distanceToPlayer;
rotationCovered = (Time.time - startTime) * rotationSpeed;
// Lerp to player position
transform.position = Vector3.Lerp(
startPosition,
players[currentPlayer].transform.position,
fractionTraveled
);
// match player orientation
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
players[currentPlayer].transform.rotation,
rotationCovered
);
// Stop moving camera
} else {
// Match orientation
if (transform.rotation != players[currentPlayer].transform.rotation)
transform.rotation = players[currentPlayer].transform.rotation;
// Set parent transform to current player
transform.parent = players[currentPlayer].transform;
}
}
void ResetCamera() {
transform.parent = null;
startTime = Time.time;
startPosition = transform.position;
startOrientation = transform.rotation;
distanceToPlayer = Vector3.Distance(
transform.position,
players[currentPlayer].transform.position
);
}
}
Obviously the values would need to be tweaked, and the movement algorithm is pretty basic. Crude but function. You can also add player movement code into the camera, just make sure it points to players[currentPlayer] and it will work for each of your player objects without having to use additional scripts unless there is a reason to do so.
Feel free to use this code. Like I said, it works. However, should you choose to do so, it can easily be modified to function like your original code simply by removing the array and reinstating the individual GameObjects.
transform.position points to the position of CameraController game object. If you want to move movingCamera you probably want to use movingCamera.transform.position. Also keep in mind that in your script the MoveTowards() would only fire when you are pressing your "Control" button.
As memBrain said it would be the best practice to use only one camera for this - visually it would look the same.
The script should look something like this:
// Assuming target1 is player 1 and target2 is player 2
private float snapThreshold = 0.1f;
private Vector3 movingCameraDestination = Vector3.zero;
void FixedUpdate()
{
if(Input.GetButtonDown("Control"))
{
if(isCurrentPlayer)
{
//Set position of transition camera to player 1 and set it's destination to player's 2 position
movingCamera.transform.position = player1.position;
movingCameraDestination = player2.position;
//Disable player 1 camera and enable transition camera
cam1.enabled = false;
movingCamera.enabled = true;
}
else
{
//Set position of transition camera to player 21 and set it's destination to player's 1 position
movingCamera.transform.position = player2.position;
movingCameraDestination = player1.position;
//Disable player 1 camera and enable transition camera
cam2.enabled = false;
movingCamera.enabled = true;
}
}
//If transition camera is enabled and its destination is not Vector3.zero - move it
if(movingCameraDestination != Vector3.zero && movingCamera.enabled)
{
movingCamera.transform.position = Vector3.Lerp(movingCamera.transform.position, movingCameraDestination, speed * Time.deltaTime);
//If the distance between transition camera and it's destination is smaller or equal to threshold - snap it to destination position
if(Vector3.Distance(movingCamera.transform.position, movingCameraDestination) <= snapThreshold)
{
movingCamera.transform.position = movingCameraDestination;
}
//If transition camera reached it's destination set it's destination to Vector3.zero and disable it
if(movingCamera.transform.position == movingCameraDestination)
{
movingCameraDestination = Vector3.zero;
movingCamera.enabled = false;
}
}
}

objects using their own unique waypoints array

update...
First Class
using UnityEngine;
using System.Collections;
[System.Serializable]
public class Wave
{
public GameObject enemyPrefab;
public float spawnInterval = 2;
public int maxEnemies = 20;
}
public class SpawnEnemy : MonoBehaviour
{
public GameObject[] waypoints;
public GameObject testEnemyPrefab;
public Wave[] waves;
public int timeBetweenWaves = 5;
private GameManagerBehavior gameManager;
private float lastSpawnTime;
private int enemiesSpawned = 0;
// Use this for initialization
void Start()
{
lastSpawnTime = Time.time;
gameManager =
GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
}
// Update is called once per frame
void Update()
{
// 1 Get the index of the current wave, and check if it’s the last one.
int currentWave = gameManager.Wave;
if (currentWave < waves.Length)
{
// 2 If so, calculate how much time passed since the last enemy spawn and whether it’s time to spawn an enemy. Here you consider two cases.
// If it’s the first enemy in the wave, you check whether timeInterval is bigger than timeBetweenWaves.
// Otherwise, you check whether timeInterval is bigger than this wave’s spawnInterval. In either case, you make sure you haven’t spawned all the enemies for this wave.
float timeInterval = Time.time - lastSpawnTime;
float spawnInterval = waves[currentWave].spawnInterval;
if (((enemiesSpawned == 0 && timeInterval > timeBetweenWaves) ||
timeInterval > spawnInterval) &&
enemiesSpawned < waves[currentWave].maxEnemies)
{
// 3 If necessary, spawn an enemy by instantiating a copy of enemyPrefab. You also increase the enemiesSpawned count.
lastSpawnTime = Time.time;
GameObject newEnemy = (GameObject)
Instantiate(waves[currentWave].enemyPrefab);
newEnemy.GetComponent<MoveEnemy>().waypoints = waypoints;
newEnemy.GetComponent<MoveEnemy>().JiggleWaypoints();
enemiesSpawned++;
}
// 4 You check the number of enemies on screen. If there are none and it was the last enemy in the wave you spawn the next wave.
// You also give the player 10 percent of all gold left at the end of the wave.
if (enemiesSpawned == waves[currentWave].maxEnemies &&
GameObject.FindGameObjectWithTag("Enemy") == null)
{
gameManager.Wave++;
gameManager.Gold = Mathf.RoundToInt(gameManager.Gold * 1.1f);
enemiesSpawned = 0;
lastSpawnTime = Time.time;
}
// 5 Upon beating the last wave this runs the game won animation.
}
else {
gameManager.gameOver = true;
GameObject gameOverText = GameObject.FindGameObjectWithTag("GameWon");
gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
}
}
}
Second Class
using UnityEngine;
using System.Collections;
public class MoveEnemy : MonoBehaviour
{
[System.NonSerialized]
public GameObject[] waypoints;
private int currentWaypoint = 0;
private float lastWaypointSwitchTime;
public float speed = 1.0f;
// Use this for initialization
void Start()
{
lastWaypointSwitchTime = Time.time;
}
// Update is called once per frame
void Update()
{
// 1
Vector3 startPosition = waypoints[currentWaypoint].transform.position;
Vector3 endPosition = waypoints[currentWaypoint + 1].transform.position;
// 2
float pathLength = Vector3.Distance(startPosition, endPosition);
float totalTimeForPath = pathLength / speed;
float currentTimeOnPath = Time.time - lastWaypointSwitchTime;
gameObject.transform.position = Vector3.Lerp(startPosition, endPosition, currentTimeOnPath / totalTimeForPath);
// 3
if (gameObject.transform.position.Equals(endPosition))
{
if (currentWaypoint < waypoints.Length - 2)
{
// 3.a
currentWaypoint++;
lastWaypointSwitchTime = Time.time;
RotateIntoMoveDirection();
}
else {
// 3.b
Destroy(gameObject);
AudioSource audioSource = gameObject.GetComponent<AudioSource>();
AudioSource.PlayClipAtPoint(audioSource.clip, transform.position);
//<< deduct health
GameManagerBehavior gameManager =
GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
gameManager.Health -= 1;
//>>
}
}
}
public void JiggleWaypoints()
{
for (int i = 1; i < waypoints.Length; i++)
{
waypoints[i].transform.position = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 3), waypoints[i].transform.position.y + Random.Range(-3, 3), 0);
}
}
private void RotateIntoMoveDirection()
{
//1 It calculates the bug’s current movement direction by subtracting the current waypoint’s position from that of the next waypoint.
Vector3 newStartPosition = waypoints[currentWaypoint].transform.position;
Vector3 newEndPosition = waypoints[currentWaypoint + 1].transform.position;
Vector3 newDirection = (newEndPosition - newStartPosition);
//2 It uses Mathf.Atan2 to determine the angle toward which newDirection points, in radians, assuming zero points to the right.
// Multiplying the result by 180 / Mathf.PI converts the angle to degrees.
float x = newDirection.x;
float y = newDirection.y;
float rotationAngle = Mathf.Atan2(y, x) * 180 / Mathf.PI;
//3 Finally, it retrieves the child named Sprite and rotates it rotationAngle degrees along the z-axis.
// Note that you rotate the child instead of the parent so the health bar — you’ll add it soon — remains horizontal.
GameObject sprite = (GameObject)
gameObject.transform.FindChild("Sprite").gameObject;
sprite.transform.rotation =
Quaternion.AngleAxis(rotationAngle, Vector3.forward);
}
public float distanceToGoal()
{
float distance = 0;
distance += Vector3.Distance(
gameObject.transform.position,
waypoints[currentWaypoint + 1].transform.position);
for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++)
{
Vector3 startPosition = waypoints[i].transform.position;
Vector3 endPosition = waypoints[i + 1].transform.position;
distance += Vector3.Distance(startPosition, endPosition);
}
return distance;
}
}
Code is working 100% without errors, BUT....
After each spawn all objects get the same waypoint array. This can be seen on the screen as all objects jump to new waypoint in line together each time new object is spawned. I want the object which is already spawn to live life with it's own array of only once created waypoints.
You need to create a new array of waypoints each time you create one from the prefabricated object. You don't show your Instantiate method but I'm guessing that it has a line like this:
this.waypoints = prefab.waypoints;
This will mean that all object you create will share the same list of waypoints (as you've discovered).
What you need is something like this - assuming that the waypoints have X, Y, and Z properties):
this.waypoints = new GameObject[5];
for (int i = 0; i++ ; i < 5)
{
this.waypoints[i].X = prefab.waypoints[i].X;
this.waypoints[i].Y = prefab.waypoints[i].Y;
this.waypoints[i].Z = prefab.waypoints[i].Z;
}
(If you want your points to be a variable length you might want to consider using a list).
This means that each object has a list of unique points even if they start with the same values you can change each independently.
Based on ChrisFs' and Joe Blows' answers, do something like this in your MoveEnemy script:
private Vector3[] myWay;
public void JiggleWaypoints(GameObject[] waypoints)
{
myWay = new Vector3[waypoints.Length];
for(int i = 1; i < waypoints.Length; i++)
{
myWay[i] = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 4), waypoints[i].transform.position.y + Random.Range(-3, 4), 0);
}
}
myWay replaces the GameObject[].
In your SpawnEnemy script you do this:
GameObject e = (GameObject)Instantiate(enemyPrefab);
e.GetComponent<MoveEnemy>().JiggleWaypoints(waypoints);

Spawning in Unity: Spheres flying out of range

I am programming a game in Unity. I am trying to spawn a sphere in space everytime the user clicks the interface. I can spawn the spheres, but the spheres are always at coordinates of around (200,200, 0) and (400,400,0), but the spheres should be spawned at where the pointer is on the screen. It's my code below, can someone help? I am writing in C#:
using UnityEngine;
using System.Collections;
public class myscript : MonoBehaviour {
//initialize a circle
public GameObject Node;
public float cooldown = 1;
bool clicker;
float clicktime = 0;
GameObject node; //reference to the prefab
// Use this for initialization
void Start () {
}
//In everyframe you can
void Update () {
clicker = Input.GetMouseButtonDown(0); //obtaining the input
clicktime += Time.deltaTime;
}
//Check whether you can shoot
void FixedUpdate(){
if (clicker == true && clicktime >= cooldown) { //if the clicker is clicked and the previos clicking is done
SpawnCircle(); //spawn a circle
clicktime = 0; //reset timer
}
}
void SpawnCircle(){
//this creates a new game object
x = Input.mousePosition.x
y = Input.mousePosition.
node = GameObject.Instantiate (Node,Input.mousePosition,Quaternion.identity) as GameObject;
//settings that we initalize our object with
//node.transform.position = new Vector3(Input.mousePosition.x, Input.mousePosition.y,0);
}
}
You need to calculate ScreenToWorld Coordinates. With Unity it's easy actually.
https://unity3d.com/learn/tutorials/modules/beginner/physics/raycasting

Categories