I have a game object which swings back and forth along one of its axis, this is attached to a parent gameObject which moves around a scene. However, when the parent object rotates the child object does not rotate with it.
I expect this is something to do with local vs global space.. however Im at a loss...
This is the code which manages the sweep.
// Increment a timer
timer += Time.deltaTime;
// Swing the object back and forth based on the rotationLimit and the rotationSpeed
currentRotation = Mathf.PingPong (timer * rotationSpeed, rotationLimit * 2f) - rotationLimit;
// Create a temporary variable to store the new rotation
Quaternion rotation = Quaternion.Euler (transform.rotation.x, transform.rotation.y + currentRotation, transform.rotation.z);
// Set the rotation to the temp var
transform.rotation = rotation;
I considered grabbing the parents rotation and using that instead of the transform.rotation. However, ideally this same script needs to work on a variety of objects, some of which don't have parents. Can anyone advise where I am going wrong.
From your tags i'm guessing you use Unity. As far as I know, unity supports the concept of a 'SceneGraph'. This allows you to build a tree of game objects, where the children follow the transformation of their parent.
See this link: http://docs.unity3d.com/ScriptReference/Transform-parent.html
ALTERNATIVE - If you want to do this manually:
You should be carefull when manually combining parent/child transformations. The easiest and probably best way to do this is to simply combine the parent and child transformations:
ChildWorldTransform = ChildLocalTransform * ParentWorldTransform
ChildLocalTransform corresponds to your currentRotation, ParentWorldTransform to the transformation of your parent object. Note that you should multiply the entire transformation as a whole, not just the rotation part!
I also suggest that you do a google for 'scenegraph'
Related
So I am making a character controller which uses Quaternion.FromToRotation to align the player with the gravity center in this piece of code:
this_body.transform.rotation *= Quaternion.FromToRotation(this_body.transform.up,gravity_up);
And when I am on certain parts of the sphere planet it starts flipping out everywhere, like in this video, and I don't know how to remedy this, although maybe the gravity implementation could be the problem, or the character controller, although I think using relative force should not mess with it.
Gravity Implementation:
float distance = direction.magnitude;
float forceMagnitude = G * (obj.GetComponent<MultiAttractor>().rb.mass * rb.mass) / Mathf.Pow(distance, 2);
Vector3 force = direction.normalized * forceMagnitude;
rb.AddForce(force);
My character controller script is a bit long so I don't think I should bore you with it, although if needed I could provide it.
This is for anyone who is having issues with using Quaternion.FromToRotation with a rigid body character controller:
I did not dig much into your problem but you are manipulating the rotation directly in the code with Quaternion.FromToRotation and also with physics. I think you need to stick to one of the two, because using both might lead to unexpected behaviours. If you introduce a "raw" rotation modification, the physics engine deals with it. – rustyBucketBay
Basically just use physics rotation like Rigidbody.rotation for rotating things like Transform.Rotate or if you want to rotate physics objects like you are adding force, but instead of moving things it rotates things, then use Rigidbody.AddTorque, or just don't use any physics rotations with other types of rotation as it can cause problems, as stated by rustyBucketBay
in the game that I'm producing, the player can shoot and I'd like to make the projectile rotates continuously when the player shoot it. Each player have an empty gameobject called SpawBala which instantiates the projectile.
I'm using these lines of code to instantiate it, but the rotation is not working:
//instantiates the bullet
GameObject tiro = Instantiate(projetil, SpawBala.transform.position, SpawBala.transform.rotation);
Rigidbody BalaRigid = tiro.GetComponent<Rigidbody>();
if (SpawBala.tag == "Bala1" && gameManager.playerTurn == 1)
{
BalaRigid.AddForce(Vector3.forward * ProjetilVeloc);
BalaRigid.transform.Rotate(new Vector3(Bulletspeed * Time.deltaTime, 0, 0));
gameManager.PontoAcaop1--;
}
How could I solve it?
Your call to Rotate only happens exactly once and rotates the object about a given amount.
Anyway since there is a Rigidbody in play you shouldn't set transforms via the transform component at all because it breaks the physics.
Rather always go through the Rigidbody component.
I actually would not use AddForce and for rotation btw AddTorque when spawning a bullet. You would have to calculate the required forces depending on the bullet's weight in order to get the desired velocity(s).
Instead rather set a fix initial velocity and for the rotation angularVelocity.
Also note that currently you are always shooting in global World-Space Z direction no matter how your SpawnBala object is oriented in space. You should rather use SpawnBala.transform.forward as direction vector:
BalaRigid.velocity = SpawnBala.transform.forward * ProjetilVeloc;
// Note that your variable names are confusing
// You should probably rename it to BulletRotationSpeed e.g.
BalaRigid.angularVelocity = SpawnBala.transform.right * Bulletspeed;
I'm trying to create collidable noodle which get pushed by other objects in my game.
I tried to create rigged/skinned mesh in Blender then connect the bones with joints in Unity and tried all of the joints with various settings, but it jitters when bit more than minimum force applied to these bones. Then i tried to bind these bones with script to keep fixed distance from connected bones (next or previous bone) which relative to only one bone/side which works well if it's pulled from one end; but i need it to be relative to both sides to act like noodle. The skinned mesh does the job of keeping it whole, so i think i need some way to control these bones/segments. Any help will be appreciated. Thanks a lot for your time, effort and consideration :).
Script for every node to keep the fixed distance:
void Update() {
// To keep initial distance
Vector3 vec = connectedNode.position - transform.position;
if (vec.magnitude > initialDistance)
transform.position +=
(vec.magnitude - initialDistance) * vec.normalized;
}
I know the title isnt very explanatory, but here's my problem:
I have a player (merely a cube with a rigidbody, a collider and a movement script), and I have a floor made of small 1 by 1 by 1 cubes (cubes with box colliders).
For some reason unknown to me, when my player cube falls and tries to collide horizontally with the floor, he just phases through... But want him to get blocked by the cubes just like it does vertically. Any help would be greatly appreciated ;)
heres how the scene looks like
heres a cube object
heres the player object
Here's a gif of the player going through the floor
Here's my c# player movement script (I know its very bad, but I prefer to put this here just in case its linked to my problem) :
void ApplyMovement()
{
transform.position += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
}
If you need any more info to help me just tell me, I'll provide it as fast as I can.
The value of
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"))
is framerate-dependent. This means the faster the framerate the faster your object will move. This is usually not what you want. Instead use Time.deltaTime
// Adjust the speed in the inspector
public float speedMultiplicator = 1;
//...
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * speedMultiplicator * Time.deltaTime
to get a framerate-independent movement. Also see the example in Input.GetAxis.
When dealing with RigidBody never change the transform.position (and rotation) directly!
If you would want to make the RigidBody jump to a certain position rather use
rigidBody.position = transform.position + ...;
However what you want is a smooth movement in order to keep the collision detection intact. So you should use RigidBody.MovePosition instead
rigidBody.MovePosition(transform.position + ...);
You don't have to deal with force etc.
Also add a RigidBody component to the floor objects. Even ifnthe object is not moving this improves the collision detection (at the cost of performance in the Physics engine ofcourse). And since the objects are not supposed to move set
isKinematic -> true
use Gravity -> false
you can also set freeze position and freeze rotation.
On both floor and player objects set Collision Detection -> Continous Dynamic. This improves the collision detection and looks for collisions also between frames.
Be aware, however, that dynamic detection is quite expensive so use it only if there is still trouble with too fast objects.
On the player you might want to also use interpolate as well.
Finally
Note that continuous collision detection is intended as a safety net to catch collisions in cases where objects would otherwise pass through each other, but will not deliver physically accurate collision results, so you might still consider decreasing the fixed Time step value in the TimeManager inspector
to make the simulation more precise, if you run into problems with fast moving objects.
For more information see the RigidBody manual and the Colliders manual
I recreated the scenario you described on my end. I put your "ApplyMovement" code in "Update". I was basically able to reproduce your results.
It seems to me that the issue might be Freezing Position X/Z on the Player. I think since you are doing that, you're telling the Rigidbody component that it is not allowed to modify the X/Z positions of the objects as part of it's collision resolution and physics simulation. When I turn those two off, I get results that are (I think) closer to what you're looking for.
One note: your "ApplyMovement" code is frame-locked, meaning your player will move at different speeds at different frame rates. To solve this, you'd need to multiply your Input.GetAxis values by Time.deltaTime.
Also, if your player moves too fast, it'll still be able to pass through collisions and cause odd behavior, so be sure to limit the max movement rate of the player to some reasonable value.
You should be applying a force to the Rigidbody of the character instead of directly manipulating the transform.position (this is preventing the physics engine from resolving the collisions). You're also freezing the X and Z position on the Rigidbody; you don't want that because it entirely prevents the Rigidbody from manipulating those values.
Instead of transform.postion += ... first get a reference to the Rigidbody somewhere in your script (best done in an Awake() method):
private Rigidbody _body;
private void Awake() {
_body = GetComponent<Rigidbody>();
}
Then make sure the vector built from your inputs is being applied to the object's "movement," not its position:
Vector3 inputVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
// You can multiply this vector by a float to adjust "speed"
_body.ApplyForce(inputVector, ForceMode.VelocityChange);
Finally, you should read up on the different ForceMode options and decide which one fits your preferences: https://docs.unity3d.com/ScriptReference/ForceMode.html
Don't forget this should happen in a FixedUpdate(), not an Update() (all physics operations should be done in FixedUpdate())
As a side note, there is also the possibility your rigidbodies still up moving too quickly and passing through each-other. Even when you're using forces and velocities, this is possible so if your run into this case down the line, investigate Collision Detection Modes. TLDR; they're settings for performance vs accuracy trade-offs.
I currently have a method that checks to see if I go out of bounds either from either the top/bottom/sides. The object itself is a ball, and I have a question about getting the ball bouncing off the edges correctly? How do I go about this?
// The behavior is not quite what I want.
if ( InsideOfBounds )
{
Vector3 mCenter = Ball.getCenter();
Vector3 normalizeV = tempCenter;
normalizeV.Normalize();
mHeroBall.setVelocity(-testSpeed * normalizeV);
}
I can provide you with an example from a Breakout-clone written in XNA:
Ball.cs
Basically, you flip the right component of velocity to make a 'perfect' rebound. If you want, you can add friction or elasticity by multiplying by a coefficient like 0.95 or 1.1 so your ball speed change.
When you update the position of your object (ball), you want to check if the new value is out of bounds (and which bount Top\Bottom or Left\Right). If the it actually out of bounds, flip the correct element in your speed vector.
example: if the ball has passed the left bound then BallSpeed.X = -BallSpeed.X
don't forget to update the ball's position with the new speed and not the old at this point, or it will fly off the screen for the current frame (unless that isn't an issue).