Unity 3D 2019: x Position keeps shifting - c#

I have made a grid spawner for obstacles on a grid of x -6 to x 6. The objects move -z axis toward the player.
They do not move along the x axis only z. For some reason despite having coded a spawner that places an object every 2 x values it places them at a fraction off each. And gets less each row. So an object placed at x2 the next row at x2 will be at x1.999987 and then x1.998 and so on.
The x value of each object should only be one of following (-6, -4, -2, 0, 2, 4, 6)
This is causing me an issue because I need to also be able to select two objects and swap them. This requires my script to scan the board for active objects and find x valuesof the objects and swap over. If the x values are not solid whole numbers it wont detect any other objects.
Thank you in advance for any advice :)
Spawn code:
void SpawnGrid()
{
for (int x = 0; x < gridX; x++)
{
for (int z = 0; z < gridZ; z++)
{
float x1 = Mathf.Round(x * gridSpacingOffset);
float z1 = Mathf.Round(z * gridSpacingOffset);
Debug.Log("x1: " + x1);
Debug.Log("x2: " + z1);
Vector3 spawnPosition = new Vector3(x1, 0, z1) + gridOrigin;
PickAndSpawn(spawnPosition, Quaternion.identity);
}
}
}
void PickAndSpawn(Vector3 positionToSpawn, Quaternion rotationToSpawn)
{
// Pick a "random" number between 0 and the length of the obstacle array
int randomIndex = Random.Range(0, itemsToPickFrom.Length);
Debug.Log("RandomIndex is: " + randomIndex);
// Declare obstacle types
obj = ObjectPooler.SharedInstance.GetPooledObject("Obstacle_Type_1");
obj1 = ObjectPooler.SharedInstance.GetPooledObject("Obstacle_Type_2");
obj2 = ObjectPooler.SharedInstance.GetPooledObject("Obstacle_Type_3");
obj3 = ObjectPooler.SharedInstance.GetPooledObject("Obstacle_Type_4");
// Add obstacles to an array
objectTypes[0] = obj;
objectTypes[1] = obj1;
objectTypes[2] = obj2;
objectTypes[3] = obj3;
// Spawn the obstacle chosen by the random index number
if (objectTypes[randomIndex] == null)
return;
objectTypes[randomIndex].transform.position = positionToSpawn;
objectTypes[randomIndex].transform.rotation = rotationToSpawn;
ontheBoard.Add(objectTypes[randomIndex]);
objectTypes[randomIndex].SetActive(true);
}
Object movement code:
void Start()
{
currentPos = transform.position;
}
void Update()
{
destinationPos = currentPos;
destinationPos.z = destinationPos.z - moveStep;
currentPos = transform.position;
}
void FixedUpdate()
{
transform.position = Vector3.MoveTowards(transform.position, destinationPos, moveSpeed * Time.fixedDeltaTime);
}
Swap Code:
private void swapIt(Vector3 pos1, Vector3 pos2)
{
if (swap != true)
{
startPos = pos1;
endPos = pos2;
archMidPos = startPos + (endPos - startPos) / 2 + Vector3.up * archHeight;
swap = true;
}
}
void Update()
{
moveSpeed = obj1.GetComponent<Cube_Control>().moveSpeed;
moveStep = obj1.GetComponent<Cube_Control>().moveStep;
destinationPosObj1 = currentPosObj1;
destinationPosObj1.z = destinationPosObj1.z - moveStep;
currentPosObj1 = obj1.transform.position;
destinationPosObj2 = currentPosObj2;
destinationPosObj2.z = destinationPosObj2.z - moveStep;
currentPosObj2 = obj2.transform.position;
// For testing press SPACEBAR to swap objects
if (Input.GetKeyDown(KeyCode.Space))
{
/*
int randomIndex = Random.Range(0, lvlManager.GetComponent<Grid_Spawn>().ontheBoard.Count);
obj1 = lvlManager.GetComponent<Grid_Spawn>().ontheBoard[randomIndex];
foreach (GameObject ob in lvlManager.GetComponent<Grid_Spawn>().ontheBoard)
{
if (ob.transform.position.x == (obj1.transform.position.x + 4))
{
obj2 = ob;
swapIt(obj1.transform.position, obj2.transform.position);
}
else { Debug.Log("No object nearby to swap"); }
}*/
swapIt(obj1.transform.position, obj2.transform.position);
}
}
private void FixedUpdate()
{
//loat cnt = gs.ontheBoard.Count;
//Debug.Log("ontheboard count: " + cnt);
if (swap == true)
{
if (count < 1.0f)
{
count += 1.0f * Time.fixedDeltaTime;
// Lerp the primary object to the new position in an arching motion
Vector3 archMidPosObj1 = archMidPos;
Vector3 endPosObj1 = endPos;
archMidPosObj1.z = archMidPosObj1.z - moveStep;
endPosObj1.z = endPosObj1.z - moveStep;
Vector3 m1 = Vector3.Lerp(startPos, archMidPosObj1, count);
Vector3 m2 = Vector3.Lerp(archMidPosObj1, endPosObj1, count);
// Move Object 1
obj1.transform.position = Vector3.Lerp(m1, m2, count);
// Calculate the inverse arch (-Y) and Lerp the secondary object in a negative arching motion
float midposY = archMidPos.y - (archMidPos.y * 2);
Vector3 archMidPosReverse = archMidPos;
archMidPosReverse.y = midposY;
Vector3 obj2StartPos = startPos;
archMidPosReverse.z = archMidPosReverse.z - moveStep;
obj2StartPos.z = obj2StartPos.z - moveStep;
Vector3 m3 = Vector3.Lerp(endPos, archMidPosReverse, count);
Vector3 m4 = Vector3.Lerp(archMidPosReverse, obj2StartPos, count);
// Move Object 2
obj2.transform.position = Vector3.Lerp(m3, m4, count);
// Reset swap boolean and count once object has swapped places
if (obj1.transform.position.x == endPos.x)
{
swap = false;
count = 0;
}
}
}
}
}
EDIT 04/04/2020:
Ok so I have noticed that the x value shifts due to multiplying by fixedDeltaTime in FixedUpdate()
If you attach below script to an object on x round number and press play it will move along the z axis, the x will shift from the round number to long decimal float.
If you comment out the line in FixedUpdate (transform.position = Vector3.MoveTowards(transform.position, destinationPos, moveStep * Time.fixedDeltaTime);) and remove comment slashes from statement below now the object stays on the whole x number, however the speed along z axis is no longer constant and loses sync each frame with other objects on same z axis moving at same pace..
Settings I currently user are:
moveSpeed: 4
moveStep: 2.5
Mass: 1
Drag/Angular Drag: None
Use Gravity: No
isKinematic: Yes
Interpolate: None
Collision: Continuous Speculative
Constraints: None
code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Cube_Control : MonoBehaviour
{
public float moveSpeed;
public float moveStep;
public Vector3 currentPos;
public Vector3 destinationPos;
private Rigidbody rb;
// Start is called before the first frame update
void Start()
{
currentPos = transform.position;
currentPos.x = Mathf.Round(currentPos.x);
rb = this.GetComponent<Rigidbody>();
}
void Update()
{
destinationPos = currentPos;
destinationPos.z = destinationPos.z - moveStep;
destinationPos.x = Mathf.Round(destinationPos.x);
currentPos = transform.position;
currentPos.x = Mathf.Round(currentPos.x);
}
// Update is called once per frame
void FixedUpdate()
{
transform.position = Vector3.MoveTowards(transform.position, destinationPos, moveStep * Time.fixedDeltaTime);
//transform.position = Vector3.MoveTowards(transform.position, destinationPos, moveStep);
}
public void setObstacleSpeed(float speed)
{
moveSpeed = speed;
}
public void setObstacleMoveStep(float step)
{
moveStep = step;
}
private void Destroy(GameObject obj)
{
obj.SetActive(false);
}
private void OnTriggerEnter(Collider other)
{
Debug.Log("Ow! I Feel Triggerd " + other);
if (other.gameObject.tag == "WallOfDoom")
{
Debug.Log("I hit the WALL OF DOOOOOOMMM!");
Destroy(this.gameObject);
}
else if (other.gameObject.tag == "Plyr_Bullet")
{
Destroy(this.gameObject);
}
}
private void OnCollisionEnter(Collision collision)
{
Debug.Log("Ow! I Feel Triggerd " + collision);
if (collision.gameObject.tag == "WallOfDoom")
{
Debug.Log("I hit the WALL OF DOOOOOOMMM!");
Destroy(this.gameObject);
}
}
}

Related

Zooming out the camera so that it can see all objects

I have a list of objects, these are blue stickmen on the video, I need to make the camera move away by itself and all objects (blue stickmen) always fit into it, you need to take into account that there will be more and more objects each time, so the camera should be dynamic and adapt itself to all objects
https://youtube.com/shorts/x3uSO2L22Kc?feature=share
Practical solution for any camera angle and objects positions
The idea here is fairly simple.
At each step we check if each object is inside of camera view or is camera too far away, then we simply adjust the camera position towards a better one.
Step by step, our camera will follow target objects dynamically, and when stabilized, all target objects will be captured by camera.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraAutoFitSmooth : MonoBehaviour
{
public int maxNumberOfObjs = 100;
public GameObject objPrefab;
public float maxInitRange = 10f;
public float minCameraHeight = 1f;
public float maxCameraMoveSpeed = 9f;
public float marginalPos = 0.1f;
[HideInInspector]
public List<Transform> objs = new List<Transform>();
Camera cam;
void Start()
{
cam = Camera.main;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
RandomObjs();
}
// Randomly regenerate objects
void RandomObjs()
{
int nowNumberOfObjs = Random.Range(0, maxNumberOfObjs);
for (int i = objs.Count - 1; i > nowNumberOfObjs; i--)
{
Destroy(objs[i].gameObject);
objs.RemoveAt(i);
}
for (int i = objs.Count; i <= nowNumberOfObjs; i++)
objs.Add(Instantiate(objPrefab).transform);
foreach (var obj in objs)
obj.position = Random.insideUnitSphere * maxInitRange;
}
void LateUpdate()
{
SetCameraFitPosition(Time.deltaTime);
}
void SetCameraFitPosition(float deltaTime)
{
Vector3 targetCamPos = cam.transform.position;
if (objs.Count == 1)
{
targetCamPos = objs[0].position - minCameraHeight * cam.transform.forward;
}
else if (objs.Count > 1)
{
float minInsideDiff = 1f, maxOutsideDiff = 0f;
Vector3 center = Vector3.zero;
foreach (var obj in objs)
{
Vector3 screenPos = GetScreenPos(obj.position);
if (IsInsideView(screenPos))
minInsideDiff = Mathf.Min(minInsideDiff, CalculateInsideDiff(screenPos.x), CalculateInsideDiff(screenPos.y), CalculateInsideDiff(screenPos.z));
else
maxOutsideDiff = Mathf.Max(maxOutsideDiff, CalculateOutsideDiff(screenPos.x), CalculateOutsideDiff(screenPos.y), CalculateOutsideDiff(screenPos.z));
center += obj.position;
}
center /= objs.Count;
float nowHeight = Vector3.Project(cam.transform.position - center, cam.transform.forward).magnitude;
float maxDiff = maxOutsideDiff > 0f ? maxOutsideDiff : -minInsideDiff;
float finalHeight = Mathf.Max(nowHeight + maxDiff * maxCameraMoveSpeed, minCameraHeight);
targetCamPos = center - finalHeight * cam.transform.forward;
}
cam.transform.position = Vector3.MoveTowards(cam.transform.position, targetCamPos, maxCameraMoveSpeed * deltaTime);
}
Vector3 GetScreenPos(Vector3 pos)
{
return cam.WorldToViewportPoint(pos);
}
float CalculateOutsideDiff(float pos)
{
float diff = 0f;
if (pos > 1f + marginalPos)
diff = pos - 1f;
else if (pos < -marginalPos)
diff = -pos;
return diff;
}
float CalculateInsideDiff(float pos)
{
float diff = 0f;
if (pos < 1f - marginalPos && pos > marginalPos)
diff = Mathf.Min(1f - pos, pos);
return diff;
}
bool IsInsideView(Vector3 screenPoint)
{
return screenPoint.z > 0f && screenPoint.x > 0f && screenPoint.x < 1 && screenPoint.y > 0f && screenPoint.y < 1;
}
}
If you need more info feel free to contact me :) Cheers!
The following script will position a perspective camera in a top down view, so that all tracked GameObjects (objs) are visible.
It is assumed that the objects are on the zero xz plane and are points, so their actual dimensions are not taken into account. There must be at least one tracked object. The objects may not be spaced in such a way that would require the cameras height to exceed the maximum floating point value.
public GameObject[] objs;//objects that must be fitted
private Camera cam;
float recXmin, recXmax, recYmin, recYmax;
Vector3 center;
void Start()
{
cam = Camera.main;
cam.transform.rotation = Quaternion.Euler(90, 0, 0);
}
void LateUpdate()
{
recXmin = objs[0].transform.position.x;
recXmax = objs[0].transform.position.x;
recYmin = objs[0].transform.position.z;
recYmax = objs[0].transform.position.z;
center = Vector3.zero;
foreach (GameObject obj in objs)
{
if (obj.transform.position.x < recXmin)
{
recXmin = obj.transform.position.x;
}
if (obj.transform.position.x > recXmax)
{
recXmax = obj.transform.position.x;
}
if (obj.transform.position.z < recYmin)
{
recYmin = obj.transform.position.z;
}
if (obj.transform.position.z > recYmax)
{
recYmax = obj.transform.position.z;
}
}
float horizontalHeight = (recYmax - recYmin) / 2 / Mathf.Tan(Mathf.Deg2Rad * cam.fieldOfView / 2);
float verticalHeight = (recXmax - recXmin) / 2 / Mathf.Tan(Mathf.Deg2Rad * Camera.VerticalToHorizontalFieldOfView(cam.fieldOfView, cam.aspect) / 2);
float finalHeight = horizontalHeight > verticalHeight ? horizontalHeight : verticalHeight;
center = new Vector3(recXmin + (recXmax - recXmin) / 2, finalHeight, recYmin + (recYmax - recYmin) / 2);
cam.transform.position = center;
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawLine(new Vector3(recXmin, 0, recYmin), new Vector3(recXmin, 0, recYmax));
Gizmos.DrawLine(new Vector3(recXmax, 0, recYmin), new Vector3(recXmax, 0, recYmax));
Gizmos.color = Color.green;
Gizmos.DrawLine(new Vector3(recXmin, 0, recYmin), new Vector3(recXmax, 0, recYmin));
Gizmos.DrawLine(new Vector3(recXmin, 0, recYmax), new Vector3(recXmax, 0, recYmax));
Gizmos.color = Color.blue;
Gizmos.DrawSphere(center, 0.5f);
}
the script determines the "bounding square" formed by all tracked objects
the bounding square is assumed to be the basis of a pyramid with the camera at its peak
using trigonometry the height of the camera can be calculated, by taking into account the known length of the pyramid's base side and the cameras field of view
the calculation is made twice for the cameras horizontal and vertical field of view
the greater of these two values is then selected
lastly the camera is position into the middle of the pyramids base and at the determined height, so that it ends up at the pyramids peak

How can I rotate the capsule only on the Y?

RotateTo is call from the Update. I want it to rotate on the Y only.
now it seems like it's rotating on all axis X,Y,Z
private void RotateTo()
{
var distance = Vector3.Distance(capsule.position, curvedLinePoints[rotationIndex].transform.position);
if(distance < 0.1f)
{
rotationIndex++;
}
// Determine which direction to rotate towards
Vector3 targetDirection = curvedLinePoints[rotationIndex].transform.position -capsule.position;
// The step size is equal to speed times frame time.
float singleStep = rotationSpeed * Time.deltaTime;
// Rotate the forward vector towards the target direction by one step
Vector3 newDirection = Vector3.RotateTowards(capsule.forward, targetDirection, singleStep, 0.0f);
// Calculate a rotation a step closer to the target and applies rotation to this object
capsule.rotation = Quaternion.LookRotation(newDirection);
}
This is the full script.
The transform is moving along g waypoints there are more than 4000 waypoints the capsule should only rotate looking each time to the next curvedLinePoint from the List curvedLinePoints.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class WaypointsFollower : MonoBehaviour
{
public float speed;
public Waypoints waypoints;
public Transform capsule;
public bool go;
public bool goForward;
public float rotationSpeed;
private int index = 0;
private int rotationIndex = 0;
private int counter = 0;
private int c = 0;
private List<GameObject> curvedLinePoints = new List<GameObject>();
public int numofposbetweenpoints;
private bool getonce;
private bool getBackwardIndexOnce = true;
private void Start()
{
waypoints = GameObject.Find("Waypoints").GetComponent<Waypoints>();
curvedLinePoints = GameObject.FindGameObjectsWithTag("Curved Line Point").ToList();
if(waypoints.moveInReverse == false)
{
goForward = true;
}
else
{
goForward = false;
}
if(goForward)
{
index = 0;
}
}
private void Update()
{
if (getonce == false)
{
numofposbetweenpoints = curvedLinePoints.Count;
getonce = true;
}
if (go == true && waypoints.lineRendererPositions.Count > 0)
{
if(goForward == false && getBackwardIndexOnce)
{
index = waypoints.lineRendererPositions.Count - 1;
getBackwardIndexOnce = false;
}
RotateTo();
Move();
}
}
private void Move()
{
Vector3 newPos = transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
Vector3 oldPos = newPos;
// error exception out of bound on line 55 to check !!!!!
newPos = Vector3.MoveTowards(oldPos, waypoints.lineRendererPositions[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == waypoints.lineRendererPositions[index]) // Vector3 comparison is approximate so this is ok
{
// when you hit a waypoint:
if (goForward)
{
bool atLastOne = index >= waypoints.lineRendererPositions.Count - 1;
if (!atLastOne)
{
index++;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else { index--; goForward = false; }
}
else
{ // going backwards:
bool atFirstOne = index <= 0;
if (!atFirstOne)
{
index--;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else { index++; goForward = true; }
}
}
else
{
stillTraveling = false;
}
}
transform.position = newPos;
}
private void RotateTo()
{
var distance = Vector3.Distance(capsule.position, curvedLinePoints[rotationIndex].transform.position);
if(distance < 0.1f)
{
rotationIndex++;
}
// Determine which direction to rotate towards
Vector3 targetDirection = curvedLinePoints[rotationIndex].transform.position -capsule.position;
// The step size is equal to speed times frame time.
float singleStep = rotationSpeed * Time.deltaTime;
// Rotate the forward vector towards the target direction by one step
Vector3 newDirection = Vector3.RotateTowards(capsule.forward, targetDirection, singleStep, 0.0f);
// Calculate a rotation a step closer to the target and applies rotation to this object
capsule.rotation = Quaternion.LookRotation(newDirection);
}
}
This is a screenshot of the hierarchy the platform is the moving transform in the script and the capsule is the capsule that should only rotate facing each time the next curvedLinePoint. There are over 4000 waypoints but only 10 curvedLinePoints. a bit confusing. The capsule should rotate facing each time the next curvedLinePoint while the transform is moving along the waypoints.
Screenshot
I tried this now :
private void RotateTo()
{
var distance = Vector3.Distance(capsule.position, curvedLinePoints[rotationIndex].transform.position);
if(distance < 0.1f)
{
rotationIndex++;
}
var lookPos = curvedLinePoints[rotationIndex].transform.position - capsule.position;
lookPos.y = 0;
var rotation = Quaternion.LookRotation(lookPos);
capsule.rotation = Quaternion.Slerp(capsule.rotation, rotation, Time.deltaTime * rotationSpeed);
}
and it's rotating bu when I'm looking on the capsule I don't see any of the axis pointing the next point for example in this screenshot the blue is facing to the right the green up the red more ore less down while the point it's moving to is on the left cube so the capsule rotates but why none of the axis is pointing at its direction?
Rotation
I also added eyes to the capsule on the blue axis thinking the blue axis is forward but the capsule is rotating the eyes are never facing the next target.
This screenshot is just to show the eyes on the blue axis direction.
Eyes

Character run faster with 2 buttons pressed at same time

Im trying to make controller script for my character. Everything works ok, but when i press 2 movement buttons at same time my character moves faster.
If i press D it moves slower than if i press D+S or D+W. How i can fix that? I want my character to move with same speed.
Code:
AnimationsCharacter animations;
CharacterController controller;
Transform camera;
Vector3 camForward;
Vector3 camRight;
Vector3 motion;
float horizontal;
float vertical;
float sprint;
float inputMagnitude;
float speed;
float defaultSpeed = 5;
float sprintSpeed = 10;
void Start()
{
controller = GetComponent<CharacterController>();
animations = GetComponent<AnimationsCharacter>();
camera = Camera.main.transform;
}
void FixedUpdate()
{
GetMoveInput();
}
public void GetMoveInput()
{
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
sprint = Input.GetAxis("Sprint");
if (horizontal != 0 || vertical != 0)
{
if(sprint != 0)
{
speed = sprintSpeed;
}
else
{
speed = defaultSpeed;
}
CalculateCamera();
Move();
}
}
public void CalculateCamera()
{
camForward = camera.forward;
camRight = camera.right;
camForward.y = 0;
camRight.y = 0;
camForward = camForward.normalized;
camRight = camRight.normalized;
}
public void Move()
{
motion = (camForward * vertical + camRight * horizontal);
inputMagnitude = new Vector2(horizontal, vertical).sqrMagnitude;
controller.Move(motion * speed * Time.deltaTime);
animations.AnimMovement(inputMagnitude);
transform.rotation = Quaternion.LookRotation(motion);
}
I tried different things, like /2 if 2 buttons pressed. Seems like i do something wrong.
You should Normalize the motion in the case that it has a sqrMagnitude > 1 (= magnitude > 1 but cheaper access) so it has always magnitude <= 1.
motion = (camForward * vertical + camRight * horizontal);
if(motion.sqrMagnitude > 1)
{
motion.Normalize();
}

How Can I reduce speed of one player and increase speed of another player when it comes closer to one another?

Here, in my code using Microsoft visual studio in C# for game development to detect Collision. I wrote the script to find shortest path of the player using the A* algorithm. In this script, I am unable to detect collision between different players.I want to reduce the speed of one player and increase the speed of another player using different tags. But I am unable to handle the speed of the player.
Here is my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class PathfindingTester : MonoBehaviour
{
// The A* manager.
private AStarManager AStarManager = new AStarManager();
// Array of possible waypoints.
List<GameObject> Waypoints = new List<GameObject>();
// Array of waypoint map connections. Represents a path.
List<Connection> ConnectionArray = new List<Connection>();
// The start and end target point.
public GameObject start;
public GameObject end;
// Debug line offset.
Vector3 OffSet = new Vector3(0, 0.3f, 0);
public float speed;
private Rigidbody rb;
private Transform target;
int current;
//float WPradius = 0.5f;
Connection aConnection;
public Text countText;
private int countit;
//public GameObject[] targets;
// Start is called before the first frame update
void Start()
{
if (start == null || end == null)
{
Debug.Log("No start or end waypoints.");
return;
}
// Find all the waypoints in the level.
GameObject[] GameObjectsWithWaypointTag;
GameObjectsWithWaypointTag = GameObject.FindGameObjectsWithTag("Waypoint");
foreach (GameObject waypoint in GameObjectsWithWaypointTag)
{
WaypointCON tmpWaypointCon = waypoint.GetComponent<WaypointCON>();
if (tmpWaypointCon)
{
Waypoints.Add(waypoint);
}
}
// Go through the waypoints and create connections.
foreach (GameObject waypoint in Waypoints)
{
WaypointCON tmpWaypointCon = waypoint.GetComponent<WaypointCON>();
// Loop through a waypoints connections.
foreach (GameObject WaypointConNode in tmpWaypointCon.Connections)
{
Connection aConnection = new Connection();
aConnection.SetFromNode(waypoint);
aConnection.SetToNode(WaypointConNode);
AStarManager.AddConnection(aConnection);
}
}
// Run A Star...
ConnectionArray = AStarManager.PathfindAStar(start, end);
// Debug.Log(ConnectionArray.Count);
// rb = GetComponent<Rigidbody>();
//rb.MovePosition((ConnectionArray[0].GetFromNode().transform.position + OffSet));
//transform.position = ConnectionArray[0].GetFromNode().transform.position;
countit = 0;
countText.text = "Count: " + countit;
/*countTextTwo.text = "Counttwo:" + countit;
countTextThree.text = "Countthree:" + countit;*/
}
// Draws debug objects in the editor and during editor play (if option set).
void OnDrawGizmos()
{
// Draw path.
foreach (Connection aConnection in ConnectionArray)
{
Gizmos.color = Color.red;
Gizmos.DrawLine((aConnection.GetFromNode().transform.position + OffSet),
(aConnection.GetToNode().transform.position + OffSet));
}
}
// Update is called once per frame
void Update()
{
if (transform.position != ConnectionArray[current].GetToNode().transform.position)
{
Vector3 pos2 = Vector3.MoveTowards(transform.position, ConnectionArray[current].GetToNode().transform.position, speed * Time.deltaTime);
var LookPos = ConnectionArray[current].GetToNode().transform.position - transform.position;
LookPos.y = 0;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(LookPos), 1);
GetComponent<Rigidbody>().MovePosition(pos2);
//Debug.Log(transform.position);
}
else
{
current = (current + 1) % ((ConnectionArray.Count));
// if (current + 2 == (ConnectionArray.Count - 1) && (transform.position != ConnectionArray[current].GetToNode().transform.position))
if (current + (ConnectionArray.Count - 1) == (ConnectionArray.Count - 1) && (transform.position != ConnectionArray[current].GetToNode().transform.position))
{
if ((transform.position != ConnectionArray[(current + (ConnectionArray.Count - 1))].GetFromNode().transform.position))
{
countit = countit + 1;
countText.text = "Count:" + countit;
/*countTextTwo.text = "Counttwo:" + countit;
countTextThree.text = "Countthree:" + countit;*/
speed = speed - 1 f;
}
ConnectionArray.Reverse();
Vector3 pos3 = Vector3.MoveTowards(transform.position, ConnectionArray[current].GetFromNode().transform.position, speed * Time.deltaTime);
GetComponent<Rigidbody>().MovePosition(pos3);
if (countit == 10)
{
speed = 0f;
}
}
else
{
{
current = (current) % ((ConnectionArray.Count));
}
}
}
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("target"))
{
other.gameObject.SetActive(true);
countit = countit + 1;
countText.text = "Count: " + countit;
}
if (other.gameObject.CompareTag("playerfirstspeed"))
{
other.gameObject.SetActive(true);
Vector3.MoveTowards(transform.position, ConnectionArray[current].GetFromNode().transform.position, speed * Time.deltaTime);
}
if (other.gameObject.CompareTag("playersecondspeed"))
{
other.gameObject.SetActive(true);
Vector3.MoveTowards(transform.position, ConnectionArray[current].GetFromNode().transform.position, speed * Time.deltaTime);
}
if (other.gameObject.CompareTag("playerthirdspeed"))
{
other.gameObject.SetActive(true);
Vector3.MoveTowards(transform.position, ConnectionArray[current].GetFromNode().transform.position, speed * Time.deltaTime);
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.CompareTag("target"))
{
other.gameObject.SetActive(false);
}
if (other.gameObject.CompareTag("playerfirstspeed"))
{
Vector3.MoveTowards(transform.position, ConnectionArray[current].GetFromNode().transform.position, speed - 2);
}
if (other.gameObject.CompareTag("playersecondspeed"))
{
Vector3.MoveTowards(transform.position, ConnectionArray[current].GetFromNode().transform.position, speed - 2);
}
if (other.gameObject.CompareTag("playerthirdspeed"))
{
Vector3.MoveTowards(transform.position, ConnectionArray[current].GetFromNode().transform.position, speed - 2);
}
}
}
As im understand u have only one variable "speed" for all of three players.
Hows about to declare "speed" variable for each player, then check certain raduis for collisions with other players, get other players by collision and make addition or substraction for them?

2D Character falls off the map in Unity3D

I am currently working on a project for one of the courses i am taking.
I am making a 2D game in unity3D, and i have a small problem, every time i run the game my character keeps on falling through the map, even though i have added a rigidbody2D and a boxCollider2D to both my character and the foreground. The code is attached, it is in C# and it is a bit long. Thank you so much in advance ..
enter code here
using System;
using UnityEngine;
using System.Collections;
public class CharacterController2D : MonoBehaviour
{
private const float SkinWidth = .02f;
private const int TotalHorizontalRays = 8;
private const int TotalVerticalRays = 4;
private static readonly float SlopeLimitTanget = Mathf.Tan (75f * Mathf.Deg2Rad);
public LayerMask PlatformMask;
public ControllerParameters2D DefaultParameters;
public ControllerState2D State { get; private set; }
public Vector2 Velocity { get { return _velocity; }}
public bool HandleCollisions { get; set; }
//Return overrideparamteres if it is not null, if it is null it will return DefaultParameters
public ControllerParameters2D Parameters { get { return _overrideParameters ?? DefaultParameters; } }
public GameObject StandingOn { get; private set;}
public Vector3 PlatformVelocity { get; private set;}
public bool CanJump
{
get
{
if(Parameters.JumpRestrictions == ControllerParameters2D.JumpBehavior.CanJumpAnywhere)
return _jumpIn <= 0;
if(Parameters.JumpRestrictions == ControllerParameters2D.JumpBehavior.CanJumpOnGround)
return State.IsGrounded;
return false;
}
}
private Vector2 _velocity;
private Transform _transform;
private Vector3 _localScale;
private BoxCollider2D _boxCollider;
private ControllerParameters2D _overrideParameters;
private float _jumpIn;
private GameObject _lastStandingOn;
private Vector3
_activeGlobalPlatformPoint,
_activeLocalPlatformPoint;
private Vector3
_raycastTopLeft,
_raycastBottomRight,
_raycastBottomLeft;
private float _verticalDistanceBetweenRays,
_horizonatalDistanceBetweenRays;
public void Awake()
{
HandleCollisions = true;
State = new ControllerState2D();
_transform = transform;
_localScale = transform.localScale;
_boxCollider = GetComponent <BoxCollider2D>();
// Absolute Value
var colliderWidth = _boxCollider.size.x * Mathf.Abs(transform.localScale.x) - (2 * SkinWidth);
_horizonatalDistanceBetweenRays = colliderWidth / (TotalVerticalRays - 1);
var colliderHeight = _boxCollider.size.y * Mathf.Abs( transform.localScale.y ) - (2 * SkinWidth);
_verticalDistanceBetweenRays = colliderHeight / (TotalHorizontalRays - 1);
}
public void AddForce(Vector2 force)
{
_velocity = force;
}
public void SetForce(Vector2 force)
{
_velocity += force;
}
public void SetHorizontalForce(float x)
{
_velocity.x = x;
}
public void SetVerticalForce(float y)
{
_velocity.y = y;
}
public void Jump()
{
AddForce(new Vector2(0, Parameters.JumpMagnitude));
_jumpIn = Parameters.JumpFrequency;
}
public void LateUpdate()
{
_jumpIn -= Time.deltaTime;
//We force the player to go up or down based on the gravity
_velocity.y += Parameters.Gravity * Time.deltaTime;
//Move the characther per his velocity scaled by time
Move (Velocity * Time.deltaTime);
}
// Ensures the player doesn't fall off the map or move through the wall
private void Move(Vector2 deltaMovement)
{
var wasGrounded = State.IsCollidingBelow;
State.Reset();
if(HandleCollisions)
{
HandlePlatforms();
CalculateRayOrigins();
if(deltaMovement.y < 0 && wasGrounded)
HandleVerticalSlope(ref deltaMovement);
if(Mathf.Abs(deltaMovement.x) > .001f)
MoveHorizontally(ref deltaMovement);
MoveVertically(ref deltaMovement);
CorrectHorizontalPlacement(ref deltaMovement, true);
CorrectHorizontalPlacement(ref deltaMovement, false);
}
_transform.Translate(deltaMovement, Space.World);
if (Time.deltaTime > 0)
_velocity = deltaMovement / Time.deltaTime;
_velocity.x = Mathf.Min (_velocity.x, Parameters.MaxVelocity.x);
_velocity.y = Mathf.Min (_velocity.y, Parameters.MaxVelocity.y);
if(State.IsMovingUpSlope)
_velocity.y = 0;
//Standing on the platform
if(StandingOn != null)
{
_activeGlobalPlatformPoint = transform.position;
_activeLocalPlatformPoint = StandingOn.transform.InverseTransformPoint(transform.position);
Debug.DrawLine(transform.position, _activeGlobalPlatformPoint);
Debug.DrawLine(transform.position, _activeLocalPlatformPoint + StandingOn.transform.position);
if(_lastStandingOn != StandingOn)
{
//If the last thing we are standing on is not null, send a message to leave it
if(_lastStandingOn != null)
_lastStandingOn.SendMessage("ControllerExist2D", this, SendMessageOptions.DontRequireReceiver);
//Inform what we are standing on that we have entered
StandingOn.SendMessage("ControllerEnter2D", this, SendMessageOptions.DontRequireReceiver);
_lastStandingOn = StandingOn;
}
//Invoke the platform that we are standing on it
else if (StandingOn != null)
StandingOn.SendMessage("ControllerStay2D", this, SendMessageOptions.DontRequireReceiver);
}
else if (_lastStandingOn != null)
{
_lastStandingOn.SendMessage("ControllerExit2D", this, SendMessageOptions.DontRequireReceiver);
_lastStandingOn = null;
}
}
private void HandlePlatforms()
{
//Calculate the velocity of the platform
if(StandingOn != null)
{
var newGlobalPlatformPoint = StandingOn.transform.TransformPoint(_activeLocalPlatformPoint);
var moveDistance = newGlobalPlatformPoint - _activeGlobalPlatformPoint;
//Sticks the player on the platform, wherever the platform teleport the players stays on it
if(moveDistance != Vector3.zero)
transform.Translate(moveDistance, Space.World);
PlatformVelocity = (newGlobalPlatformPoint - _activeGlobalPlatformPoint) / Time.deltaTime;
}
else
PlatformVelocity = Vector3.zero;
StandingOn = null;
}
private void CorrectHorizontalPlacement(ref Vector2 deltaMovement, bool isRight)
{
var halfwidth = (_boxCollider.size.x * _localScale.x) / 2f;
var rayOrigin = isRight ? _raycastBottomRight : _raycastBottomLeft;
if(isRight)
rayOrigin.x -= (halfwidth - SkinWidth);
else
rayOrigin.x += (halfwidth - SkinWidth);
var rayDirection = isRight ? Vector2.right : -Vector2.right;
var offset = 0f;
for(var i = 1; i <= TotalHorizontalRays - 1; i++)
{
var rayVector = new Vector2(deltaMovement.x + rayOrigin.x, deltaMovement.y + rayOrigin.y + (i * _verticalDistanceBetweenRays));
Debug.DrawRay(rayVector, rayDirection * halfwidth, isRight ? Color.cyan : Color.magenta);
var raycastHit = Physics2D.Raycast(rayVector, rayDirection, halfwidth, PlatformMask);
if(!raycastHit)
continue;
offset = isRight ? ((raycastHit.point.x - _transform.position.x) - halfwidth) : (halfwidth - (_transform.position.x - raycastHit.point.x));
}
deltaMovement.x += offset;
}
private void CalculateRayOrigins()
{
var size = new Vector2 (_boxCollider.size.x * Mathf.Abs (_localScale.x), _boxCollider.size.y * Mathf.Abs (_localScale.y)) / 2;
var center = new Vector2(_boxCollider.center.x * _localScale.x, _boxCollider.center.y * _localScale.y);
//Location of the player, then we add the box collider to it relative to the center of the player
_raycastTopLeft = _transform.position + new Vector3 (center.x - size.x + SkinWidth, center.y + size.y - SkinWidth);
_raycastBottomRight = _transform.position + new Vector3 (center.x + size.x - SkinWidth, center.y - size.y + SkinWidth); //Going right
_raycastBottomLeft = _transform.position + new Vector3 (center.x - size.x + SkinWidth, center.y - size.y + SkinWidth); //Going left and down-up
}
//Cast rays to the left or to the right depending on the player's movement
//Determining how far the player can go either to the left, or to the right
private void MoveHorizontally(ref Vector2 deltaMovement)
{
var isGoingRight = deltaMovement.x > 0;
//The distance between the starting point and the final destination
var rayDistance = Mathf.Abs (deltaMovement.x) + SkinWidth;
//Where is the player going? right or left
var rayDirection = isGoingRight ? Vector2.right : -Vector2.right;
//Right? we start from bottom right. Left? we start fro, bottom left
var rayOrigin = isGoingRight ? _raycastBottomRight : _raycastBottomLeft;
//Determines how many rays we want to shoot out to the left or to the right
for(var i = 0; i < TotalHorizontalRays; i++)
{
var rayVector = new Vector2(rayOrigin.x, rayOrigin.y + (i * _verticalDistanceBetweenRays));
//Visual representation about the rays
Debug.DrawRay(rayVector, rayDirection * rayDistance, Color.red);
//Checks if the player hit something or not
var rayCastHit = Physics2D.Raycast(rayVector, rayOrigin, rayDistance, PlatformMask);
if(!rayCastHit) //If there was a raycast then do something, otherwise continue to loop
continue;
//We return true if we are on a horizotnal slope, and check if we are going right or left or hit something while going up
if(i == 0 && HandleHorizontalSlope(ref deltaMovement, Vector2.Angle(rayCastHit.normal, Vector2.up), isGoingRight))
break;
//If we hit something then we can only go that far forward
deltaMovement.x = rayCastHit.point.x - rayVector.x;
rayDistance = Mathf.Abs(deltaMovement.x);
if(isGoingRight)
{
//If we are going right, then we have to substract the skinwidth
deltaMovement.x -= SkinWidth;
State.IsCollidingRight = true;
}
else
{
//The oppoiste of the if statement, if we are going left, we add the skinwidth
deltaMovement.x += SkinWidth;
State.IsCollidingLeft = true;
}
//Handles error collision, if the player hits something and go through it
if(rayDistance < SkinWidth + .0001f)
break;
}
}
private void MoveVertically(ref Vector2 deltaMovement)
{
//Check to see if going up or down
var isGoingUp = deltaMovement.y > 0;
var rayDistance = Mathf.Abs (deltaMovement.y) + SkinWidth;
var rayDirection = isGoingUp ? Vector2.up : -Vector2.up;
var rayOrigin = isGoingUp ? _raycastTopLeft : _raycastBottomLeft;
rayOrigin.x += deltaMovement.x;
var standingOnDistance = float.MaxValue;
for(var Count = 0; Count < TotalVerticalRays; Count++)
{
var rayVector = new Vector2(rayOrigin.x + (Count * _horizonatalDistanceBetweenRays), rayOrigin.y);
Debug.DrawRay(rayVector, rayDirection * rayDistance, Color.red);
var raycastHit = Physics2D.Raycast(rayVector, rayDirection, rayDistance, PlatformMask);
//If the player hit nothing then keep going.
if(raycastHit)
{
continue;
}
if(!isGoingUp)
{
var verticalDistanceToHit = _transform.position.y - raycastHit.point.y;
if(verticalDistanceToHit < standingOnDistance)
{
standingOnDistance = verticalDistanceToHit;
//Platform we are standing on
StandingOn = raycastHit.collider.gameObject;
}
}
//Determine the furthest distance we can move down or up without hitting anything
deltaMovement.y = raycastHit.point.y - rayVector.y;
rayDistance = Mathf.Abs(deltaMovement.y);
if(isGoingUp)
{
deltaMovement.y -= SkinWidth;
State.IsCollidingAbove = true;
}
else
{
deltaMovement.y += SkinWidth;
State.IsCollidingBelow = true;
}
if(!isGoingUp && deltaMovement.y > .0001f)
{
State.IsMovingUpSlope = true;
}
if(rayDistance < SkinWidth + .0001f)
{
break;
}
}
}
private void HandleVerticalSlope(ref Vector2 deltaMovement)
{
//Give us the center of the vertical rays;
var center = (_raycastBottomLeft.x + _raycastBottomRight.x) / 2;
var direction = -Vector2.up;
var slopeDistance = SlopeLimitTanget * (_raycastBottomRight.x - center);
var slopeRayVector = new Vector2 (center, _raycastBottomLeft.y);
Debug.DrawRay(slopeRayVector, direction * slopeDistance, Color.yellow);
var raycastHit = Physics2D.Raycast (slopeRayVector, direction, slopeDistance, PlatformMask);
if (!raycastHit)
return;
// ReSharper disable CompareOfFloatsByEqualityOperator
var isMovingDownSlope = Mathf.Sign (raycastHit.normal.x) == Mathf.Sign (deltaMovement.x);
if(!isMovingDownSlope)
return;
var angle = Vector2.Angle (raycastHit.normal, Vector2.up);
if(Mathf.Abs(angle) < .0001f)
return; //Which means there we are not on a slope, we are on something else
State.IsMovingDownSlope = true;
State.SlopeAngle = angle;
deltaMovement.y = raycastHit.point.y - slopeRayVector.y;
}
private bool HandleHorizontalSlope(ref Vector2 deltaMovement, float angle, bool isGoingRight)
{
//We do not want to move to an angle of 90
if(Mathf.RoundToInt(angle) == 90)
return false;
if(angle > Parameters.SlopeLimit)
{
deltaMovement.x = 0;
return true;
}
if(deltaMovement.y > .07f)
return true;
deltaMovement.x += isGoingRight ? -SkinWidth : SkinWidth;
deltaMovement.y = Mathf.Abs (Mathf.Tan (angle * Mathf.Deg2Rad) * deltaMovement.x);
State.IsMovingUpSlope = true;
State.IsCollidingBelow = true;
return true;
}
public void OnTriggerEnter2D(Collider2D other)
{
var parameters = other.gameObject.GetComponent<ControllerPhysicsVolume2D>();
if(parameters == null)
return;
_overrideParameters = parameters.Parameters;
}
public void OnTriggerExit2D(Collider2D other)
{
var parameters = other.gameObject.GetComponent<ControllerPhysicsVolume2D>();
if(parameters == null)
return;
_overrideParameters = null;
}
}
As #Terrance said you really don't need to write your own code logic for collision detection.
Secondly I noticed OnTriggerEnter2D and OnTriggerExit2D methods in your code, that also points out to one thing that all your boxCollider2d has isTrigger option checked. Therefore, I suggest you to uncheck isTrigger option on both your player and ground as TRIGGER will never stop two objects from crossing each other (you need to have both objects have 'isTrigger' unchecked on their colliders if you don't want them to pass through each other). And use method OnCollisionEnter2D and OnCollisionExit2D to detect the collision.
What is difference between Trigger and a Collider:
Taking real world example Colliders are tangible object e.g you yourself and the floor you are standing on both are solid and tangible.
While trigger is intangible, example of triggers can be the walkthrough security doors; these doors are hollow from inside allowing any person to pass without any hindrance, but if you wear any metal object on yourself and pass through that "Hollow Area" between the door, the door will TRIGGER an alarm. therefore with respect to the game world you can say that the door has a trigger at it hollow area.

Categories