I have been using Photon unity networking plugin for multiplayer. in the following code for character instantiation I want to spawn the player who joins to be spawned at a fixed point then random. I am new at this and I tried to edit it by giving fixed gameObject position at a button click event but was unable to do so. Here is the code -
using UnityEngine;
public class CharacterInstantiation : OnJoinedInstantiate {
public delegate void OnCharacterInstantiated(GameObject character);
public static event OnCharacterInstantiated CharacterInstantiated;
public new void OnJoinedRoom() {
if (this.PrefabsToInstantiate != null) {
GameObject o = PrefabsToInstantiate[(PhotonNetwork.player.ID - 1) % 4];
//Debug.Log("Instantiating: " + o.name);
Vector3 spawnPos = Vector3.zero;
if (this.SpawnPosition != null) {
spawnPos = this.SpawnPosition.position;
}
Vector3 random = Random.insideUnitSphere;
random = this.PositionOffset * random.normalized;
spawnPos += random;
spawnPos.y = 0;
Camera.main.transform.position += spawnPos;
o = PhotonNetwork.Instantiate(o.name, spawnPos, Quaternion.identity, 0);
if (CharacterInstantiated != null) {
CharacterInstantiated(o);
}
}
}
}
this code is in the test scene with the plugin. Just want to spawn the joining players are fixed point like spawnpoint[0], spawnpoint[1] and so on. Thanks in advance for the help.
and here is the code for prefab instantiate in the plugin-
public class OnJoinedInstantiate : MonoBehaviour
{
public Transform SpawnPosition;
public float PositionOffset = 2.0f;
public GameObject[] PrefabsToInstantiate;
public void OnJoinedRoom()
{
if (this.PrefabsToInstantiate != null)
{
foreach (GameObject o in this.PrefabsToInstantiate)
{
Debug.Log("Instantiating: " + o.name);
Vector3 spawnPos = Vector3.up;
if (this.SpawnPosition != null)
{
spawnPos = this.SpawnPosition.position;
}
Vector3 random = Random.insideUnitSphere;
random.y = 0;
random = random.normalized;
Vector3 itempos = spawnPos + this.PositionOffset * random;
PhotonNetwork.Instantiate(o.name, itempos, Quaternion.identity, 0);
}
}
}
}
If you want to make different spawn points you should change your script to:
using UnityEngine;
public class CharacterInstantiation : OnJoinedInstantiate {
public delegate void OnCharacterInstantiated(GameObject character);
public static event OnCharacterInstantiated CharacterInstantiated;
public int counter = 0;
public Vector3[] spawnPositions;
public new void OnJoinedRoom() {
if (this.PrefabsToInstantiate != null) {
GameObject o = PrefabsToInstantiate[(PhotonNetwork.player.ID - 1) % 4];
//Debug.Log("Instantiating: " + o.name);
Vector3 spawnPos = Vector3.zero;
if (this.SpawnPosition != null) {
spawnPos = spawnPositions[counter];
}
Vector3 random = Random.insideUnitSphere;
random = this.PositionOffset * random.normalized;
spawnPos += random;
spawnPos.y = 0;
Camera.main.transform.position += spawnPos;
o = PhotonNetwork.Instantiate(o.name, spawnPos, Quaternion.identity, 0);
if (CharacterInstantiated != null) {
CharacterInstantiated(o);
counter++;
}
}
}
}
You just need to give values for spawnPositions.
Related
First I find the objects that interest me using GameObject.FindGameObjectsWithTag. And I bring them into one array All[ ] . I create NavMeshAgent>. I drive the agent to selected points on the map. Until he meets someone from the All[ ] array. And it would seem that everything works, but BUT. The agent only triggers on the last object in the array. I sat for 2 days, tried many ways, the result is the same, it can run the array not through ( foreach or for ) . Maybe there is a complex solution to the problem. Or even another way, I'm in the programming of bread, but I try my best. Any idea is accepted and tested. Thanks!!!
public void getTarget(GameObject[] targets) runs through array objects - this is where the problem lies
public GameObject[] Concat(GameObject[] first, GameObject[] second, GameObject[] third) concatenates arrays of objects
public void moveToTarget(Vector3 target) points to the target for the
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class MinionMoveByLine : MonoBehaviour
{
public enum MovementType
{
Moveing,
Learp
}
//Переменные для перемещения по карте
public MovementType type = MovementType.Moveing;
public NavMeshLineToMove MyLine;
public float speed = 1;
public float maxDistance = .3f;
private NavMeshAgent enemy;
//Переменные для растояний и приоритета крипов
private GameObject[] minions;
private GameObject[] towers;
private GameObject[] players;
private GameObject[] All;
public GameObject minion;
private Vector3[] position;
private Vector3 targetPosition;
private float distanceVisionForAttack = 6f;
private float radiusOfAttack = 2f;
private IEnumerator<Transform> pointInPath;
// Start is called before the first frame update
void Start()
{
minions = GameObject.FindGameObjectsWithTag("minion");
towers = GameObject.FindGameObjectsWithTag("tower");
players = GameObject.FindGameObjectsWithTag("player");
All = Concat(players, towers, minions);
Debug.Log("minions "+ minions.Length);
Debug.Log("towers " + towers.Length);
Debug.Log("players " + players.Length);
minion = (GameObject)this.gameObject;
enemy = GetComponent<NavMeshAgent>();
if (MyLine == null)
{
Debug.Log("Line Not Set");
return;
}
pointInPath = MyLine.GetNextPathPoint();
pointInPath.MoveNext();
if (pointInPath.Current == null)
{
Debug.Log("Need point to move");
return;
}
transform.position = pointInPath.Current.position;
}
void LateUpdate()
{
Vector3 position = minion.transform.position;
if (pointInPath == null || pointInPath.Current == null)
{
return;
}
foreach(var obj in All)
{
Debug.Log(All.Length);
Debug.Log(obj);
}
getTarget(All);
var distanceSqure = (transform.position - pointInPath.Current.position).sqrMagnitude;
if (distanceSqure < maxDistance * maxDistance)
{
pointInPath.MoveNext();
}
}
public GameObject[] Concat(GameObject[] first, GameObject[] second, GameObject[] third)
{
GameObject[] Concated = new GameObject[first.Length+second.Length+third.Length];
for (int i = 0; i < first.Length; i++)
{
Concated[i] = first[i];
}
for (int i = 0; i < second.Length; i++)
{
Concated[first.Length + i] = second[i];
}
for (int i = 0; i < third.Length; i++)
{
Concated[first.Length + second.Length + i] = third[i];
}
return Concated;
}
public void getTarget(GameObject[] targets)
{
Vector3 minionPosition = this.transform.position;
foreach (GameObject go in targets)
{
Transform transform = go.GetComponent<Transform>();
Vector3 transformPosition = transform.position;
float distanceToTarget = Vector3.Distance(transformPosition, minionPosition);
if (distanceToTarget <= distanceVisionForAttack && distanceToTarget > radiusOfAttack)
{
moveToTarget(transformPosition);
}else if(distanceToTarget <= radiusOfAttack)
{
moveToTarget(minion.transform.position);
}
else if(type == MovementType.Moveing && distanceToTarget > distanceVisionForAttack)
{
enemy.SetDestination(pointInPath.Current.position);
}
}
var distanceSqure = (transform.position - pointInPath.Current.position).sqrMagnitude;
if (distanceSqure < maxDistance * maxDistance)
{
pointInPath.MoveNext();
}
}
public void moveToTarget(Vector3 target)
{
enemy.SetDestination(target);
}
}
result of starting scene
What is happening in redactor - YouTube
I leave for those who in the future will face the same stupidity as me, change
getTarget ( );
new variables added
GameObject currentTarget;
float dist = Mathf.Infinity;
and cycle
foreach(GameObject go in targets)
{
Vector3 targetPosition = go.transform.position;
float distanceToTarget = Vector3.Distance(targetPosition,
minionPosition);
if (distanceToTarget < dist)
{
dist = distanceToTarget;
currentTarget = go;
}
}
Special thanks to BugFinder
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class MinionMoveByLine : MonoBehaviour
{
public enum MovementType
{
Moveing,
Learp
}
//Переменные для перемещения по карте
public MovementType type = MovementType.Moveing;
public NavMeshLineToMove MyLine;
public float speed = 1;
public float maxDistance = .3f;
private NavMeshAgent enemy;
//Переменные для растояний и приоритета крипов
private GameObject[] minions;
private GameObject[] towers;
private GameObject[] players;
private GameObject[] All;
public GameObject minion;
private Vector3[] position;
private Vector3 targetPosition;
private float distanceVisionForAttack = 6f;
private float radiusOfAttack = 2f;
GameObject currentTarget;
float dist = Mathf.Infinity;
private IEnumerator<Transform> pointInPath;
// Start is called before the first frame update
void Start()
{
minions = GameObject.FindGameObjectsWithTag("minion");
towers = GameObject.FindGameObjectsWithTag("tower");
players = GameObject.FindGameObjectsWithTag("player");
All = Concat(players, towers, minions);
Debug.Log("minions "+ minions.Length);
Debug.Log("towers " + towers.Length);
Debug.Log("players " + players.Length);
//currentTarget = All[0];
minion = (GameObject)this.gameObject;
enemy = GetComponent<NavMeshAgent>();
if (MyLine == null)
{
Debug.Log("Line Not Set");
return;
}
pointInPath = MyLine.GetNextPathPoint();
pointInPath.MoveNext();
if (pointInPath.Current == null)
{
Debug.Log("Need point to move");
return;
}
transform.position = pointInPath.Current.position;
}
void LateUpdate()
{
Vector3 position = minion.transform.position;
if (pointInPath == null || pointInPath.Current == null)
{
return;
}
foreach(var obj in All)
{
Debug.Log(All.Length);
Debug.Log(obj);
}
getTarget(All);
var distanceSqure = (transform.position - pointInPath.Current.position).sqrMagnitude;
if (distanceSqure < maxDistance * maxDistance)
{
pointInPath.MoveNext();
}
}
public GameObject[] Concat(GameObject[] first, GameObject[] second, GameObject[] third)
{
GameObject[] Concated = new GameObject[first.Length+second.Length+third.Length];
for (int i = 0; i < first.Length; i++)
{
Concated[i] = first[i];
}
for (int i = 0; i < second.Length; i++)
{
Concated[first.Length + i] = second[i];
}
for (int i = 0; i < third.Length; i++)
{
Concated[first.Length + second.Length + i] = third[i];
}
return Concated;
}
public void getTarget(GameObject[] targets)
{
Vector3 minionPosition = this.transform.position;
foreach (GameObject go in targets)
{
Vector3 targetPosition = go.transform.position;
float distanceToTarget = Vector3.Distance(targetPosition, minionPosition);
if (distanceToTarget < dist)
{
dist = distanceToTarget;
currentTarget = go;
}
}
float distanceToCurrentTarget = Vector3.Distance(currentTarget.transform.position, minionPosition);
if (distanceToCurrentTarget <= distanceVisionForAttack && distanceToCurrentTarget > radiusOfAttack)
{
moveToTarget(currentTarget);
}
else if (distanceToCurrentTarget <= radiusOfAttack)
{
moveToTarget(minion);
}
else if (type == MovementType.Moveing && distanceToCurrentTarget > distanceVisionForAttack)
{
dist = Mathf.Infinity;
enemy.SetDestination(pointInPath.Current.position);
}
var distanceSqure = (transform.position - pointInPath.Current.position).sqrMagnitude;
if (distanceSqure < maxDistance * maxDistance)
{
pointInPath.MoveNext();
}
}
public void moveToTarget(GameObject target)
{
enemy.SetDestination(target.transform.position);
}
}
I've tried a lot of different things. Assigning the array elements just in the editor. Assigning the elements on boot using the Await(). Changing what script calls the functions. What GameObject has the attached script. How the Vector2 is called. How the array is initialized. I can't figure out what I'm missing.
GameRules Script
using System.Collections.Generic;
using UnityEngine;
public class GameRules : MonoBehaviour
{
public GameObject[] rightSwitchSpawns = new GameObject[7];
public GameObject[] leftSwitchSpawns = new GameObject[7];
public GameObject rightSwitchPrefab;
public GameObject leftSwitchPrefab;
void Awake(){
rightSwitchSpawns = GameObject.FindGameObjectsWithTag("RightSpawns");
leftSwitchSpawns = GameObject.FindGameObjectsWithTag("LeftSpawns");
}
// Start is called before the first frame update
void Start()
{
RandomLeft();
RandomRight();
}
public void RandomLeft()
{ Debug.Log("This Left array length is " + leftSwitchSpawns.Length);
int leftRandom1 = Random.Range(0, leftSwitchSpawns.Length -1);
Debug.Log("left 1 index is " + leftRandom1);
Vector2 leftOne = new Vector2(leftSwitchSpawns[leftRandom1].transform.position.x,leftSwitchSpawns[leftRandom1].transform.position.y);
leftSwitchPrefab = Instantiate(leftSwitchPrefab, new Vector2(leftOne.x,leftOne.y), Quaternion.identity);
int leftRandom2 = Random.Range(0, leftSwitchSpawns.Length -1);
while(leftRandom2 == leftRandom1)
{
leftRandom2 = Random.Range(0, leftSwitchSpawns.Length -1);
}
Vector2 leftTwo = new Vector2(leftSwitchSpawns[leftRandom2].transform.position.x,leftSwitchSpawns[leftRandom2].transform.position.y);
leftSwitchPrefab = Instantiate(leftSwitchPrefab, new Vector2(leftTwo.x,leftTwo.y), Quaternion.identity);
Debug.Log("Left 2 index is: " + leftRandom2);
int leftRandom3 = Random.Range(0, leftSwitchSpawns.Length -1);
while(leftRandom3 == leftRandom1 || leftRandom3 == leftRandom2)
{
leftRandom3 = Random.Range(0, leftSwitchSpawns.Length -1);
}
Vector2 leftThree = new Vector2(leftSwitchSpawns[leftRandom3].transform.position.x,leftSwitchSpawns[leftRandom3].transform.position.y);
leftSwitchPrefab = Instantiate(leftSwitchPrefab, new Vector2(leftThree.x,leftThree.y), Quaternion.identity);
Debug.Log("Left 3 index is: " + leftRandom3);
}
public void RandomRight()
{
int rightRandom1 = Random.Range(0, rightSwitchSpawns.Length -1);
Debug.Log("This Right array length is " + rightSwitchSpawns.Length);
Vector2 rightOne = rightSwitchSpawns[rightRandom1].transform.position;
rightSwitchPrefab = Instantiate(rightSwitchPrefab, new Vector2(rightOne.x,rightOne.y), Quaternion.identity);
Debug.Log("Right 1 index is: " + rightRandom1);
int rightRandom2 = Random.Range(0, rightSwitchSpawns.Length -1);
while (rightRandom2 == rightRandom1)
{
rightRandom2 = Random.Range(0, rightSwitchSpawns.Length -1);
}
Vector2 rightTwo = rightSwitchSpawns[rightRandom2].transform.position;
rightSwitchPrefab = Instantiate(rightSwitchPrefab, new Vector2(rightTwo.x,rightTwo.y), Quaternion.identity);
Debug.Log("Right 2 index is: " + rightRandom2);
int rightRandom3 = Random.Range(0, rightSwitchSpawns.Length -1);
while (rightRandom3 == rightRandom1 || rightRandom3 == rightRandom2)
{
rightRandom3 = Random.Range(0, rightSwitchSpawns.Length -1);
}
Vector2 rightThree = rightSwitchSpawns[rightRandom3].transform.position;
rightSwitchPrefab = Instantiate(rightSwitchPrefab, new Vector2(rightThree.x,rightThree.y), Quaternion.identity);
Debug.Log("Right 3 index is: " + rightRandom3);
}
public void DestroyRightSwitches(){
Debug.Log("Right Switches Destroyed");
Destroy(rightSwitchPrefab);
}
public void DestroyLeftSwitches(){
Debug.Log("Left Switches Destroyed");
Destroy(leftSwitchPrefab);
}
}
PlayerMovement Script
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : GameRules
{
private float speed = 5f;
private float jump = 5f;
private Rigidbody2D rb;
private bool isPlaying = false;
private Transform trans;
// Start is called before the first frame update
void Awake()
{
trans = gameObject.GetComponent<Transform>();
rb = gameObject.GetComponent<Rigidbody2D>();
rb.simulated = false;
}
// Update is called once per frame
void Update()
{
if(Input.GetMouseButtonDown(0)){
if(isPlaying == false){
isPlaying = true;
rb.simulated = true;
rb.velocity = new Vector2(speed,0f);
}
else{
rb.velocity = new Vector2(speed,jump);
}
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Wall")
{
OnDeath();
}
if(collision.gameObject.tag == "RightSwitch"){
speed = -speed;
rb.velocity = new Vector2(speed,0f);
DestroyRightSwitches();
RandomRight();
}
if(collision.gameObject.tag == "LeftSwitch"){
speed = -speed;
rb.velocity = new Vector2(speed,0f);
DestroyLeftSwitches();
RandomLeft();
}
}
void OnDeath(){
isPlaying = false;
rb.simulated = false;
trans.position = new Vector2(0,0);
DestroyLeftSwitches();
DestroyRightSwitches();
RandomLeft();
RandomRight();
}
}
The specific error is
IndexOutOfRangeException: Index was outside the bounds of the array.
GameRules.RandomLeft () (at Assets/Scripts/GameRules.cs:28)
GameRules.Start () (at Assets/Scripts/GameRules.cs:20)
But if you look at the debug statements. At initial runtime the array is full with a length of 7, Gives you the indexes of each point. and then it runs again for some reason with a length and index of 0. Then the error shows up.
The errors I Get in picture form
Your arrays are declared as public. In Unity3d's MonoBehaviour it means that these fields are serialized. If you have this script attached to the game object on the scene or to some prefab that is instantiated after, serialized values will be taken from this game object (you can see it in the inspector). It means that if there will be empty arrays in the serialized object, the length of your arrays will be 0 at runtime.
The issue is that I have the Playermovement script deriving from my GameRules script so in the hierarchy the player movement script also has empty arrays attached to the game object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCameraBehind : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public bool behindMultipleTargets = false;
public string cameraWarningMsgs = "";
public string targetsWarningMsgs = "";
// Use this for initialization
void Start()
{
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
cameraWarningMsgs = "Gettig camera component.";
camera = transform.gameObject;
}
else
{
cameraWarningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
if(targets.Count == 0)
{
targetsWarningMsgs = "No targets found.";
}
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
}
}
public void MoveCameraToPosition()
{
if (targets.Count > 1 && behindMultipleTargets == true)
{
var center = CalculateCenter();
transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
}
if (behindMultipleTargets == false)
{
Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
transform.position = new Vector3(center.x, center.y + 2, center.z);
}
}
private Vector3 CalculateCenter()
{
Vector3 center = new Vector3();
var totalX = 0f;
var totalY = 0f;
foreach (var target in targets)
{
totalX += target.transform.position.x;
totalY += target.transform.position.y;
}
var centerX = totalX / targets.Count;
var centerY = totalY / targets.Count;
center = new Vector3(centerX, centerY);
return center;
}
}
The CalculateCenter function make the targets(objects) to change positions and vanish away far away. Even if there is only one single target.
What I want to do is if there is one object for example one 3d cube position the camera behind the cube. And if there are more cubes for example two or ten and the camera is somewhere else calculate the middle position behind the targets and position the camera in the middle behind them.
To show what I mean in this example the view(like a camera) is behind the two soldiers in the middle position between them from behind.
But what if there are 5 soldiers how can I find the middle position and then position the camera behind them like this example in the screenshot ?
This is my old script version was working fine but only for 1 or 2 targets. But if there are 5 targets(soldiers) how can I position the camera behind them in the middle ? Like in the screenshot example.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCameraBehind : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public bool behindTwoTargets = false;
public string warningMsgs = "";
// Use this for initialization
void Start()
{
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
warningMsgs = "Gettig Camera omponent.";
camera = transform.gameObject;
}
else
{
warningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
camera.transform.Rotate(0, 180, 0);
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
}
}
public void MoveCameraToPosition()
{
if (targets.Count == 2 && behindTwoTargets == true)
{
Vector3 center = ((targets[0].transform.position - targets[1].transform.position) / 2.0f) + targets[1].transform.position;
camera.transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
}
if (behindTwoTargets == false)
{
Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
camera.transform.position = new Vector3(center.x, center.y + 2, center.z);
}
}
}
This is my last version of my working code still using the CalculateCenter function :
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraLook : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public float cameraHeight = 2f;
public float rotateTime = 2f;
public bool multipleTargets = false;
public bool changeRandomTarget = false;
public bool behindFront = false;
public bool targetsRandomRot = false;
public string cameraWarningMsgs = "";
public string targetsWarningMsgs = "";
private List<Vector3> vectors = new List<Vector3>();
//Random move rotation timer part
Quaternion qTo;
float speed = 3f;
float timer = 0.0f;
// Use this for initialization
void Start()
{
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
cameraWarningMsgs = "Gettig camera component.";
camera = transform.gameObject;
}
else
{
cameraWarningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
if (targets.Count == 0)
{
targetsWarningMsgs = "No targets found.";
}
else
{
foreach(GameObject vector in targets)
{
vectors.Add(vector.transform.position);
}
}
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
if (targetsRandomRot == true)
{
RotateTargetsRandom();
}
}
}
public void MoveCameraToPosition()
{
Vector3 center = CalculateCenter();
camera.transform.position = center;
if (behindFront == false)
{
camera.transform.rotation = Quaternion.LookRotation(-center, Vector3.up);
}
else
{
camera.transform.rotation = Quaternion.LookRotation(center, Vector3.up);
}
}
private Vector3 CalculateCenter()
{
Vector3 center = new Vector3();
var x = targets[0].transform.position.x;
var y = targets[0].transform.position.y;
var z = targets[0].transform.position.z;
if (multipleTargets == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
else
{
x += targets[0].transform.position.x;
y += targets[0].transform.position.y;
z += targets[0].transform.position.z;
}
if(changeRandomTarget == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
x = x / targets.Count;
y = y / targets.Count;
z = z / targets.Count;
if (behindFront == false)
{
center = new Vector3(x, y + cameraHeight, z + cameraDistance);
}
else
{
center = new Vector3(x, y + cameraHeight, z - cameraDistance);
}
return center;
}
private void RotateTargetsRandom()
{
timer += Time.deltaTime;
if (timer > rotateTime)
{ // timer resets at 2, allowing .5 s to do the rotating
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));
timer = 0.0f;
}
foreach (var target in targets)
{
target.transform.rotation = Quaternion.Slerp(target.transform.rotation, qTo, Time.deltaTime * speed);
}
}
}
And now I want to add and use the bool flag changeRandomTarget :
But not sure how to do it :
if(changeRandomTarget == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
I want that each X seconds it will pick a random center and change the camera position according to it. For example the first item in the targets List the last item and all the items so each X seconds the center will be once behind targets[0] or targets1 or targets[i]
Not sure how to do it with my code or with derHugo solution.
Surely you just find the average
so
if (mobcount > 1)
{
var x=mob[0].position.x;
var y=mob[0].position.y;
var z=mob[0].position.z;
for(int i=1; i<mobcount; i++)
{
x += mob[i].position.x;
y += mob[i].position.y;
z += mob[i].position.z;
}
x = x / mobcount;
y = y / mobcount;
z = z / mobcount;
}
therefore the camera should look at the position x,y,z.. and perhaps set the distance to be a fixed distance behind the nearest mob...
Actually you don't even need to do it component wise:
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
...
private static Vector3 Average(IReadOnlyCollection<Vector3> vectors)
{
if(vectors == null) return Vector3.zero;
switch (vectors.Count)
{
case 0:
return Vector3.zero;
case 1:
return vectors.First();
default:
var average = Vector3.zero;
foreach(var vector in vectors)
{
average += vector;
}
return average / vectors.Count;
}
}
Or directly using Linq aggregate
private static Vector3 Average(IReadOnlyCollection<Vector3> vectors)
{
if(vectors == null) return Vector3.zero;
switch (vectors.Count)
{
case 0:
return Vector3.zero;
case 1:
return vectors.First();
default:
var average = vectors.Aggregate(Vector3.zero, (current, vector) => current + vector);
return average / vectors.Count;
}
}
I am writing a C# script on Unity 3D.
I'm working on pathfinding now.
The path has been found correctly in the Array List and the Object can move according to the path with a constant speed.
Then, I want to improvise, where when the path found is a straight line, the object will increase its speed. Meanwhile, when the path turns the object will reduce its speed again.
Here, I don't know how to group between straight and turning paths in an arrayList.
Thankyou for helping me :)
This is the code :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
public abstract class Unit : MonoBehaviour
{
#region public variables
public GameObject Astar;
public bool drawGizmos = false;
protected float gravity = 9.8f;
public Transform target;
public Transform NPC;
public Vector3 lastTargetPosition;
public float movementSpeed;
public float rotationSpeed = 85;
protected float distanceToPath = 1;
public Vector2 currentPosition = new Vector2(0, 0);
protected int spacesMoved = 0;
// Default action times to 5 second interval
protected float period = 1f;
protected float nextActionTime = 1f;
protected bool isSafeToUpdatePath = false;
protected int pathFoundCount = 0;
protected bool isMoving = false;
protected bool isTargetReached = false;
#endregion
#region member variables
public Vector3[] m_path;
protected int m_targetIndex;
protected CharacterController m_characterController;
private Node lastNodePosition;
private List<Node> lastPositionNeighbors;
private Vector3 m_lastKnownPosition;
private Quaternion m_lookAtRotation;
private GridSystem m_grid;
private Coroutine lastRoutine = null;
private bool preventExtraNodeUpdate = false;
public Stopwatch timer;
#endregion
public virtual void Awake()
{
timer = new Stopwatch();
if (Astar != null)
m_grid = Astar.GetComponent<GridSystem>();
}
public virtual void Start()
{
m_characterController = GetComponent<CharacterController>();
timer.Reset();
timer.Start();
PathRequestManager.RequestPath(transform.position, target.position, OnPathFound);
lastTargetPosition = target.position;
UnityEngine.Debug.Log("NPC Position : " + transform.position);
UnityEngine.Debug.Log("Target Position : " + target.position);
}
public virtual void Update()
{
if (Time.time > nextActionTime) //update path setiap 1f
{
nextActionTime += period;
isSafeToUpdatePath = true;
}
else
{
isSafeToUpdatePath = false;
}
//If we don't check !isMoving the AI may get stuck waiting to update the grid for nextActionTime.
if (target.position != lastTargetPosition)
{
isMoving = true;
UpdateNodePosition();
UpdatePath();
UpdateRotation();
}
lastTargetPosition = target.position;
}
public void UpdatePath()
{
lastNodePosition.walkable = Walkable.Passable;
PathRequestManager.RequestPath(transform.position, target.position, OnPathFound);
}
public virtual void OnPathFound(Vector3[] newPath, bool pathSuccessful)
{
if (pathSuccessful)
{
pathFoundCount++;
m_path = newPath;
m_targetIndex = 0;
// Stop coroutine if it is already running.
if (lastRoutine != null)
StopCoroutine(lastRoutine);
lastRoutine = StartCoroutine(FollowPath());
}
}
public float time;
public virtual IEnumerator FollowPath()
{
Vector3 currentPath = m_path[0];
while (true)
{
if (Vector3.Distance(transform.position, currentPath) < distanceToPath)
{
m_targetIndex++;
// If we are done with path.
if (m_targetIndex >= m_path.Length)
{
timer.Stop();
UnityEngine.Debug.Log("Time Move : " + timer.ElapsedMilliseconds);
isMoving = false;
yield break;
}
currentPath = m_path[m_targetIndex];
}
float Distance = Vector3.Distance(NPC.transform.position, target.transform.position);
UnityEngine.Debug.Log("Distance : " + Distance);
// Occurs each frame
//move follow path
UpdatePosition(currentPath);
yield return null;
}
}
public virtual void UpdatePosition(Vector3 destination)
{
Node node = m_grid.NodeFromWorldPoint(transform.position);
Vector3 direction = destination - transform.position;
movementSpeed = 1;
transform.Translate(direction.normalized * movementSpeed * Time.deltaTime, Space.World);
UnityEngine.Debug.Log("Speed NPC : " + movementSpeed);
}
public virtual void UpdateRotation()
{
m_lastKnownPosition = target.transform.position;
m_lookAtRotation = Quaternion.LookRotation(m_lastKnownPosition - transform.position);
if (transform.rotation != m_lookAtRotation)
transform.rotation = Quaternion.RotateTowards(transform.rotation, m_lookAtRotation, rotationSpeed * Time.deltaTime);
}
public void UpdateNodePosition()
{
Node node = m_grid.NodeFromWorldPoint(transform.position);
if (isMoving == false)
{
lastPositionNeighbors = m_grid.GetNeighbours(node);
foreach (Node n in lastPositionNeighbors)
{
if (n.walkable != Walkable.Impassable)
n.walkable = Walkable.Blocked;
}
node.walkable = Walkable.Blocked;
lastNodePosition = node;
currentPosition = new Vector2(node.gridX, node.gridY);
return;
}
if (lastNodePosition != null && isMoving)
{
preventExtraNodeUpdate = false;
lastPositionNeighbors = m_grid.GetNeighbours(node);
lastNodePosition.walkable = Walkable.Passable;
if (lastPositionNeighbors != null)
foreach (Node n in lastPositionNeighbors)
{
if (n.walkable != Walkable.Impassable)
n.walkable = Walkable.Passable;
}
if (!node.Equals(lastNodePosition))
spacesMoved++;
}
else
{
node.walkable = Walkable.Blocked;
lastNodePosition = node;
currentPosition = new Vector2(node.gridX, node.gridY);
}
}
public void OnDrawGizmos()
{
if (!drawGizmos)
return;
if (m_path != null)
{
for (int i = m_targetIndex; i < m_path.Length; i++)
{
Gizmos.color = Color.black;
Gizmos.DrawCube(m_path[i], Vector3.one);
}
}
}
}
This screenshot after running
Okay. It looks to me like all that you have to do in order to determine if you are on a curved path is to check if the next step you are going to take is directly in front of the player. You can do this in your UpdatePosition function. Just check if the direction you are about to move in has the same x or z position. Assuming that y is up and all points on your grid have the same y position. In the case that you are moving horizontally, x will stay the same, and in the case that you are moving vertically, z will stay the same. Or vice versa.
public virtual void UpdatePosition(Vector3 destination)
{
Node node = m_grid.NodeFromWorldPoint(transform.position);
Vector3 direction = destination - transform.position;
if(destination.x == transform.position.x || destination.z == transform.position.z)
{
//Direction is staying the same
movementSpeed = 1f;
}else{
movementSpeed = 0.5f;
}
transform.Translate(direction.normalized * movementSpeed * Time.deltaTime, Space.World);
UnityEngine.Debug.Log("Speed NPC : " + movementSpeed);
}
You should be able to customize the movement speed however you want from there. IF you're having issues still after this, try printing out the (x,y,z) components of the destination and the transform and see where they are similar when the path is straight and what changes when the path is curved. The code above assumes the y never changes.
I'm creating a 2d runner and i have this "collision.cs" file that I have my heart system in, I don't get any errors but when I die a heart doesn't get removed so what am I doing wrong?
The system is based on tags so I tried changing the tag system a lot but nothing worked; then I tried to change the way I find the gameobject after a while I saw that it was creating a lot off gameobjects instead of 3 so I tried to change the tag system around that but even that didn't work and I really don't want to have a plain text that says 3 lives etc.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class Collision : MonoBehaviour {
public int lifes = 3 ;
//public GameObject Life_icon1;
//public GameObject Life_icon2;
//public GameObject Life_icon3;
public Sprite Heart;
public int current_icon = 3;
public GameObject ParentPanel;
public static int Coins = 0;
public float offset = 150f;
List<int> i = new List<int>() { 1 };
public int tagN;
void Update() {
tagN = i.Max() + 1;
}
// Use this for initialization
void Start () {
for(int x = 0; x < lifes; x++)
{
i.Add(x);
GameObject NewObj = new GameObject(); //Create the GameObject
Image NewImage = NewObj.AddComponent<Image>(); //Add the Image Component script
NewImage.gameObject.tag = x.ToString();
if(x == 0) {
NewImage.transform.position = new Vector3(0 + 40f, 0 + 40f , 0);
} else {
NewImage.transform.position = new Vector3(0 + offset, 0 + 40f , 0);
offset += 130f;
}
//print(x);
NewImage.sprite = Heart; //Set the Sprite of the Image Component on the new GameObject
NewObj.GetComponent<RectTransform>().SetParent(ParentPanel.transform); //Assign the newly created Image GameObject as a Child of the Parent Panel.
NewObj.SetActive(true); //Activate the GameObject
}
}
void AddLife(int amount) {
lifes++;
i.Add(amount);
GameObject NewObj = new GameObject(); //Create the GameObject
NewObj.gameObject.tag = tagN.ToString();
Image NewImage = NewObj.AddComponent<Image>(); //Add the Image Component script
NewImage.transform.position = new Vector3(0 + offset, 0 + 40f , 0);
NewImage.sprite = Heart; //Set the Sprite of the Image Component on the new GameObject
NewObj.GetComponent<RectTransform>().SetParent(ParentPanel.transform); //Assign the newly created Image GameObject as a Child of the Parent Panel.
NewObj.SetActive(true); //Activate the GameObject
}
void DelLife(int amount) {
Vector3 pos = transform.position;
offset -= 130f;
pos.x = -0.49f;
pos.y = -0.49f;
transform.position = pos;
i.RemoveAt(i.Max());
GameObject go = null;
if (GameObject.FindWithTag(tagN.ToString()) != null)
{
go = GameObject.FindWithTag(tagN.ToString());
}
if (go != null)
{
go.gameObject.SetActive(false);
}
}
void OnTriggerEnter2D(Collider2D other)
{
//extra life item collision
if(other.gameObject.name == "Heart_item") {
AddLife(1);
Destroy(other.gameObject);
}
if(other.gameObject.name == "Spike") {
DelLife(1);
}
if(other.gameObject.name == "Coin") {
Destroy(other.gameObject);
Coins += 1;
}
}
}