Back and forth movement using Rigidbody2D movePosi

2019-08-17 15:02发布

问题:

I have two force fields I & II (Image here - https://i.stack.imgur.com/yXAhQ.png). They both have an attached script with a bool 'repel', which is toggled on MouseDown(). These force fields need to either attract or repel a spaceship directly in its path. The actual movement of the ship is done by raycasting right & down from the ship. These raycasts check the 'repel' bool of the force fields and the ship is then either moved away or towards the force fields. All gameObjects are Kinematic.

I need to be able to move the ship back and forth between the force fields by toggling their 'repel' bools. This was working fine by using transform.Translate to move the ship. However, collisions were buggy, so I decided to use Rigidbody2D.MovePosition instead.

Now, the ship can move towards ForceField I and when it detects ForceField II, it changes its course along a vertical line, which is what I want. BUT, it can no longer move towards or away from ForceField I when it detects it along the X axis ray. So, the ship can now only move up and down. How do I keep the ship moving between the force fields?

Here's the code attached to the ship -

using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;

 public class shipRays_test : MonoBehaviour {

             public float rayDistance = 100;
             public Vector2 Xspeed;
             public Vector2 Yspeed;

             private polarityScript polarityright;
             private polarityScript polaritydown;
             private Rigidbody2D rb;

             void Start()
             {
                 rb = GetComponent<Rigidbody2D>();
             }  

             void FixedUpdate ()
             {
                 Debug.DrawRay (transform.position, Vector2.right * rayDistance, Color.red);
                 RaycastHit2D rightHit = Physics2D.Raycast (transform.position, Vector2.right, rayDistance);

                 Debug.DrawRay (transform.position, Vector2.down * rayDistance, Color.green);
                 RaycastHit2D downHit = Physics2D.Raycast (transform.position, Vector2.down, rayDistance);

                 if (rightHit.collider != null) 
                 {
                     if (rightHit.collider.CompareTag ("forceField"))
                     {    
                         polarityright = rightHit.collider.gameObject.GetComponent<polarityScript > ();
                         if (polarityright.repel) 
                         {
                             rb.MovePosition (rb.position - Xspeed * Time.fixedDeltaTime);      
                         }
                         else if (!polarityright.repel)
                         {
                             rb.MovePosition (rb.position + Xspeed * Time.fixedDeltaTime);
                         }
                     }
                 }

                 if (downHit.collider != null)
                 {
                     if (downHit.collider.CompareTag ("forceField"))
                     {
                         polaritydown= downHit.collider.gameObject.GetComponent<polarityScript >();
                         if (polaritydown.repel)
                         {
                             rb.MovePosition (rb.position + Yspeed * Time.fixedDeltaTime);
                         }
                         else if (!polaritydown.repel)
                         {
                             rb.MovePosition (rb.position - Yspeed * Time.fixedDeltaTime);
                         }
                     }
                 }
             }
 }

回答1:

Apparently Rigidbody.MovePosition() stores the value passed and interpolates over frames, each invocation overwriting the previous value, during which time Rigidbody.position does not change. This isn't noted in the documentation at all (or at least not well), but there's the rub.

To fix this you need to create a variable to hold the desired new position yourself, adding to it as your logic flow and only at the end calling MovePosition().

So you'd have to set things up like this:

Vector3 newPos = rb.position;
 if (rightHit.collider != null) 
 {
     //...
         {
             newPos -= Xspeed * Time.fixedDeltaTime;      
         }
     //...
 }

 if (downHit.collider != null)
 {
     //...
         {
             newPos += Yspeed * Time.fixedDeltaTime;      
         }
     //...
 }
 rb.MovePosition(newPos);