Spawning rigidbodies with velocity - instantiation

So I am making a gun in a Godot game. I want to use rigidbodies for the bullets, and it spawns like normal out of the gun. However, I cannot seem to find a way to spawn the rigidbody bullets, with velocity. Here is my code so far, I would love some help with this! (I am using gdscript, and I am new to Godot):
extends Position3D
signal spawned(spawn)
export(PackedScene) var spawnling_scene
func _physics_process(delta):
if Input.is_action_pressed("leftClick"):
spawn()
func spawn():
var spawnling = spawnling_scene.instance()
add_child(spawnling)
spawnling.set_as_toplevel(true)
emit_signal("spawned", spawnling)
return spawnling

You can write the linear_velocity of the RigidBody3D before you add it to the scene tree. Here is a quick example:
extends Position3D
func _input(event: InputEvent) -> void:
var bullet := preload("res://scenes/bullet/bullet.tscn")
if event.is_action_pressed("ui_accept"):
var bullet_instance := bullet.instance() as RigidBody
bullet_instance.linear_velocity = Vector3.RIGHT * 50
add_child(bullet_instance)
bullet_instance.set_as_toplevel(true)
how do I make it so that instead of going in one direction, it goes in the direction that I face?
The Basis of the transform has the direction of the axis. Since we usually use the z axis as forward direction in Godot, usually the z axis of the Basis is the direction it is facing:
bullet_instance.linear_velocity = global_transform.basis.z * 50

Related

Unintended player movement from transform.InverseTransformDirection

this is my first time posting on here. I'm working on a game using the new Unity multiplayer networking solution.
In summary, the issue is that the player is not moving as intended.
I am trying to take player input as follows:
Vector3 worldSpaceDir = new Vector3(Input.GetAxisRaw("Vertical"), 0, Input.GetAxisRaw("Horizontal"));
then convert it to the object space coordinates of the player character:
_inputDirection = transform.InverseTransformDirection(worldSpaceDir);
The issue I'm having is with a rotation of 0 or 180 the player moves as expected with the WASD inputs, however, at 90 or 270 all the inputs are flipped(A = right, D = left, W = backward, S = forward).
I found a question that is exactly my question but no one responded with an answer. The question is quite old now so I wanted to ask it again for more visibility.
Here's a link to the original question.
Firstly, you are taking the worldSpaceDir wrong, it should be as follow
Vector3 worldSpaceDir = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
here we take horizontal input as X and vertical input as Z, because in Unity Forward is pointed as Z and not Y.
Secondly, we do not need to use InverseTransformDirection() we just need TransformDirection() something like following
Vector3 inputDirection = transform.TransformDirection(worldSpaceDir);
here we are telling unity to convert the worldSpaceDir that is relative to transform (local direction) into a world space direction, so we might actually give a proper name to worldSpaceDir.
The following would work for you.
private void Update() {
Move();
}
private void Move() {
Vector3 directionToMove = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
Vector3 inputDirection = transform.TransformDirection(directionToMove);
transform.position += inputDirection * Time.deltaTime;
}
I think you want to go the other way round actually!
Transform.InverseTransformDirection converts a vector from world space into local space.
What you get as input however is a local vector on the XZ plane. You want to apply this direction according to your player objects orientation, if e.g. pressing right (your input is 1,0,0) the object shall move towards its transform.right vector.
So you rather want to convert in the opposite direction into world space to move the object in the Unity world space.
You should rather be using Transform.TransformDirection!
var worldMove = transform.TransformDirection(input);
Or alternatively you can also just multiply by the rotation like
var worldMove = transform.rotation * input;
Note that if you are also using a Rigidbody like the question you linked there is also Rigidbody.AddRelativeForce which basically works the same way and expects a local space vector which is then internally converted into a world space force.

assigning velocity to rigidbody doesn't do anything

I have a script attached to a mesh with a kinematic, rigid body with a convex mesh collider that I'd like to move around. Here's what I call in my update function:
if (Input.GetKey(forwards)) {
Debug.Log("forwards!!");
//get current velocity in local space
Vector3 localVel = transform.InverseTransformDirection(body.velocity);
//alter so that forward component = speed
localVel = new Vector3(localVel.x, localVel.y, linearSpeed);
//convert back into world space and set to body
Vector3 worldVel = transform.TransformDirection(localVel);
body.velocity = worldVel;
}
Other Info:
body is a Rigidbody variable that I assign in Start() using GetComponent<Rigidbody>();
linearSpeed is a float with value 1
I'm getting the Debug.Log output, but my mesh is not moving. Is there anything obvious I'm missing here? This is my first script for a 3D, as opposed to a 2D game.
public float speed = 20;
Rigidbody r;
void Start(){
r = gameObject.GetComponent<Rigidbody> (); //Put's reference to local rigidbody into variable "r"
}
void FixedUpdate () {
Vector3 direction = Vector3.zero; //set's current direction to none
//Adds vectors in case that user is pressing the button
if(Input.GetKey(KeyCode.W)) direction += Vector3.forward;
if(Input.GetKey(KeyCode.S)) direction -= Vector3.forward;
if(Input.GetKey(KeyCode.D)) direction += Vector3.right;
if(Input.GetKey(KeyCode.A)) direction -= Vector3.right;
//Normalizez direction (put's it's magnitude to 1) so object moves at same speeds in all directions
r.AddForce (direction.normalized * speed); //Adds direction with magnitude of "speed" to rigidbody
}
Rigidbody MUST be attached to same GO as this script. This script uses world directions, because working with local directions is much harder (the object is rotating and changes directions rapidly, you can use it if you want just by replacing reference to Vector3 to transform like this:
if(Input.GetKey(KeyCode.W)) direction += transform.forward;
Of course for all direction.
This is very basic way to move the object along it's local axises, to do it more better you need to write specific scripts for specific sets of objects, it all depends what kind of object are you moving and how you want to move it. (is it sphere, cube..., will it ever fly up, should it rotate....).
If the RigidBody is Kinematic it is meant to be moved by means other than the physics system; animations, transform.position, etc. Make your rigid body non-kinematic and it should move when you set velocity.

2D bouncing formula doesn't work properly

I am new to unity, and i am trying to create a bouncing ball, so i've did many researches about bouncing realted physics and i found a formula :
Formula:
-2*(V dot N)*N + V
Where V is the velocity vector and N is the normal of the surface on which the ball will bounce
Here is my script :
using UnityEngine;
using System.Collections;
public class BallPhysics : MonoBehaviour {
void Start () {
rigidbody2D.velocity =new Vector2 (-1,-3);
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D(Collider2D col) {
if (col.gameObject.name == "Pong") {
tBounce ();
}
}
void tBounce(){
RaycastHit2D hit = Physics2D.Raycast (new Vector2 (transform.position.x,transform.position.y), new Vector2(-1f,-1f));
Vector2 n = hit.normal;
Vector2 v = rigidbody2D.velocity;
Vector2 R = -2 * (Vector2.Dot (v, n)) * n + v;
rigidbody2D.velocity = R;
}
}
I am giving the ball a velocity vector in the start function, i am using OnTriggerEnter2D for collision handling and raycast2D to get the normal of a surface.
The problem is that the script doesn't reflect the velocity vector called R, i think the probleme is in the normal vector.
For example let's say V is a Vector2(-1,-1) so basically R should be (-1,1), but it's not. R is (3,1) !
i've successfuly been able to make a ball bouncing on Horizontal/vertical surface by reversing the ball velocity but this won't work properly with arbitary angles,that's why i am using this formula.
So what's the problem ?
Your raycast is likely hitting the wrong collider. You start it at transform.position. That is the center point of your ball object.
Imagine a ray coming out of a circle's center. What's the first line it hits? It hits the circle itself first. So your Raycast reports the surface normal of the ball, not the pong paddle.
There are many ways to get around this. You can apply a Physics Layer that ignores raycasts. I think there is one pre-defined like that. You can create custom ones as well and supply a layer mask to your raycast.
There are other ways to solve it like originating the raycast from somewhere else, but since you're doing this as the objects collide, a layer mask is probably the simplest.

Elliptical movement of a rigidbody (as in whale trail game) by applying force in unity using c#?

I want to move a rigid body in an elliptical movement like the player movement "whale trail" game.What I did is:
Created a Cube called "Player" with scale(1.5,0.5,0.1)
Created another small cube called Point with scale(0.1,0.1,0.1) and positioned same as Player but 0.5 more in x (So that now the player looks like a 2D rectangle and a point on it little right to the centre of the rectangle).
Then I created a fixed joint between both bodies
Now I applied for on the player at the position of the Point as follows ,
float mfAngle = 0.0f;
void update()
{
mfAngle=transform.eulerAngles.z;
mfAngle=mfAngle%360;
if(mfAngle>=0 && mfAngle<90)
{
mfXforce=-0.1f;
mfYforce=0.1f;
}
if(mfAngle>=90 && mfAngle<180)
{
mfXforce=-0.1f;
mfYforce=0.1f;
}
if(mfAngle>=180 && mfAngle<270)
{
mfXforce=-0.1f;
mfYforce=-0.1f;
}
if(mfAngle>=270 && mfAngle<360)
{
mfXforce=0.1f;
mfYforce=-0.1f;
}
Debug.Log("Angle ="+mfAngle+"X = "+mfXforce+"Y = "+mfYforce);
Vector3 pointPos=_goPointObject.transform.position;
transform.rigidbody.AddForceAtPosition(new Vector3(mfXforce,mfYforce,0),pointPos);
}
But it doesn't works fine.I just moves upwards and the turns and moves in different direction.If anyone know how to move the rigid body in elliptical motion by applying force give me a solution.(I want to use it as like whale trail game u can see the video of the "loop movement" in this http://www.youtube.com/watch?v=wwr6c2Ws1yI video).Thanks in advance.
I had found the solution by myself.To achieve that elliptical movement u have to create two bodies and connect them with joint by placing it horizontally next to each other.Then u have to apply force in x direction constantly and in Y direction only when the Screen is be touched on the first body.
And its important to reduce the X speed when moving up then u will get that elliptical rotation.
It works fine for me.
Thanks,
Ashokkumar M

How to prevent colliders from passing through each other?

I am having trouble keeping game objects inside of a contained space. When they reach the edge, there is some momentary push back but then they will go right through the wall.
I am using a Box Collider on the player, and a Mesh Collider for the level's wall. I am having issues with both a Player Character (a space ship) that the movement is controlled by the player. And with projectiles, which are fire and forget moving at a constant speed.
This is my movement code for my player. It is being run in the FixedUpdate() function.
//Movement
haxis = Input.GetAxis("Horizontal") * speed;
vaxis = Input.GetAxis("Vertical") * speed;
moveVector.x = haxis;
moveVector.z = vaxis;
if(moveVector.magnitude > 1)
{
moveVector.Normalize();
}
rigidbody.MovePosition(transform.position + moveVector * speed);
With the bullets, they are given a velocity and the engine calculates their moviements. They are using Box Collider and it is set as a Trigger so they don't have physics. But I use OnTriggerEnter to destroy them.
//Projectiles without physics collisiions
function OnTriggerEnter (other : Collider) {
Destroy(gameObject);
}
Some, but not all of the bullets will be destroyed when hitting the mesh collider wall. The player will sometimes hit it and stop, but can usually push through it. How can I make the collisions with the mesh collider work every time?
Collision with fast-moving objects is always a problem. A good way to ensure that you detect all collision is to use Raycasting instead of relying on the physics simulation. This works well for bullets or small objects, but will not produce good results for large objects.
http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html
Pseudo-codeish (I don't have code-completion here and a poor memory):
void FixedUpdate()
{
Vector3 direction = new Vector3(transform.position - lastPosition);
Ray ray = new Ray(lastPosition, direction);
RaycastHit hit;
if (Physics.Raycast(ray, hit, direction.magnitude))
{
// Do something if hit
}
this.lastPosition = transform.position;
}
I have a pinball prototype that also gave me much trouble in the same areas. These are all the steps I've taken to almost (but not yet entirely) solve these problems:
For fast moving objects:
Set the rigidbody's Interpolate to 'Interpolate' (this does not affect the actual physics simulation, but updates the rendering of the object properly - use this only on important objects from a rendering point of view, like the player, or a pinball, but not for projectiles)
Set Collision Detection to Continuous Dynamic
Attach the script DontGoThroughThings (https://www.auto.tuwien.ac.at/wordpress/?p=260) to your object. This script cleverly uses the Raycasting solution I posted in my other answer to pull back offending objects to before the collision points.
In Edit -> Project Settings -> Physics:
Set Min Penetration for Penalty to a very low value. I've set mine to 0.001
Set Solver Iteration Count to a higher value. I've set mine to 50, but you can probably do ok with much less.
All that is going to have a penalty in performace, but that's unavoidable. The defaults values are soft on performance but are not really intented for proper simulation of small and fast-moving objects.
How about set the Collision Detection of rigidbody to Continuous or Continuous Dynamic?
http://unity3d.com/support/documentation/Components/class-Rigidbody.html
So I haven't been able to get the Mesh Colliders to work. I created a composite collider using simple box colliders and it worked exactly as expected.
Other tests with simple Mesh Colliders have come out the same.
It looks like the best answer is to build a composite collider out of simple box/sphere colliders.
For my specific case I wrote a Wizard that creates a Pipe shaped compound collider.
#script AddComponentMenu("Colliders/Pipe Collider");
class WizardCreatePipeCollider extends ScriptableWizard
{
public var outterRadius : float = 200;
public var innerRadius : float = 190;
public var sections : int = 12;
public var height : float = 20;
#MenuItem("GameObject/Colliders/Create Pipe Collider")
static function CreateWizard()
{
ScriptableWizard.DisplayWizard.<WizardCreatePipeCollider>("Create Pipe Collider");
}
public function OnWizardUpdate() {
helpString = "Creates a Pipe Collider";
}
public function OnWizardCreate() {
var theta : float = 360f / sections;
var width : float = outterRadius - innerRadius;
var sectionLength : float = 2 * outterRadius * Mathf.Sin((theta / 2) * Mathf.Deg2Rad);
var container : GameObject = new GameObject("Pipe Collider");
var section : GameObject;
var sectionCollider : GameObject;
var boxCollider : BoxCollider;
for(var i = 0; i < sections; i++)
{
section = new GameObject("Section " + (i + 1));
sectionCollider = new GameObject("SectionCollider " + (i + 1));
section.transform.parent = container.transform;
sectionCollider.transform.parent = section.transform;
section.transform.localPosition = Vector3.zero;
section.transform.localRotation.eulerAngles.y = i * theta;
boxCollider = sectionCollider.AddComponent.<BoxCollider>();
boxCollider.center = Vector3.zero;
boxCollider.size = new Vector3(width, height, sectionLength);
sectionCollider.transform.localPosition = new Vector3(innerRadius + (width / 2), 0, 0);
}
}
}
1.) Never use MESH COLLIDER. Use combination of box and capsule collider.
2.) Check constraints in RigidBody. If you tick Freeze Position X than it will pass through the object on the X axis. (Same for y axis).
Old Question but maybe it helps someone.
Go to Project settings > Time and Try dividing the fixed timestep and maximum allowed timestep by two or by four.
I had the problem that my player was able to squeeze through openings smaller than the players collider and that solved it. It also helps with stopping fast moving objects.
Edit ---> Project Settings ---> Time ... decrease "Fixed Timestep" value .. This will solve the problem but it can affect performance negatively.
Another solution is could be calculate the coordinates (for example, you have a ball and wall. Ball will hit to wall. So calculate coordinates of wall and set hitting process according these cordinates )
Try setting the models to environment and static. That fix my issue.