playMaker

Author Topic: Request for Bound function  (Read 1849 times)

hoyoyo80

  • Full Member
  • ***
  • Posts: 136
Request for Bound function
« on: April 25, 2022, 08:19:48 AM »
Hi all,

I would love to request the bound function as taught in this tutorial
Bound function will get the centre of all object transform in the list.
I would love to implement the above tutorial in my game.

Thanks

PolyMad

  • Hero Member
  • *****
  • Posts: 545
Re: Request for Bound function
« Reply #1 on: April 25, 2022, 04:23:35 PM »
You can do it manually, if you want, it's pretty easy.

Get all the POSITION VECTORS of all the objects.
Split all the X, Y and Z.
Sum all the X into a variable Xsum, and do the same for Y and Z.
Then divide the Xsum by the number of objects, and do the same with the Ysum and Zsum.
Put the 3 values Xsum, Ysum, Zsum in a vector, et voilĂ .

hoyoyo80

  • Full Member
  • ***
  • Posts: 136
Re: Request for Bound function
« Reply #2 on: April 26, 2022, 01:33:13 AM »
TQ Bro. How about the bound.size function, it is use to get the width of the bounded box.

PolyMad

  • Hero Member
  • *****
  • Posts: 545
Re: Request for Bound function
« Reply #3 on: April 26, 2022, 11:11:06 AM »
TQ Bro. How about the bound.size function, it is use to get the width of the bounded box.

You want the bounding box of all the objects?
Even easier: you have to take the minimum and maximum X, Y, and Z of all the obejcts, and put them in a vector  :D

I don't know if there's a ready Math Action with an operator for this, I just scanned but can't find anything that seems to find the highest and lowest values in a list of values, so I would go like this:
- Make an Array with all the X values of the objects.
- Get the first value of the Array and put it in HighX.
- Loop through the Array.
- If HighX value is higher than what is in the Array Index, keep it, and go to the next Item in the Array.
- If the value in the Index of the Array is higher than HighX, replace it.
- This way your HighX will be the highest in the Array when you reach the end.
Do the same for Y and Z, and put them in VectorHIGH.
Do the same for the low of X, Y and Z and put them in VectorLOW.

Now you have 2 vectors with the highest XYZ and lowest XYZ.
Subtract the VectorLOW from the VectorHIGH, and put the results in VectorBoxSIZE.

Now divide VectorBoxSIZE by 2, so you get the center of it, let's call it VectorBoxCENTERRel, because this center is relative to its size, not to the world.

Now you add VectorBoxCENTERRel to VectorLOW and put them in VectorBoxCENTERWorld.

With this data you can now create a bounding box at position VectorBoxCENTERWorld, with size VectorBoxSIZE.

There's probably some way to do this faster and with much more class, but this is what I can do: brute force LOL  ;D
« Last Edit: April 26, 2022, 05:03:49 PM by PolyMad »

cel

  • Full Member
  • ***
  • Posts: 132
Re: Request for Bound function
« Reply #4 on: April 27, 2022, 05:53:02 PM »
something like this??

Code: [Select]
using System.Collections;
using System.Collections.Generic;

using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
[Tooltip("Makes the camera follow diferent targets")]
[ActionCategory("Camera")]
public class multiTargetCamera : FsmStateAction
{

[RequiredField]
[Tooltip("The camera to use")]
public FsmOwnerDefault camera;


[Tooltip("Targets to track")]
public FsmGameObject[] targets;

public FsmVector3 offSet;

public FsmFloat  smoothTime;

private Vector3 velocity;

public FsmFloat minZoom;
public FsmFloat maxZoom;
public FsmFloat zoomLimiter;


private Camera camera2;
private GameObject obj;



        public override void Reset()
        {
targets = null;
camera = null;
offSet = null;
smoothTime = 0.3f;
minZoom = 80;
maxZoom = 20;
zoomLimiter = 50;


}



        public override void OnPreprocess()
{

Fsm.HandleLateUpdate = true;
}

public override void OnEnter()
{
var camera1 = Fsm.GetOwnerDefaultTarget(camera);
camera2 = camera1.GetComponent<Camera>();

}

        public override void OnLateUpdate()
        {
if (targets.Length == 0)

return;
move();
zoom();

        }
void zoom()
        {


float newzoom = Mathf.Lerp(maxZoom.Value, minZoom.Value, GetGreatestDistance() / zoomLimiter.Value);
camera2.fieldOfView = Mathf.Lerp(camera2.fieldOfView, newzoom, Time.deltaTime);
        }

void move()
        {
Vector3 centerpoint = GetCenterPoint();
Vector3 newposition = centerpoint + offSet.Value;
camera2.transform.position = Vector3.SmoothDamp(camera2.transform.position, newposition, ref velocity, smoothTime.Value);

        }

float  GetGreatestDistance()
        {

var bounds = new Bounds(targets[0].Value.GetComponent<Transform>().position, Vector3.zero);
for (int i = 0; i < targets.Length - 1; i++)
{

bounds.Encapsulate(targets[i].Value.GetComponent<Transform>().position);

}

return bounds.size.x;
}
Vector3 GetCenterPoint()

        {
if (targets.Length == 1)

            {

return targets[0].Value.GetComponent<Transform>().position;
            }



var bounds = new Bounds(targets[0].Value.GetComponent<Transform>().position, Vector3.zero);

for (int i = 0; i< targets.Length -1; i++)
            {


bounds.Encapsulate(targets[i].Value.GetComponent<Transform>().position);
            }

return bounds.center;
        }

    }

}


see if it works for you

hoyoyo80

  • Full Member
  • ***
  • Posts: 136
Re: Request for Bound function
« Reply #5 on: April 28, 2022, 01:08:26 AM »
Wow..that is quick bro. Thanks and will try that

cel

  • Full Member
  • ***
  • Posts: 132
Re: Request for Bound function
« Reply #6 on: April 28, 2022, 05:16:17 PM »
made a few changes.... targets are now defined in an array variable, that you can change or add to it at runtime.... also added the options for update... recommended is late update

Code: [Select]
using System.Collections;
using System.Collections.Generic;

using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
[Tooltip("Makes the camera follow diferent targets")]
[ActionCategory("Camera")]
public class multiTargetCamera : FsmStateAction
{

[RequiredField]
[Tooltip("The camera to use")]
public FsmOwnerDefault camera;


[Tooltip("Targets to track")]
[ArrayEditor(VariableType.GameObject)]
public FsmArray targets1;

public FsmVector3 offSet;

public FsmFloat  smoothTime;

private Vector3 velocity;

public FsmFloat minZoom;
public FsmFloat maxZoom;
public FsmFloat zoomLimiter;


private Camera camera2;


public enum everyFrameOptions { Update, FixedUpdate, LateUpdate };


[Tooltip("Defines how to perform the action when 'every Frame' is enabled.")]
public everyFrameOptions everyFrameOption;

public override void Awake()
{

switch (everyFrameOption)
{
case everyFrameOptions.FixedUpdate:
Fsm.HandleFixedUpdate = true;
break;
case everyFrameOptions.LateUpdate:
Fsm.HandleLateUpdate = true;
break;

}

}

public override void Reset()
        {
targets1 = null;
camera = null;
offSet = null;
smoothTime = 0.3f;
minZoom = 80;
maxZoom = 20;
zoomLimiter = 50;


}



     

public override void OnEnter()
{
var camera1 = Fsm.GetOwnerDefaultTarget(camera);
camera2 = camera1.GetComponent<Camera>();

}

public override void OnUpdate()
{
if (everyFrameOption == everyFrameOptions.Update)

{
if (targets1.Length == 0)

return;
move();
zoom();

}

}

public override void OnFixedUpdate()
{
if (everyFrameOption == everyFrameOptions.FixedUpdate)

{
if (targets1.Length == 0)

return;
move();
zoom();

}

}

public override void OnLateUpdate()
        {
if (everyFrameOption == everyFrameOptions.LateUpdate)

{
if (targets1.Length == 0)

return;
move();
zoom();

}

        }
void zoom()
        {


float newzoom = Mathf.Lerp(maxZoom.Value, minZoom.Value, GetGreatestDistance() / zoomLimiter.Value);
camera2.fieldOfView = Mathf.Lerp(camera2.fieldOfView, newzoom, Time.deltaTime);
        }

void move()
        {
Vector3 centerpoint = GetCenterPoint();
Vector3 newposition = centerpoint + offSet.Value;
camera2.transform.position = Vector3.SmoothDamp(camera2.transform.position, newposition, ref velocity, smoothTime.Value);

        }

float  GetGreatestDistance()
        {


var getvalue = targets1.Get(0) as GameObject;
var bounds = new Bounds(getvalue.transform.position, Vector3.zero);
for (int i = 0; i < targets1.Length - 1; i++)
{
getvalue = targets1.Get(i) as GameObject;
bounds.Encapsulate(getvalue.transform.position);

}

return bounds.size.x;
}
Vector3 GetCenterPoint()

        {
if (targets1.Length == 1)

            {
var getvalue = targets1.Get(0) as GameObject;
return getvalue.transform.position;
}

var getvalue1 = targets1.Get(0) as GameObject;
var bounds = new Bounds(getvalue1.transform.position, Vector3.zero);


for (int i = 0; i< targets1.Length -1; i++)
            {

getvalue1 = targets1.Get(i) as GameObject;
bounds.Encapsulate(getvalue1.transform.position);
}

return bounds.center;
        }

    }

}

hoyoyo80

  • Full Member
  • ***
  • Posts: 136
Re: Request for Bound function
« Reply #7 on: April 30, 2022, 02:22:33 AM »
Hi cel.It kinda work. It is possible to use it with cinemachine virtual camera?On regular camera it works good.

Thanks

hoyoyo80

  • Full Member
  • ***
  • Posts: 136
Re: Request for Bound function
« Reply #8 on: May 04, 2022, 03:45:31 AM »
Hi all. For cinemachine, there is already a builtin playmaker action to target group using the virutal camera. We only need to supply the array of objects to be add as target.

But i will leave this request on for those  who is not using cinemachine. As for cel and Polymad, thanks for the hint and action(cel).