I’m trying to create a rigidbody game object of a piston that will extend at a certain speed up to a certain position when the player contacts it, and then retract back to its starting position after the player is no longer contacting it. I created an empty game object, and as children I created a cube (with its colliders turned off so as to not interfere with the cylinder), and then a cylinder. I added a rigid body to the cylinder. Here’s my code for the script attached to the cylinder.
using UnityEngine;
using System.Collections;
public class Piston : MonoBehaviour {
public float speed;
private bool pistonExtend;
// Use this for initialization
void Start () {
pistonExtend = false;
}
// Update is called once per frame
void Update () {
Debug.Log ("pistonExtend = " + pistonExtend);
//Debug.Log ("velocity = " + rigidbody.velocity);
if (pistonExtend == true & transform.position.y < 0.5f) {
rigidbody.MovePosition(rigidbody.position+Vector3.up * speed * Time.deltaTime);
//Debug.Break();
}
if(pistonExtend == false & transform.position.y > 0.0f)
{
Debug.Log("I should be retracting");
//rigidbody.MovePosition(rigidbody.position+Vector3.down * speed * Time.deltaTime);
rigidbody.MovePosition(Vector3.zero);
}
}
void OnCollisionEnter(Collision other){
if (other.gameObject.tag == "Player") {
pistonExtend=true;
}
}
void OnCollisionExit(Collision other){
if (other.gameObject.tag == "Player") {
pistonExtend=false;
}
}
}
It works halfway. When the player contacts the cylinder, it extends, but extends past the point where the code was to have it stop extending. And then when it retracts, it snaps back but not to the zero point in the code. It usually snaps back to a point in the y0.5-0.8 range, even though its move position should be to vector3.zero.
When I step through 1 frame at a time after extension, the piston sits at its weirdly offset retracted position steadily. However, if I let it run full speed, it bounces between its offset retracted position and another position lower (but not zero).
As far as I can tell, my code logic should be correct. I’ve tried many other methods to try and get this to work, but none get as close as this. I’ve tried update, fixedupdate, and lateupdate. All produce identical behavior. What am I doing wrong?
OK. Thanks so much to robertbu for helping me work this out. My final implementation is a little bit different than what I was initially going for. The point of the piston object was to propel the player using physics when the play made contact. This was very difficult to fine tune between bounciness of the player physics material and the rate the piston was extending. I ultimately decided to just have the piston directly change the players velocity instead of using the rigidbody collision to propel the player. Here’s the code now.
using UnityEngine;
using System.Collections;
public class Piston : MonoBehaviour {
public float speedExtend; // speed piston extends
public float speedRetract; // speed piston retracts
public float timeExtended; // time in seconds piston should remain extended before retracting
public Vector3 jumpspeed = new Vector3 (0, 10, 0); // player's vertical speed when piston is triggered
private bool pistonExtend; // boolean to tell script to extend piston
private float timeLeft; // variable to hole amount of time left before piston retracts
private bool extended; // boolean to denote if piston is in an extended state
private Quaternion orientation; //get worldspace orientation to make piston object work in any orientation
// Use this for initialization
void Start () {
pistonExtend = false;
extended = false; //piston starts retracted
timeLeft = timeExtended; //set time remaining to total time
}
// Update is called once per frame
void FixedUpdate () {
orientation = transform.rotation; //set orientation quat during update so it can move in the world and always work
if (pistonExtend == true) { //do this when we want to extend
if(transform.localPosition.y <= 0.5f){ // extend until we reach this position
rigidbody.MovePosition(rigidbody.position+orientation*Vector3.up * speedExtend * Time.deltaTime);
extended = true;
}
timeLeft = timeLeft-Time.deltaTime; // start counting down
if(timeLeft<0f){
pistonExtend=false; //when time runs out, set the retract flag
}
}
if(pistonExtend == false & transform.localPosition.y >= 0.1f) //retract back to start position
{
rigidbody.MovePosition(rigidbody.position+orientation*Vector3.down * speedRetract * Time.deltaTime);
timeLeft = timeExtended; //reset extended time
extended = false;
}
}
void OnTriggerEnter(Collider other){
if (other.gameObject.tag == "Player" && extended == false) {
pistonExtend=true;
other.rigidbody.velocity = orientation * jumpspeed; //set player velocity according to orientation
}
}
}
Changing from “update” to “FixedUpdate” solved my weird overtravel issues. Thanks again.