Unity3D: Adding force based on direction an object is facing - c#

I am trying to make a "worms"-like game where the player can choose the position of an object (the player can move the object around 180 degrees) , and then the force would be added to the direction the object is facing. I tried using transform.right and transform.forward, but the force was not driven towards where the object is pointing. I have looked around A LOT, and still not found/understand what I can do. Heres the code I use for shooting the object:
void shootIt(){
transform.parent = null;
isPlaying = true;
A.isKinematic = false;
A.AddForce(transform.up*varSpeed*_multiplier);
} //"A" stands for the RigidBody2D component I got by using GetComponent<Rigidbody2D>();
Help is as always greatly appreciated.

Try this:
void shootIt()
{
Vector2 direction = transform.localPosition.normalized;
transform.parent = null;
isPlaying = true;
A.isKinematic = false;
A.AddForce(direction*varSpeed*_multiplier);
}
Also consider forcing yourself to write good names for your variables. A is not very descriptive.

Related

How to collide two objects without moving either object in Unity

I have a setup similar to this mockup in my 3D Unity game.
Each object has a collider as well as a rigid body. I am moving the object using mouse using simple mouse input events
private void OnMouseDown()
{
isSelected = true;
}
private void OnMouseDrag()
{
if (!isSelected) return;
Vector3 touchLocation = InputController.Instance.getTapLocation(); // Gets touch/mouse location using Raycast
_transform.position = track.GetPositionOnPath(touchLocation); //Uses vector projection math
}
private void OnMouseUp()
{
if (isSelected)
isSelected = false;
}
The object movement is constrained to a path using Vector projection
public Vector3 GetPositionOnPath(Vector3 touchLocation)
{
//Make the vector for the track u
Vector3 u = end.position - start.position;
//Make the touch location vector from the track start position v
Vector3 v = touchLocation - start.position;
float uv = Vector3.Dot(u, v);
float uMagSqr = Mathf.Pow(u.magnitude, 2);
Vector3 p = (uv / uMagSqr) * u; //Projection Formula (u.v)/(|u|^2) * u
Vector3 finalVector = start.position + p;
//Clamp the final vector to the end.positions of the track
if (start.position.x > end.position.x)
finalVector.x = Mathf.Clamp(finalVector.x, end.position.x, start.position.x);
else
finalVector.x = Mathf.Clamp(finalVector.x, start.position.x, end.position.x);
if (start.position.z > end.position.z)
finalVector.z = Mathf.Clamp(finalVector.z, end.position.z, start.position.z);
else
finalVector.z = Mathf.Clamp(finalVector.z, start.position.z, end.position.z);
return finalVector;
}
I want to make it in such a way that other objects in the way would obstruct the movement of the selected object as shown in the mockup. The solutions I thought of were to increase the weights of the objects so that they won't fly away when they collide, or to keep every object kinematic except the currently selected one. But they both have the same issue that the objects simply slide through each other.
It seems like a simple thing to do, but I can't seem to find any resources to help me out. I would really appreciate some help on how to tackle this problem and implement the mechanic as I intend. Thanks in Advance.
I have yet to find the exact solution I am looking for. But since it is highly discouraged to move the position of a rigid body object, I switched over to a physics-based movement based on information I found on this and this thread. Here is my current implementation:
private void OnMouseDown()
{
isSelected = true;
_rigidbody.isKinematic = false;
}
private void OnMouseDrag()
{
if (!isSelected) return;
Vector3 target = InputController.Instance.getTapLocation();
//_rigidbody.MovePosition(target);
force = _track.GetPositionOnPath(target) - _transform.position;
}
private void OnMouseUp()
{
if (!isSelected) return;
isSelected = false;
_rigidbody.isKinematic = true;
force = Vector3.zero;
}
private void FixedUpdate()
{
_rigidbody.velocity = force;
}
However, this comes at the cost of the movement not being perfectly responsive to the input given by the player as shown in this gif.
This is a fix so I am posting this as an answer but any other better options are much appreciated.

How to move a RigidBody2D to a position while still checking for collision

I am currently creating a game in Unity, in which you move a ball around using OnMouseDrag(), a CircleCollider2D and a RigidBody2D. This is how I set the position of the ball:
private void OnMouseDrag()
{
Vector2 mouseInWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
playerRb.position = new Vector3(mouseInWorld.x, mouseInWorld.y, 0);
}
I still want the ball to slide on collision while the mouse moves around. Is there a way to do this?
I have tried RigidBody2D.MovePosition(), but the ball jumped around from one point to another, and Raycasts but couldn't get that to work either.
EDIT:
This is what I've got now:
playerRb.velocity = new Vector3(mouseInWorld.x - playerRb.position.x, mouseInWorld.y - playerRb.position.y, 0);
Now the problem is, that the ball lags behind the mousePosition.
When you use RigidBody.MovePosition, you don't call the physics engine and so it ignores collisions. If you want collisions to happen you need to use RigidBody.Velocity instead.
Doing this change will require you to make some change to your code though because what you give to RigidBody.Velocity is a velocity and not a position so you will need to calculate the velocity required in x,y (and z if you are in 3d) to reach your destination.
I invite you to read the Unity page about velocity for more info
https://docs.unity3d.com/ScriptReference/Rigidbody-velocity.html
Note: This will make the player/ball stick to collisions.
Modifying the velocity could cause the ball to bounce around unexpectedly when the ball collides with the wall. I would use a CircleCast for this, check if it hit anything, then use MovePosition accordingly:
float cursorDepth;
Rigidbody2D playerRb;
CircleCollider cc;
void Awake()
{
playerRb = GetComponent<Rigidbody2D>();
cc = GetComponent<CircleCollider>();
}
private void OnMouseDrag()
{
Vector2 mouseInWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 posToMouse = mouseInWorld - playerRb.position;
RaycastHit2D hit = Physics2D.CircleCast(playerRb.position,
cc.radius * transform.lossyScale.x, posToMouse, posToMouse.magnitude);
if (hit.collider != null)
{
mouseInWorld = hit.centroid;
}
playerRb.MovePosition(mouseInWorld);
}
But notice that if the ball can't move all the way to the mouse, it might cause the drag to end. So, plan accordingly.

Collider not working if object is not moving

I tryed to make an elevator and i came around something that i could not explain.
So here is the scenario:
Once i put my object(in this case a cube) on the elevator it will go up and down.
If the object sits out the ride without moving and waits for the next ride, the colliding will stop when the elevator comes back through the ground.
If the object moves while the elevator come's back everything is fine and the object go's for another ride.
Could someone explain to my why this is happening and is there a fix for this ?
The platform is expected to go through the ground and pick up the object once it comes back above ground. (Imagine a not all to sectret elevator)
I alredy tried to add the script DontGoThroughThings.cs. It didnt work either.
Here is a screenshot of the inspectors.
Here is the script i made for the elevator to go up and down.
Elevator.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Elevator: MonoBehaviour {
public float speed;
public float distance;
private bool goingUp;
void Start () {
goingUp = true;
}
void Update () {
var currentPosition = transform.position;
currentPosition.y = goingUpDown(currentPosition.y);
transform.position = currentPosition;
}
private float goingUpDown(float currentPosition)
{
if (goingUp)
currentPosition += speed;
else
currentPosition -= speed;
if (currentPosition > distance / 2)
goingUp = false;
if (currentPosition < -distance / 2)
goingUp = true;
return currentPosition;
}
}
If you need any more information leave a comment. Thank you
You need to add a RigidBody to your elevator object, and then check the "Is Kinematic" option on it.
From the Unity Documentation RigidBody Manual:
Is Kinematic : If enabled, the object will not be driven by the physics engine, and can only be manipulated by its Transform. This is useful for moving platforms or if you want to animate a Rigidbody that has a HingeJoint attached.

Move an Object in the direction it is facing? C#

There are questions like this but I couldn't find any answers in C#, so here's my question: I want to rotate an object (in Unity 5) in the direction it's facing. I currently have this code to rotate my player.
using UnityEngine;
using System.Collections;
public class Movement : MonoBehaviour
{
private bool isLeft = false;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (isLeft == false)
{
transform.rotation = Quaternion.Euler(90, 45,0);
isLeft = true;
Debug.Log("Turned Right");
}
else
{
transform.rotation = Quaternion.Euler(90, -45, 0);
Debug.Log("Turned Left");
isLeft = false;
}
}
}
While your question and description are a bit ambiguous, it seems that you want to move the arrow, in the direction it's facing, correct?
Make sure that the arrow in the game object, is pointing forwards. You can see what forward is, by selecting the game object in the scene. Forward will be the blue arrow.
Now in code, to move it in this direction, you can move it in many different ways. Apply force/Translate/Set position. I recommend you try them out, to see what looks and feels the best. To simply change its position:
transform.position += transform.forward * Time.deltaTime * movementSpeed;
Where movement speed is a float that describes how fast it should move. Time.deltaTime is necessary if you put this code in Update().
Ok full edit on answer, so you have an arrow and whichever way its facing you want it to move the direction it's facing and when the player clicks it have it turn 45 degrees.
the easy part is turning it, basically you would call an onclick() function or set up colliders on the object and write up a brief snippet checking when mouse click down does it equal your arrow.name or collider. if so set up a new variable for a Vector3 to store the new rotation and just add 45 to the objects rotation and set the new rotation of the gameobject equal to your new rotation variable.

Unity. Disable collision physics but have method for collision called

Basically, i have player object and bunch of other. For this moment they all have RigitBody2D, and colliders, code for creating:
obj = new GameObject();
obj.tag = "web";
obj.name = "web";
float randomX = Random.Range (Utilities.getMainCameraBounds ().min.x, Utilities.getMainCameraBounds ().max.x);
float randomY = Random.Range (Utilities.getMainCameraBounds ().min.y, Utilities.getMainCameraBounds ().max.y);
obj.transform.position = new Vector3(randomX, randomY);
obj.transform.localScale = new Vector3 (3.0f, 3.0f, 3.0f);
collider = obj.AddComponent <BoxCollider2D>();
body = obj.AddComponent<Rigidbody2D> ();
body.constraints = RigidbodyConstraints2D.FreezeAll;
joint = obj.AddComponent<HingeJoint2D> ();
renderer = obj.AddComponent<SpriteRenderer>();
renderer.sortingOrder = 1;
renderer.sprite = Resources.Load("Textures/dot_net", typeof(Sprite)) as Sprite;
Purpose for this is to catch collision like this :
void OnCollisionEnter2D(Collision2D collision) {
if (collision.transform.tag == "web") {
Player.getInstance().joint(collision.rigidbody);
}
}
After player collides with some of those objects, method joint called, it's purpose to connect player and web with HingeJoint2D to simulate pendulum behvior. Code of joint:
public void joint(Rigidbody2D body) {
WebCollection.getInstance ().turnOffColliders (body.gameObject);
HingeJoint2D hingeJoint = webLine.getObject ().AddComponent<HingeJoint2D> ();
hingeJoint.connectedBody = body;
hingeJoint.anchor = new Vector2 (0.00120592f, 0.1921938f);
hingeJoint.connectedAnchor = new Vector2 (0.1939605f, 0.03025406f);
}
Pendulum behavior is working just fine, but in moment of it, or just when player is moving towards web, other web objects are colliding with it, creating real colliding behavior(like crushing into each other)
My goal: i want web objects to react on the collision(calling method above), but on the screen to player just go throw them.
What i've already tried: I wanted to turnOff other objects bodies (WebCollection.getInstance ().turnOffColliders (body.gameObject);) and after pendulum movement is over, to turn them back, but it causes very strange behavior.
What also can be a solution is to manually checking if player is colliding with web object right now, and handle it, but this is to costly i think.
To put my comment into an answer for those finding your question:
If you want to have Colliders that only trigger events and do not physically collide with other Colliders, then what you want are Triggers. To make a Collider a trigger you check the Is Trigger checkbox of the collider component in the inspector (you can also set it via script with the Collider.IsTrigger boolean property).
To do something when the trigger fires, use the OnTrigger events (OnTriggerEnter, OnTriggerExit, OnTriggerStay) (see http://docs.unity3d.com/ScriptReference/Collider.html)
There is also a short introduction to Colliders as Triggers by unity: http://unity3d.com/learn/tutorials/topics/physics/colliders-triggers

Categories

Resources