Unity MovePosition() not working?

Started by
5 comments, last by ZeroRadius 7 years, 2 months ago

Hello,

A bit of background::::: I wrote a 2D player controller in C# and it was working fine until I realized that I could go through the back of box colliders. if I hit the collider from the front it pops me up to the next collider up (it's stairs doe they get smaller as you go up) if you hit it from the back (where the stack of colliders are aligned) it lets you go through the collider and back to the front of the object. I tried adding a Polygon collider to see what would happen and it pops you to the bottom of the collider rather than treating the back of the collider as a solid wall. I am using transform.translate() for movement

I posted this problem on unity answers and was told that I should use addForce or if I did not want to do that then use Moveposition and it would fix my problem. My problem now is that I cannot get moveposition to work.

I have it written like this:


 void MoveRight()
    {
         //this.transform.Translate(Vector2.right * Speed * Time.deltaTime);
        this.GetComponent<Rigidbody2D>().MovePosition(this.transform.position + transform.right * this.Speed * Time.deltaTime);
    }

Here is the full player controller:: please note that I am only using movePosition in the MoveRight() method which is what I am trying to get working.


using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour {

    public float Speed = 2f; //Player Movement Speed;
    public float JumpForce = 300f; // Fource to add to player jump (how high he goes)
    private string Platform = "Desktop"; // What device is game being played on
    private int Jumps = 0; // How many jumps has player made (resets to 0 when player lands, this helps with Double jumps)



    public Transform GroundCheckPoint; //Empty Game object, check if it touches ground to allow jumping
    public float GroundCheckRadius; // How big a radius to give GroundCheckPoint
    public LayerMask GroundLayer; // Layers to allow jumping on
    public bool Grounded = true; // Is player touching the ground



    public bool TouchLeft = false;
    public bool TouchRight = false;
    public bool TouchJump = false;
    public bool TouchPowerUp = false;

    public bool TestMobileControls = false;


    void Start()
    {
        if (Application.platform == RuntimePlatform.WindowsPlayer)
            this.Platform = "Desktop";
        else if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
            this.Platform = "Mobile";
        if (TestMobileControls)
            this.Platform = "Mobile";

        //If they are not playing on mobile. Hide touch controls
        if(this.Platform != "Mobile")
        {
            GameObject[] mobileUI = GameObject.FindGameObjectsWithTag("MobileControl");
            foreach (GameObject ui in mobileUI)
                ui.SetActive(false);
        }
    }
	void Update ()
    {
        Grounded = Physics2D.OverlapCircle(GroundCheckPoint.position, GroundCheckRadius, GroundLayer);

        switch(Platform) //Change controls based on device that game is being played on
        {
            case "Desktop":
                this.PcMove();
                break;
            case "Mobile":
                this.MobileMove();
                break;
        }  
	}
    void MoveLeft()
    {
        this.transform.Translate(-Vector2.right * Speed * Time.deltaTime);
    }
    void MoveRight()
    {
         //this.transform.Translate(Vector2.right * Speed * Time.deltaTime);
        this.GetComponent<Rigidbody2D>().MovePosition(this.transform.position + transform.right * this.Speed * Time.deltaTime);
    }
    void Jump()
    { 
        if (this.Grounded)
        { // If player is touching the ground 
            this.GetComponent<Rigidbody2D>().AddForce(transform.up * JumpForce);
        }
    }



    void PcMove()
    {
        if (Input.GetKey(KeyCode.D))
            this.MoveRight();
        if (Input.GetKey(KeyCode.A))
            this.MoveLeft();
        if (Input.GetKeyDown(KeyCode.Space))
            this.Jump();

    }
    void MobileMove()
    {
        if (this.TouchLeft)
            this.MoveLeft();
        if (this.TouchRight)
            this.MoveRight();
        if (this.TouchJump)
        {
            this.Jump();
            this.TouchJump = false;
        }
            
    }
}

I have been searching the web but my code looks correct to me. any ideas what I am doing wrong in MovePosition() ?

Thanks in advanced

~Zero

Advertisement

First thing: fixedupdate vs update (remember input latency).
I don't see a point in using .move if the iskinematic flag is turned off, but I don't know if it's turned off (and maybe .move wouldn't work, but i've never done that). So maybe you can use .addforce (you will get stuck with the the slower physics update). I think you could also "raycast with a collider" and after that make the move/physicsforce ((if you move) you reduce input latency, and you don't pass through objects), but I don't know how that would work for 2D (RigidBody.Sweeptest or something like that for 3d... there's also a sphere/capsule cast).

Thank you for the reply. I did try Fixed update but when it did not change anything i changed it back. I would use addForce as a last resort but I can't seem to get it to work for moving right/left, i can only get it to work for jumping.

I:m doing this::


this.GetComponent<Rigidbody2D>().AddForce(this.transform.right * this.Speed * Time.deltaTime);

I moved my speed up to 5000 from the 5 that I was using with the transform.translate and my character does not move. The only thing I can get to move my player left and right is transform.translate. I even tried using .velocity

If you use a rigidbody and physics, don't manually translate or rotate the gameObject. It will make the physics go haywire. In your case it will mess with the collisions (what you see there most probably is the physics engine finding the rigidbody collider inside another collider in the next physics step and moving it the shortest distance to the edge of the collider it is in, which in case of a fast translation and a low physics framerate can be the wrong side of the collider).

You CAN mix physics and manual translation/rotation, but then you need to handle physics interactions also "manually", which means raycasting to find out if a collider is in the way, and only moving your "rigidbody" the distance to the next collider if it is. Kinda messy, a good way to get rid of rigidbodys altogether if you want to have more control over physics and movement, but when mixed with normal physics its going to be messy.

So the answer in the Unity Answer was correct. If you are using a rigidbody and physics, you should work with forces.

If you like more control over movement (like snappy movement without the physical "lag" that often annoys players in Jump and Runs), why even use physics and rigidbodys? If its just for jumping, you could write your own "jump physics" that calculates the jump arc and translates the player character to the right position every frame... if you want the easy way out, just "activate" physics for the jump, and set the rigidbody to kinematic as soon as the character touches the ground. Of course now you need to handle collisions yourself. But you can normally translate your gameobject without the physics getting in the way. Use gameobject translation when on the ground, and set kinematic to false and apply an upward force when jumping.

For "manual" collision handling, you could try raycasting. As long as the rays are short, and few, performance wise they shouldn't matter at all. Just find the distance to the next collider, and use that information to calculate collisions and keep the character grounded.

EDIT: One thing to also keep in mind: If you are moving your rigidbody over another collider, keep in mind that the physics engine is simulating friction. If that friction is very high, the player character might move slowly or not at all. Check the physics materials used on both colliders.

Thanks for the reply. I might end up writing my own physics but I'm going to try and use addForce first. I figured out why the addForce was not working. I had the Constarints >> Freeze x/y on so tht my character would not topple over. I think i will try creating an empty game object and making the sprite and the collider seprate. Thank you both for the help.

Also of note from the docs:


If the rigidbody has isKinematic set false then it works differently. It works like transform.position=newPosition and teleports the object (rather than a smooth transition).

Also, you want to freeze the rotation if you want your object to not topple over, not freeze it's position.

Thanks! Now my character is not toppling over. I never realized one of those said rotation. I don't know how to mark this as answered but it is. Thanks to everyone for the help!

This topic is closed to new replies.

Advertisement