I'm working on a Unity game. In it, I want to be able to give different entities different degrees of friction without creating multiple materials in the editor. I'm currently trying to do this by defining a PhysicsMaterial2D as a member variable and instantiating it in the Start method. The material's friction is then applied based on a public member variable. I then set the actor's collider2D's sharedMaterial.
public class ActorUpdateScript : MonoBehaviour {
public float friction;
PhysicsMaterial2D actorMaterial;
void Start () {
actorMaterial = new PhysicsMaterial2D();
actorMaterial.friction = friction;
collider2D.sharedMaterial = actorMaterial;
}
}
I can verify that collider2D.sharedMaterial is indeed receiving the new material, as I can print it's friction and it gives me the expected result. However, no matter what number I give it's friction, it always behaves like the default material. (0.4 friction I believe). The collision boxes he's walking on all have a material with a friction of 1.
What am I doing wrong? Does anyone have any suggestions on how to make unity pay attention to the material I've applied?
Also, before you tell me, I know I can have different materials (high friction, medium friction, low friction, etc) that I apply to different entities. But I'm planning on eventually adding super basic modding support, so the friction for a given entity will be set with a JSON file.
The problem is probably that you have a physics material on both your character and the floor and the combine method is to take the smaller of the two, you will always get the lower value.
To fix this you either remove the physics material from the character, set it high enough it always gets overwritten or change it depending on what you are standing on to alway get the correct behavior.
void Start () {
actorMaterial = new PhysicsMaterial2D();
collider2D.sharedMaterial = actorMaterial;
collider2D.sharedMaterial.friction = friction;
}
Assign new material to collider.sharedMaterial first.
And change material value.
It works for me.
Related
I created my first shader by following this video. Dissolve Shader Video Link
In a Coroutine,i took the Material's component from the object:
PalaceMaterial = palaceInstance.GetComponent <Renderer> () .material;
I set the parameter to 0:
PalaceMaterial.SetFloat ("_ CutoffHeight", 0);
To have this effect, I had to modify the parameter "CuttoffHeight" gradually
putting it in Update ()
PalaceMaterial.SetFloat("_CutoffHeight", Mathf.MoveTowards(PalaceMaterial.GetFloat("_CutoffHeight"), CutoffHeight, 100 * Time.deltaTime));
I applied this to all objects.
Every 2 seconds i instantiate an "invisible object" (CutoffHeight
set to 0)
and in Update() it change the value gradually.
Now I would like to change this parameter to all objects that use this shader simultaneously.
I hope i was clear.
Video of my project :
Project, Dissolve_Effect
I would like to change the "_CutoffHeight" parameter simultaneously in all the cubes that are in the first platform, then in the second one, etc. etc.
Do you have any idea?
In general you shouldn't additionally use GetFloat but rather store the value locally and calculate it from there.
Then this already should work if multiple objects share the exact same material by using e.g.
GetComponent<Renderer>().sharedMaterial.SetFloat(...);
but this works only as long as you don't have multiple instances of the material in your renderers.
There is a way to set a property for all Shaders (which have that property) and their according instances (= Materials) I came across in this thread
To do this you have to
Disable "exposed" for the according property. Apparently it only works for properties that are not exposed in the Inspector.
Use the generated shader property ID you can find in the Inspector of the shader asset itself.
You can also retrieve it using Shader.PropertyToID
You can also change it to match your actual parameter name.
Use the global setter methods of the shader like Shader.SetGlobalXY
e.g. in order to set the Spec Brightness you would do
Shader.SetGlobalFloat("Vector1_DD757871", value);
So in your case you could probably have one single controller doing something like
// Need this only if you have to get the initial value once
[SerializeField] private Material PalaceMaterial;
private float currentValue;
private string propertyId;
private void Awake()
{
propertyId = Shader.PropertyToID("_CutoffHeight");
currentValue = PalaceMaterial.GetFloat("_CutoffHeight");
}
private void Update()
{
currentValue = Maths.MoveTowards(currentValue, CutoffHeight, 100 * Time.deltaTime);
Shader.SetGlobalFloat(propertyId, currentValue);
}
so I've been struggling with a problem for a while, not sure how to approach it.
I'm trying to simulate a magic system similar to The Force used in Star Wars in Unity, and have ran into some troubles. I'm trying to simulate pushing and pulling on objects appropriately. This means that when the player pushes an object, both the player and the object get a force applied to them. If the object is light enough, the player shouldn't be affected in any noticeable way, and the object should be pushed away. If their masses are similar, both should be pushed away at some rate, and if the object is heaver, the player should be mainly pushed away. The same goes with pulling. The problem is when objects are anchored against something. If a player pushes a light object into a wall, the player should start receiving enough force to start pushing them backwards, since the combined mass of the wall and the object are pushing the player back.
Currently, I'm able to do the first part with the following code when a key is pressed:
Note that the force is determined based off the distance from the player to the object and the mass of them.
// dir: push or pull (-1 or 1)
Vector3 directionToPlayer = (dir * (player.transform.position - transform.position)).normalized;
rb.AddRelativeForce(directionToPlayer * f * Time.deltaTime);
player.GetComponent<Rigidbody>().AddRelativeForce(-directionToPlayer * f * Time.deltaTime);
As it is, the code works fine when the objects are just by themselves just by relying on Unity's Physics system. However, it does NOT work when an object is being pushed against a wall, or something really heavy. This is pretty clear as I'm just applying the same force to both the object and the player, and letting Unity decide whether to move the entity based off its rigidbody mass.
My question is, how can I detect if an object is anchored, and if it is combine the mass of the object and the object which it is anchored to, and apply that force to the player? I was thinking how to do this, and I know that I need to figure out the direction of which the force is being applied from, and then determine whether the object that's being pushed or pulled is colliding with anything in that direction, and if so apply a force to the player based off the combined masses. This gets a little tricky however when pushing an object at an angle that's against a wall. For example consider the following scenario:
There is both a horizontal and a vertical component of the force being applied on the cube, and so that should be considered when the cube+wall combined object pushes back on the player. How could this be accomplished or approached? I'm really struggling coming up with how to do this without hard coding direcitons.
Any help is appreciated, and I'll gladly clarify if anything is unclear.
NOTE The system is really based from a book series called Mistborn, but the concept is really close to The Force in Star Wars, and so I'll run with that as more people are familiar with it
This is not a complete solution, but you can use my idea below to acquire the nearby objects and then apply force to your objects and player in accordance with that.
The script should be placed on the object you are pushing or at least use a sphere collider from the object you are pushing.
public List<string> _ValidTargetTags = new List<string> { "Wall" };
public void CheckNearbyArea()
{
//Each of the nearby items will be checked to see if they are a wall or other valid target.
Collider[] ObjectsStruck = ScanForItems(GetComponent<SphereCollider>());
foreach (var o in ObjectsStruck)
{
if (_ValidTargetTags.Contains(o.gameObject.tag))
{
//If wall or other valid target
//Check where wall is placed
//Act according to wall position.
}
}
}
///The method below should find a list of all items inside a spherecollider of the object you are pushing.
Collider[] ScanForItems(SphereCollider sphereCollider)
{
Vector3 center = sphereCollider.transform.position + sphereCollider.center;
float radius = sphereCollider.radius;
Collider[] allOverlappingColliders = Physics.OverlapSphere(center, radius);
return allOverlappingColliders;
}
With this solution you will be able to check the players location relative to any nearby walls. This you can use to calculate what his direction is compared to the wall, relative to the object he is pushing.
I have multiple enemies that move toward the player. I am trying to stop them from merging into each other, i.e maintain some type of minimum distance between each other. What I'm trying is this (from unity3d forums):
enemy1.transform.position = (enemy1.transform.position -
enemy2.transform.position).normalized * distance + enemy2.transform.position;
However, when I have >= 3 enemies they still seem to bunch up even when I apply this to every enemy combination.
I need a better method as this one does not work and does not scale.
What you do around your enemy prefab is place a quad box which in effect is a trigger element, then on you script for the enemy you set that if another enemy (using tag types, I imagine) comes within touching of the quad box then to run appropriate code to stop the enemy getting closer in and to prevent the enemy actually overlapping with this trigger box.
Your code you example in your question looks like it is referencing the enemy units specifically rather than as instance entitites which is very probably a bad way of coding, as you're finding, it's very inflexible dealing with not-specifically-named reference entities.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
private Transform otherEntity;
public float distance = 50.0f;
private Transform thisEntity;
void OnTriggerEnter(Collider other)
{
otherEntity = other.GetComponent<Transform>();
thisEntity = GetComponent<Transform>();
thisEntity.position = (thisEntity.position - otherEntity.position).normalized * distance + otherEntity.position;
}
}
I have not tested the above code but using the code you reference the values for the transform are loaded from the Game Component for the referenced entities, as this has changed ALOT in Unity since release of version 5.1 and your source for your code was an answer given in 2012!!
thisEntity is the object that the script is attached to, typically one of the enemy. The otherEntity is the object that comes within the quad trigger (please remember the quad needs to be referenced as a trigger element.
The values of the Entity variables need to be set once the trigger is entered, so that it always effects the correct other element.
(I may be totally wrong with my methodology but I hope this helps.)
I'm trying to drive a configurable joint to the same rotation as another game object. Basically I'm trying to get one marionette to shadow another.
Im using the following code:
public GameObject master;
public GameObject slave;
void Update (){
ConfigurableJoint cj = slave.transform.GetComponent(typeof(ConfigurableJoint)) as ConfigurableJoint;
cj.targetRotation = master.transform.rotation;
}
However, I don't get any rotation out of the slave. Can anyone explain what I should be doing?
Are you sure you are getting the right joint ? Is cj null ?
Maybe try this line instead :
ConfigurableJoint cj = slave.GetComponent<ConfigurableJoint>();
When you are dealing with physics you can't apply rotation to a Rigid Body. What you can do is copy and paste the local transform to another non-static game object in relationship with its perent that does not contain a Rigid Body.
So basically the configurable joint has so so many options and parameters to set it up to your need that you need to take a course 2hrs course. There is no space here for a simple answer to set it up. I recommend this free old course because is the only one that at the moment explains in deep: This is more a general answer but works. There is an old tutorial in Unity3 that explains the setup:
https://archive.org/details/3dbuzz-archive/unity-fundamentals-part-04/020-physics/013-13-configurable-joint.mp4
I'm attempting to simulate a ship/space station with internal gravity.
To accomplish this, I'm making the player and all contents of the ship children of the ship. The ship itself has colliders, but no rigid body components. The idea is that as the ship moves, so will all of its contents. Pretty straightforward so far.
To simulate gravity in the ship, the player controller and all rigid bodies have the default gravity turned off. Instead of the standard, each frame a force is applied along the negative up vector of the parent ship.
This sort of works, but there is one major problem that I have to sort out before this thing is solid. All rigid bodies slide around the interior of the ship very slowly.
I'm aware that this is probably due to the updated position of the floor combined with the gravity force resulting in some kind of shear force. The objects always slide against the rotation of the ship.
I've tried mucking around with all of the physics properties from Physic materials to drag to mass, etc. None of these have worked, and I'm pretty sure it's due to the fundamental fact that the floor is moving, even though the RBs are children of the object that the floor is a part of.
Anyone have a solution to this that isn't some kind of duct tape? I could try to make everything kinematic and only "wake up" when certain external collisions occur or something, but that could get very cumbersome. I need for this to work in as much of a general purpose way as possible.
Some code:
On the ship
void Update ()
{
transform.Rotate(new Vector3(Time.deltaTime * 0.125f,Time.deltaTime*0.5f,0));
}
void FixedUpdate()
{
Vector3 tempVec;
foreach(Rigidbody rb in rigidBodies)
{
//Gravity!!
tempVec = transform.up * -9.81f * rb.mass * Time.deltaTime;
rb.AddForce(tempVec, ForceMode.Acceleration);
}
}
I've also worked on a version where the ship was following the movements of a rigid body. I couldn't do direct parenting, so I had to simply set the transform manually each frame to match the physics proxy. This still had the same effect as above, though it's probably ultimately how I want to move the ship, since that will tie into the flight mechanics more properly.
If you equate this to a real world scenario, the only thing that stops us from sliding around on the floor is friction.
Does the Physics library correctly apply friction based on the contacting materials? If not applying a certain amount of friction (or a minimum amount of force applied required to overcome it) should have the effect of preventing you from sliding around on the floor.
Although this is pretty much "duct tape" as above, it could neatly fit in and expand your physics engine if it doesn't already contain a way to enforce it.
As suggested above, the issue is because of how the physics engine applies friction. If I'm not mistaken, there will be some other forces acting on objects in a rotating frame (some of which are very unintuitive - check out this video: https://www.youtube.com/watch?v=bJ_seXo-Enc). However, despite all that (plus likely rounding errors arising from the engine itself and the joys of floating-point mathematics), in the real world, static friction is greater than moving (kinetic) friction. I don't think this is often implemented in game physics engines, which is why we so often see "wobbly" near-static objects. Also, you may run into the issue that even if this is implemented, the physics engine may be interpreting two contacting rotating bodies as non-static (even though their contact surfaces are static from a local perspective, the engine may be thinking globally)... [Insert joke about Newton and Einstein arguing].
https://i.stack.imgur.com/AMDr2.gif shows an idealised version of what friction actually looks like in the real world: until you overcome the static friction, nothing moves.
One way you would implement this (if you can access the physics engine that low-level) would be to round all movement forces below a certain threshold to zero - i.e. force < 0.001* is set to 0 (or possibly velocity < 0.001 is set to zero - whichever is easier).
*Some threshold - you'll have to work out what this is.
Otherwise, maybe you could instruct those objects to stop calculating physics and "stick" them to the parent surface, until such time as you want to do something with them? (This is probably a bad solution, but most of the other ideas above rely on hacking the underlying physics code).