How to set a mass of mesh of an actor (Blueprint or C++)? - unreal-engine4

I'm creating an actor that has a static mesh component. I want to acess that static mesh mass and override it to a variable. I've tried Set All Mass Scale, Set Mass Scale, Set Mass Override. In the last two it asks for a bone name, which I don't understand as I work with a static mesh not a skeletal mesh. None of three seem to do anything. How to set a mesh mass inside of an actor class (preferrably in the costructor) in UE5/4?

Example from here:
void AYourStaticMeshActorClass::SetMassScale(const float& NewScale)
{
if(!StaticMeshComponent) return;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FBodyInstance* BodyInst = StaticMeshComponent->GetBodyInstance();
if(!BodyInst) return;
//~~~~~~~~~~~~~~~~~~~~~~~~
// New Scale
BodyInst->MassScale = NewScale;
// Trigger Update!
BodyInst->UpdateMassProperties();
}

Related

How to make Trajectory Predictor on my ball?

hey guys , So as you can see i made a robot arm grab a slingshot's objectholder with a ball in it. My arm pulls it any direction I want it but I wanted the user to know which box is going to be shot at.
If you're applying an impulse force (or velocity) to your ball and there is gravity in your world, your item will follow the Projectile motion;
Here you can find details about it:
https://en.wikipedia.org/wiki/Projectile_motion
There are basically two main options
calculating it yourself
This is probably way better for performance especially if you want a really simple trajectory preview without accounting for any collision etc
refer to linked article. But it basically comes down to
and would need slightly rework from 2D to 3D physics, should be trivial though since the important part about the Y axis basically stays the same.
You would
Call this simulation with according supposed shoot direction and velocity
Visualize the tracked positions e.g. in a LineRenderer
Physics.Simulate
This allows you to run physics updates manually all within a single frame and actually let the Physics engine handle it all for you
This costs of course a lot of performance but you get all collisions etc accounted for automatically without getting a headache
You would
Make a snapshot of all Rigid bodies in your scene - in order to reset after the simulation
Simulate the desired amount of physics steps (XY seconds ahead) while keeping track of the simulated data
reset everything to the state tracked in step 1
use the simulated data from step 2 to visualize e.g. with a LineRenderer
This might look somewhat like e.g.
public class Prediction : MonoBehaviour
{
public LineRenderer line;
public Rigidbody tracked;
private Rigidbody[] allRigidbodies;
private void Awake()
{
allRigidbodies = FindObjectsOfType<Rigidbody>();
}
private void LateUpdate()
{
// Wherever you would get this from
Vector3 wouldApplyForce;
// Step 1 - snapshot
// For simplicity reasons for now just the positions
// using some Linq magic
var originalPositions = allRigidbodies.ToDictionary(item => item, item => item.position);
// Step 2 - Simulate e.g. 2 seconds ahead
var trackedPositions = new Vector3 [(int) (2 / Time.fixedDeltaTime)];
Physics.autoSimulation = false;
tracked.AddForce(wouldApplyForce);
for(var i = 0; i < trackedPositions.Length; i++)
{
Physics.Simulate(Time.fixedDeltaTime);
trackedPositions[i] = tracked.position;
}
// Step 3 - reset
foreach (var kvp in originalPositions)
{
kvp.Key.position = kvp.Value;
}
Physics.autoSimulate = true;
// Step 4 - Visualize
line.positionCount = trackedPositions.Length;
line.SetPositions(trackedPositions);
}
}
Of course we won't talk about performance here ^^

How do I convert Mesh to MeshFilter in unity

Hi I am making a Generation Game In unity, and I have custom meshes and I wanted a function to convert Mesh to MeshFilters in the fastest way cause this function will get a input of a Array of Meshes and the output will be a Array of MeshFilters.
Thanks :)
This should be pretty streight forward.
In general you don't simply "create" MeshFilters. You rather attach them to a GameObject. There are bascially three ways to do so:
use AddComponent in order to attach it to an existing object
use Instantiate in order to create a clone instance of an existing prefab
use the constructor of GameObject and pass the according type(s) in as parameters
And well then just assign your Mesh to MeshFilter.sharedMesh or MeshFilter.mesh in this case where you assign the entire mesh it shouldn't really make a difference.
So you could e.g. simply do
// Needed for option B - see below
//[SerializeField] private MeshFilter preparedPrefab;
public MeshFilter[] CreateObjects(Mesh[] meshes)
{
var amount = meshes.Length;
var meshFilters = new MeshFilter[amount];
for(var i = 0; i < amount; i++)
{
// here you have multiple options
// A - create a new empty GameObjects with the MeshFilter component
meshFilters[i] = new GameObject("someName" /*, typeof(MeshRenderer), etc*/).AddComponent<MeshFilter>();
// B - Rather already prepare a prefab/template which contains all the components you need
// in particular you might also want a MeshRenderer in roder to see your objects
// and e.g. MeshCollider in order to apply physics and raycasting to your objects
//meshFilter[i] = Instantiate(prapredPrefab);
meshFilter[i].sharedMesh = meshes[i];
}
return meshFilters;
}
Note that a Mesh itself has no information about any position, rotation, scale and child-parent relationships in your scene. For this you would need more information.

Unity3D How can I select multiple objects in 3D with a drag and select / lasso select?

I am struggling to find a good tutorial or informations that would allow me to select multiple objects in 3D in a user friendly manner.
So far, the best tutorial I found is this one : https://sharpcoderblog.com/blog/unity-3d-rts-style-unit-selection. The tutorial works by using the transform.position of the selectable objects and checking if it within the user's selection.
What I wish is to have the user be able to select a unit even if it is only partially within the user's selection such as most RTS games do ( both in 2D and 3D ).
One possibility would be to create a temporary mesh using the camera's clipping distances and the user's selection and then check for collisions but I was not able to find any tutorials using this method nor do I know if it is the best approach to the subject.
If I understand correctly you want to
somehow start a selection
collect every object that was "hit" during the collection
somehow end the collection
Couldn't you simply use raycasting? I will assume simple mouse input for now but you could basically port this to whatever input you have.
// Just a little helper class for an event in the Inspector you can add listeners to
[SerializeField]
public class SelectionEvent : UnityEvent<HashSet<GameObject>> { }
public class SelectionController : MonoBehaviour
{
// Adjust via the Inspector and select layers that shall be selectable
[SerializeField] private LayerMask includeLayers;
// Add your custom callbacks here either via code or the Inspector
public SelectionEvent OnSelectionChanged;
// Collects the current selection
private HashSet<GameObject> selection = new HashSet<GameObject>();
// Stores the current Coroutine controlling he selection process
private Coroutine selectionRoutine;
// If possible already reference via the Inspector
[SerializeField] private Camera _mainCamera;
// Otherwise get it once on runtime
private void Awake ()
{
if(!_mainCamera) _mainCamera = Camera.main;
}
// Depending on how exactly you want to start and stop the selection
private void Update()
{
if(Input.GetMouseButtonDown(0))
{
StartSelection();
}
if(Input.GetMouseButtonUp(0))
{
EndSelection();
}
}
public void StartSelection()
{
// if there is already a selection running you don't wanr to start another one
if(selectionRoutine != null) return;
selectionRoutine = StartCoroutine (SelectionRoutine ());
}
public void EndSelection()
{
// If there is no selection running then you can't end one
if(selectionRoutine == null) return;
StopCoroutine (selectionRoutine);
selectionRoutine = null;
// Inform all listeners about the new selection
OnSelectionChanged.Invoke(new HashSet<GameObject>(selection);
}
private IEnumerator SelectionRoutine()
{
// Start with an empty selection
selection.Clear();
// This is ok in a Coroutine as long as you yield somewhere within it
while(true)
{
// Get the ray shooting forward from the camera at the mouse position
// for other inputs simply replace this according to your needs
var ray = _mainCamera.ScreenPointToRay(Input.mousePosition);
// Check if you hit any object
if(Physics.Raycast(ray, out var hit, layerMask = includeLayers ))
{
// If so Add it once to your selection
if(!selection.Contains(hit.gameObject)) selection.Add(hit.gameObject);
}
// IMPORTANT: Tells Unity to "pause" here, render this frame
// and continue from here in the next frame
// (without this your app would freeze in an endless loop!)
yield return null;
}
}
}
Ofcourse you could do it directly in Update in this example but I wanted to provide it in a way where you can easily exchange the input method according to your needs ;)
From UX side you additionally might want to call a second event like OnSelectionPreviewUpdate or something like this every time you add a new object to the selection in order to be able to e.g. visualize the selection outcome.
I might have understood this wrong and it sounds like you rather wanted to get everything inside of a drawn shape.
This is slightly more complex but here would be my idea for that:
Have a dummy selection Rigidbody object that by default is disabled and does nothing
don't even have a renderer on it but a mesh filter and mesh collider
while you "draw" create a mesh based on the input
then use Rigidbody.SweepTestAll in order to check if you hit anything with it
Typed on smartphone but I hope the idea gets clear
I think I would try to create a PolygonCollider2D because it is quite simple comparing to creating a mesh. You can set its path (outline) by giving it 2D points like location of your pointer/mouse. Use the SetPath method for it. You can then use one of its methods to check if another point in space overlaps with that collider shape.
While the PolygonCollider2D interacts with 2D components you can still use its Collider2D.OverlapPoint method to check positions/bounds of your 3D objects after translating it to 2D space.
You can also use its CreateMesh method to create a mesh for drawing your selection area on the screen.
You can read more about the PolygonCollider2D here.
Hope it makes sens and hope it helps.

Multiple PlotCube synchronization

Multiple ILPlotCubes in the same ILScene react independent to mouse interaction. Docu example here.
Each of my PlotCubes contains one LinePlot and I need to keep the X-Axis of both PlotCubes aligned. Therefore an event is needed that notifies me when the X-Axis in one PlotCube is changed due to mouse interaction.
Couldn't find anything in the documentation or search engines. Did some limited testing with mouse events (complicated, possible ?). Found a ILAxisChangedEventArgs class, but no event.
Use ILPlotCube.Limits instead! The ILLimits class manages the axis limits for a plotcube. It provides the Changed event. You can use that in order to reflect changes to other plot cubes.
private void ilPanel1_Load_1(object sender, EventArgs e) {
// just some data
ILArray<float> A1 = new float[] { 1,4,3,2,5 };
// setup new plot cube
var pc1 = ilPanel1.Scene.Add(new ILPlotCube("pc1") {
ScreenRect = new RectangleF(0,0,1,.6f)
});
// 2nd plot cube
ILArray<float> A2 = new float[] { -1,-4,-3,-2,4 };
var pc2 = ilPanel1.Scene.Add(new ILPlotCube("pc2") {
ScreenRect = new RectangleF(0, .4f, 1, .6f)
});
// add line plots to the plot cubes
pc1.Add(new ILLinePlot(A1));
pc2.Add(new ILLinePlot(A2));
// Synchronize changes to the limits property
// NOTE: mouse interaction is fired on the SYNCHRONIZED COPY
// of the plot cube, which is maintained for each individual ILPanel!
pc1 = ilPanel1.SceneSyncRoot.First<ILPlotCube>("pc1");
pc2 = ilPanel1.SceneSyncRoot.First<ILPlotCube>("pc2");
pc1.Limits.Changed += (_s, _a) => { SynchXAxis(pc1.Limits, pc2.Limits); };
pc2.Limits.Changed += (_s, _a) => { SynchXAxis(pc2.Limits, pc1.Limits); };
}
private void SynchXAxis(ILLimits lim1, ILLimits lim2) {
// synch x-axis lim1 -> lim2
Vector3 min = lim2.Min;
Vector3 max = lim2.Max;
min.X = lim1.XMin; max.X = lim1.XMax;
// disable eventing to prevent from feedback loops
lim2.EventingSuspend();
lim2.Set(min, max);
lim2.EventingStart(); // discards Changed events
}
Now, when you zoom / pan with the mouse, changes to one plot cube gets transferred to the other plot cube. This acts on the X axes only. Other limits will not be affected.
Two Hints
1) Keep in mind that mouse interaction does not affect the original plot cube object you created but instead change a synchronized copy of it. The copy is maintained by the ILPanel internally and prevents from multithreading issues as well as from changes to one instance populating back to other instances which may existing in other panels. In order to get informed about those changes, you must wire up to the event handler of the synchronized copy. ILPanel.SceneSynchRoot provides you access.
2) When transferring the changes from the Limits of one plot cube to the other one should disable the eventing on the target limits object. Otherwise, it would trigger another Changed event and the events would fire endlessly. The ILLimits.EventingStart() function reenables the eventing after your changes and discards all events accumulated so far.

Rotating a tower nozzle mesh in unity3D

I am making my first game in Unity 3D something like tower defense game. I have imported a Fbx model of a tower and attached it to a prefab. Now I want the nozzle of the tower to rotate and follow the enemy as the enemy passes by .
In the fbx model i imported i got I have two poly meshes one for the base of the tower that is fixed, and one for the top of the tower that will rotate. Now I tried to create two different gameObject with these two meshes but if I put them on same point they overlap. So I have to do manual alignment such that the nozzle sit correctly over the base.
I was wondering if there is any other way such that entire towers remain is one gameObject and I can rotate the upper part.
I did manage to solve my problem. Not sure if was the best way , but it works.
To upgrade the towers and transform only the nozzle part I essentially did this.
public class tryFbx : MonoBehaviour {
public GameObject[] ModelPrefab;
GameObject modelInstance;
Renderer rn = new Renderer();
// Attaching the model to prefab at runtime by creating a array of prefabs
public void AttachModelToPrefab(GameObject modelPrefab) {
modelInstance = GameObject.Instantiate(modelPrefab) as GameObject;
modelInstance.transform.position = transform.position;
modelInstance.transform.rotation = transform.rotation;
// Attach the model instance to the prefab shell
modelInstance.transform.parent = gameObject.transform;
}
void Start () {
}
// Update is called once per frame
void Update () {
if (GameManager.upgrade){
AttachModelToPrefab(ModelPrefab[GameManager.towerUpgradeLevel]);
foreach ( Renderer r in modelInstance.GetComponentsInChildren<Renderer>()){
// "polySurface98" is the name of the mesh I want to rotate. The tower and its upgrade have the same name.
if (r.name == "polySurface98")
rn = r;
}
// apply any transformation to the partial fbx
rn.transform.Translate(1,1,1);
}
}
}
You can create a hierarchy of GameObjects; you'll have one parent GameObject representing the tower and 2 children, being that you rotate one of them. Note that the coordinates of the children will be in relation to the parent's, so any "messy" manual calibration you make on the children will be contained.
Or, more complicated, you can create only one mesh that has an animation and apply it to one GameObject.