I have a cube in the Hierarchy.
And my player (ThirdPersonController) i want to detect when the player is standing on the cube.
I want to know when it’s left right top bottom. But the main goal is if the player stand on the cube do something.
I don’t understand in the script what the Vector3 v3 should be in the Inspector how do i use it ?
In the inspector i see V3 x = 0 y = 0 z = 0
The script is attached to the cube.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Test : MonoBehaviour {
public Vector3 v3;
private static readonly Dictionary<Vector3, string> _dic = new Dictionary<Vector3, string>(6, new Vector3Comparer())
{
{Vector3.down, "Down"},
{Vector3.up, "Up"},
{Vector3.back, "Back"},
{Vector3.forward, "Front"},
{Vector3.left, "Left"},
{Vector3.right, "Right"},
};
void ReturnSide(Vector3 side)
{
string output = _dic[side];
Debug.Log(output + " was hit.");
}
class Vector3Comparer : IEqualityComparer<Vector3>
{
public bool Equals(Vector3 x, Vector3 y)
{
bool t = x.x == y.x && x.y == y.y && x.z == y.z;
return t; // or use any prebuilt method to compare vectors and return result.
}
public int GetHashCode(Vector3 obj)
{
return obj.GetHashCode();
// or implement your own hash generator
}
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
ReturnSide(v3);
}
}
A unity cube comes with a box collider on it. But I would suggest shrinking the on thats on it so it only covers one side. Then make 6 of them… one for each side. Then when you get a OnColliderEnter or Stay you can check which collider your hitting and act appropriately
Expanding a little on what was previously said (although those solutions would work):
If you’re just interested in what local direction the object is in, checking the direction I think is still fine.
There is even a built in function that can do just that - Transform.InverseTransformPoint.
I’d personally expand a little bit on it, using enum flags for easier reading, but that’s personal preference. It’s completely workable on its own, you just check vector x/y/z values instead of an enum.
using System;
using UnityEngine;
public class RelativePosition : MonoBehaviour
{
void OnCollisionEnter(Collision col)
{
Direction directionToOther = RelativePosition.GetRelativeDirection(col.transform.position, gameObject.transform);
Debug.Log("The other object " + col.gameObject.name + " was in direction: " + directionToOther);
// sample checks, add whatever you need
if ((directionToOther & Direction.Front) != 0)
Debug.Log("In front of me!");
if ((directionToOther & (Direction.Down | Direction.Left)) == (Direction.Down | Direction.Left))
Debug.Log("Below and to the left!");
}
// helper method
// preferably put it in a separate class
public static Direction GetRelativeDirection(Vector3 objPosition, Transform relativeTo)
{
Direction dir = Direction.UnknownOrDirectlyOnTop;
Vector3 relativePosition = relativeTo.InverseTransformPoint(objPosition);
dir |= relativePosition.x != 0 ? (relativePosition.x > 0 ? Direction.Right : Direction.Left) : 0;
dir |= relativePosition.y != 0 ? (relativePosition.y > 0 ? Direction.Up : Direction.Down) : 0;
dir |= relativePosition.z != 0 ? (relativePosition.z > 0 ? Direction.Front : Direction.Back) : 0;
return dir;
}
[Flags]
public enum Direction
{
UnknownOrDirectlyOnTop = 0,
Left = 1,
Right = 2,
Up = 4,
Down = 8,
Front = 16,
Back = 32
}
}
Put it on the player, collide with some objects and see if it’s understandable/suitable for you (I’ve tested it a little bit, but nothing extensive).
You might want to rule out your ground terrain immediately, to not spam the console too much.
I’m literally running this code in Unity right now without issues.
Can you post your version? If you’ve moved the helper (static) and the enum to a separate class, make sure that you update the class name in the OnCollistion part (line 9 in my example).
Now it’s working but what i wanted to do is to check when the player is standing on the cube or walking on it.
Here is a screenshot of what i mean standing on it. What i want to do is once the player is standing on the cube move the cube with the player standing on it.
If the player is standing on the cube do something. If the player is on the ground don’t do anything.
You should’ve said from the beginning you wanted a moving platform
There are tons of tutorials for those.
Not knowing what was the purpose, current solutions are general “what direction the collision took place” types.
Incorporating the existing code to make one is pretty easy:
RelativePosition.cs
using System;
using UnityEngine;
public static class RelativePosition
{
public static Direction GetRelativeDirection(Vector3 objPosition, Transform relativeTo)
{
Direction dir = Direction.UnknownOrDirectlyOnTop;
Vector3 relativePosition = relativeTo.InverseTransformPoint(objPosition);
dir |= relativePosition.x != 0 ? (relativePosition.x > 0 ? Direction.Right : Direction.Left) : 0;
dir |= relativePosition.y != 0 ? (relativePosition.y > 0 ? Direction.Up : Direction.Down) : 0;
dir |= relativePosition.z != 0 ? (relativePosition.z > 0 ? Direction.Front : Direction.Back) : 0;
return dir;
}
[Flags]
public enum Direction
{
UnknownOrDirectlyOnTop = 0,
Left = 1,
Right = 2,
Up = 4,
Down = 8,
Front = 16,
Back = 32
}
}
MovingPlatform.cs
using UnityEngine;
using Direction = RelativePosition.Direction;
public class MovingPlatform : MonoBehaviour
{
[SerializeField]
private Transform playerTransform;
[SerializeField]
private Vector3[] waypoints; // remember to set in inspector!
[SerializeField]
private float moveSpeed = 4;
[SerializeField]
private int currentWaypoint = -1;
void Start()
{
if (waypoints == null || waypoints.Length == 0)
Debug.LogWarning("Waypoints not set!");
}
void Update()
{
if (waypoints == null || waypoints.Length == 0)
return;
if (playerTransform == null)
return;
if ((RelativePosition.GetRelativeDirection(playerTransform.position, transform) & Direction.Up) != 0)
{
MoveTowardsNextPoint();
}
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.CompareTag("Player"))
{
playerTransform = col.transform;
}
}
void OnCollisionExit(Collision col)
{
if (col.transform == playerTransform)
{
playerTransform = null;
}
}
private void MoveTowardsNextPoint()
{
if (currentWaypoint < 0 || transform.position == waypoints[currentWaypoint])
{
currentWaypoint = GetNextWaypoint();
}
Vector3 newPosition = Vector3.MoveTowards(transform.position, waypoints[currentWaypoint], moveSpeed * Time.deltaTime);
Vector3 changeInPosition = transform.position - newPosition;
DragPlayer(changeInPosition);
transform.position = newPosition;
}
private int GetNextWaypoint()
{
int tmpWaypointIndex = currentWaypoint + 1;
if (tmpWaypointIndex >= 0 && tmpWaypointIndex < waypoints.Length)
{
return tmpWaypointIndex;
}
return 0;
}
private void DragPlayer(Vector3 changeInPosition)
{
playerTransform.position = playerTransform.position - changeInPosition;
}
}
Comparison is done using tags, you could do however you wish.
I’m caching the reference to playerTransform on collision and removing it on end, to not check every frame if it’s still colliding. Direction of collision is still checked in Update, just in case it’s possible to move below while still colliding (whole in platform, etc.).
Dragging the player along is done the most basic way possible.
Either way the code should be pretty self-explanatory I think, and also modular enough so you can change individual parts to better suit your needs (f.e. keep moving if the player goes back, or go back to waypoint[0] etc.).
Tested with StandardAssets ThirdPersonController (Ethan), worked nicely enough. Running on the platform works fine, keep in mind jumping up stops the platform
Extend/change/use/discard as you need. Happy coding