Unity Platform Effector 2D doesn't work for me
Hello, i'm trying to do a 2.5D plaftormer, for that i'm using only 2d colliders. I have a player controller script that i copied from a Unity tutorial:
public class PhysicsObject : MonoBehaviour
{
[HideInInspector]
public float minGroundNormalY = .65f;
public float gravedad = 1f;
protected Vector2 targetVelocity;
protected bool grounded;
protected Vector2 groundNormal;
protected Rigidbody2D rb2d;
protected Vector2 velocity;
protected ContactFilter2D contactFilter;
protected RaycastHit2D[] hitBuffer = new RaycastHit2D[16];
protected List<RaycastHit2D> hitBufferList = new List<RaycastHit2D>(16);
protected const float minMoveDistance = 0.001f;
protected const float shellRadius = 0.01f;
void OnEnable()
{
rb2d = GetComponent<Rigidbody2D>();
}
void Start()
{
contactFilter.useTriggers = false;
contactFilter.SetLayerMask(Physics2D.GetLayerCollisionMask(gameObject.layer));
contactFilter.useLayerMask = true;
}
void Update()
{
targetVelocity = Vector2.zero;
ComputeVelocity();
}
protected virtual void ComputeVelocity()
{
}
void FixedUpdate()
{
velocity += gravedad * Physics2D.gravity * Time.deltaTime;
velocity.x = targetVelocity.x;
grounded = false;
Vector2 deltaPosition = velocity * Time.deltaTime;
Vector2 moveAlongGround = new Vector2(groundNormal.y, -groundNormal.x);
Vector2 move = moveAlongGround * deltaPosition.x;
Movement(move, false);
move = Vector2.up * deltaPosition.y;
Movement(move, true);
}
void Movement(Vector2 move, bool yMovement)
{
float distance = move.magnitude;
if (distance > minMoveDistance)
{
int count = rb2d.Cast(move, contactFilter, hitBuffer, distance + shellRadius);
hitBufferList.Clear();
for (int i = 0; i < count; i++)
{
hitBufferList.Add(hitBuffer[i]);
}
for (int i = 0; i < hitBufferList.Count; i++)
{
Vector2 currentNormal = hitBufferList[i].normal;
if (currentNormal.y > minGroundNormalY)
{
grounded = true;
if (yMovement)
{
groundNormal = currentNormal;
currentNormal.x = 0;
}
}
float projection = Vector2.Dot(velocity, currentNormal);
if (projection < 0)
{
velocity = velocity - projection * currentNormal;
}
float modifiedDistance = hitBufferList[i].distance - shellRadius;
distance = modifiedDistance < distance ? modifiedDistance : distance;
}
}
rb2d.position = rb2d.position + move.normalized * distance;
}
}
The player script:
public class PlayerPlatformerController : PhysicsObject
{
public int playerId;
public float velocidadMax = 7;
public float salto = 7;
private SpriteRenderer spriteRenderer;
private Animator animator;
// Use this for initialization
void Awake()
{
spriteRenderer = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
}
protected override void ComputeVelocity()
{
Vector2 move = Vector2.zero;
move.x = Input.GetAxis("Horizontal"+playerId);
if (Input.GetButtonDown("Jump"+playerId) && grounded)
{
velocity.y = salto;
}
/*else if (Input.GetButtonUp("Jump"))
{
if (velocity.y > 0)
{
velocity.y = velocity.y * 0.5f;
}
}*/
/*bool flipSprite = (spriteRenderer.flipX ? (move.x > 0.01f) : (move.x < 0.01f));
if (flipSprite)
{
spriteRenderer.flipX = !spriteRenderer.flipX;
}*/
if (move.x > 0.02f)
{
spriteRenderer.flipX = false;
}
if(move.x < -0.02f)
{
spriteRenderer.flipX = true;
}
animator.SetBool("grounded", grounded);
animator.SetFloat("velocityX", Mathf.Abs(velocity.x) / velocidadMax);
animator.SetFloat("velocityY", velocity.y);
targetVelocity = move * velocidadMax;
}
}
So when i try to pass-trought the platform I can't, it detects it like a normal collision. What am i doing wrong?
(This is my first question, sorry if i am breaking some rule)
Answer by codemite · Nov 23, 2017 at 08:24 PM
You'll have to manually check for the platform, since you're not relying on the inner physics engine. Something like this might work before adding the collisions
PlatformEffector2D platform = hitBuffer[i].collider.GetComponent<PlatformEffector2D>();
if (!platform ||
(hitBuffer[i].normal == Vector2.up
&& velocity.y < 0 && yMovement)) //only when going down
{
hitBufferList.Add(hitBuffer[i]); // get the colliding objects
}
I used the same tutorial as the OP and this solution works. I made the following changes to the $$anonymous$$ovement function in the PhysicsObject script
void $$anonymous$$ovement(Vector2 move, bool y$$anonymous$$ovement){
float distance = move.magnitude;
if(distance>$$anonymous$$$$anonymous$$oveDistance)
{
int count = rb2d.Cast(move, contactFilter, hitBuffer, distance+shellRadius);
hitBufferList.Clear();
for (int i = 0; i<count;i++){
// This line and the if statement will check if a platform has a PlatformEffector2D.
// If it does, it will allow the player to jump up from underneath, but not fall through
// the top surface
PlatformEffector2D platform =hitBuffer[i].collider.GetComponent<PlatformEffector2D>();
if(!platform||(hitBuffer[i].normal == Vector2.up && velocity.y < 0 && y$$anonymous$$ovement)){
hitBufferList.Add (hitBuffer[i]);
}
}
for (int i = 0; i<hitBufferList.Count; i++)
{
Vector2 currentNormal = hitBufferList[i].normal;
if(currentNormal.y>$$anonymous$$GroundNormalY)
{
grounded = true;
if(y$$anonymous$$ovement){
groundNormal = currentNormal;
currentNormal.x=0;
}
}
float projection = Vector2.Dot(velocity, currentNormal);
if(projection < 0){
velocity = velocity - projection * currentNormal;
}
float modifiedDistance = hitBuffer[i].distance - shellRadius;
distance = modifiedDistance < distance ? modifiedDistance : distance;
}
}
rb2d.position = rb2d.position + move.normalized * distance;
}
Also I made a further edit because didn't want to add platformeffectors to everything I had made already. If you change this line
PlatformEffector2D platform = hitBuffer[i].collider.GetComponent();
to this line.
BoxCollider2D platform = hitBuffer[i].collider.GetComponent ();
you do not have to add PlatformEffectors to every platform and you can still jump through the bottom, without falling through the top. Which might be easier on your computer computationally.
I found that switching:
if (!platform||(hitBuffer[i].normal == Vector2.up && velocity.y < 0 && y$$anonymous$$ovement))
{
hitBufferList.Add (hitBuffer[i]);
}
to:
if(!platform||(hitBuffer[i].normal == Vector2.up && velocity.y <= 0))
{
hitBufferList.Add (hitBuffer[i]);
}
. kept the character from falling through platforms
Answer by Cuttlas-U · Apr 27, 2020 at 07:41 AM
For some reason the comparing part didnt work for me ! I mean this :
hitBuffer[i].normal == Vector2.up
so i ended up using vector2.distance < 0.01f instead ,
Your answer
Follow this Question
Related Questions
2D colliders doesnt work with Gravity Scale = 0 0 Answers
Camera for 2.5D 2P Platformer 0 Answers
How to kill player (and or end game) when enemy hits the ground? JAVASCRIPT 1 Answer
Unity 2D does not detect collisions 0 Answers
Enemies spawning on top of each other,Enemies spawn on top of each other 0 Answers