Forum rules - please read before posting.

Adjusting the PickUp component plus question re performance

I want to allow the player to pick up large-ish items and move them around (and new positions to save between loads and saves). I've added the Pickup component and if I click and hold the player does pick up the object.
However, there are some behaviours I'd like to change:-

  1. Clicking once to pick up the object immediately results in the player dropping the object again. I'd prefer if it just remained held.
  2. When I click and hold instead, the object is held too high. How can I have it held lower? (Does this relate to prefab's pivot position?)
  3. When I turn and look around, the object rotation doesn't change, whereas I need the player to position and orientate things like lights and cameras to point in different directions. I don't need the rotation feature.

If I need to code my own pickup script, how can I be sure the new position is saved when the player reloads his save?

Also, the game will essentially be a large house and be one scene. Do you think I will have performance issues with several hundred interactive AC objects?

Thanks.

Comments

  • edited December 2021

    Welcome to the community, @redmotion.

    Hopefully the majority of these can be incorporated through the use of add-on script(s) that work with the existing PickUp system - avoiding the need to replace things.

    Clicking once to pick up the object immediately results in the player dropping the object again. I'd prefer if it just remained held.

    The built-in behaviour is for draggables to be held while holding an input down, but this can be overridden through the use of a custom script.

    This script on the AC wiki, for example, delegates dragging to separated inputs.

    When I click and hold instead, the object is held too high. How can I have it held lower? (Does this relate to prefab's pivot position?)

    When held, a PickUp will move it's Rigidbody's position to the cursor's position in world-space. You can override this, however, by calling the PickUp component's OverrideMoveToPosition function.

    Here's a sample script that should handle both of the above:

    using UnityEngine;
    using AC;
    
    [DefaultExecutionOrder (100)]
    public class ForceGrab : MonoBehaviour
    {
    
        public Vector3 heldOffset = new Vector3 (0f, 1f, 0f);
        private Moveable_PickUp pickUp;
        private bool isHeld;
        private bool letGoOnce;
    
    
        private void OnEnable ()
        {
            pickUp = GetComponent<Moveable_PickUp> ();
            EventManager.OnGrabMoveable += OnGrabMoveable;
            EventManager.OnDropMoveable += OnDropMoveable;
        }
    
    
        private void OnDisable ()
        {
            EventManager.OnGrabMoveable -= OnGrabMoveable;
            EventManager.OnDropMoveable -= OnDropMoveable;
        }
    
    
        private void Update ()
        {
            if (Input.GetMouseButtonDown (0) && !isHeld)
            {
                pickUp.Grab (pickUp.transform.position);
            }
            else if (Input.GetMouseButtonUp (0) && isHeld)
            {
                if (!letGoOnce)
                {
                    letGoOnce = true;
                }
                else
                {
                    pickUp.LetGo ();
                }
            }
    
            if (isHeld)
            {
                pickUp.OverrideMoveToPosition (pickUp.GetWorldMousePosition () + heldOffset);
            }
        }
    
    
        private void OnGrabMoveable (DragBase dragBase)
        {
            if (pickUp == dragBase)
            {
                KickStarter.playerInput.GetHeldObjectData (dragBase).IgnoreDragState = true;
                isHeld = true;
                letGoOnce = false;
            }
        }
    
    
        private void OnDropMoveable (DragBase dragBase)
        {
            if (pickUp == dragBase)
            {
                isHeld = false;
            }
        }
    
    }
    

    Quick note: for this to compile, you'll have to open up AC's Moveable_PickUp script and change its GetWorldMousePosition function from protected to public. I shall make the same change to the next release.

    This script relies on the OnGrabMoveable and OnDropMoveable custom events. More on custom events, which provide a means to run custom code when AC performs common tasks, can be found here.

    When I turn and look around, the object rotation doesn't change, whereas I need the player to position and orientate things like lights and cameras to point in different directions. I don't need the rotation feature.

    It should be possible to update the Rigidbody's rotation by calling MoveRotation in a separate script, using the same events as above to limit this call to only when a PickUp is held.

    Calculating exactly what rotation to set this to, though, is a little tricky. I shall give it some thought, however.

    If I need to code my own pickup script, how can I be sure the new position is saved when the player reloads his save?

    To save data related to a scene object in save games, attach a Remember component. The Remember Transform component, for example, stores information about that object's Transform.

    For more on Remember components, see the Manual's "Saving scene objects" chapter. A tutorial on writing a custom Remember component can be found here.

    Also, the game will essentially be a large house and be one scene. Do you think I will have performance issues with several hundred interactive AC objects?

    When an AC object isn't being used, it's performance impact shouldn't be too large. I'd say it's more a question of what physics-related components are involved - i.e. if all of these have Rigidbodies. This would impact performance regardless of AC's involvement, however.

  • edited December 2021

    Thanks, for the reply Chris. got positive on a covid test shortly after reading this reply, so haven't had a chance to look at it until now. Seem to be recovering ok.

    This is great. I've added the ForceGrab script to the light plus a short bit of code to control the rotation as I needed it:

    In Update I modified the script as follows:-

        if (isHeld) {
                pickUp.OverrideMoveToPosition (pickUp.GetWorldMousePosition () + heldOffset);
                Quaternion rot = FindObjectOfType<Camera>().transform.rotation;
                Vector3 v3_r = rot.eulerAngles;
                pickUp.transform.rotation = Quaternion.Euler(0f,v3_r.y,v3_r.z);
        }   
    

    Is there a more efficient way to get the camera transform? Does AC store a global reference to it in the scene/global variables at all? I know FindObject style methods are not great to use like this!

    Many thanks again.

  • I just noticed that clicking the mouse anywhere - even in the air, facing the opposite direction - jolts the object with the ForceGrab script towards the player. You can continue to click until the object moves close enough to be picked up.

    Adding if (!isHeld) return; at the top of ForceGrab:Update() fixed this issue.

  • Seem to be recovering ok.

    I'm relieved to hear it!

    Is there a more efficient way to get the camera transform?

    Yes - you can get the MainCamera's transform directly with:

    AC.KickStarter.CameraMainTransform
    

    The MainCamera is the one you'll want to read - other cameras (such as GameCameras) that are in the scene won't necessarily be facing the correct direction.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.