In Unity, I want to create a platform that rotates like a propeller. When it hits an object, I want that object to go flying in a logical direction. If I just update the object's rotation every frame, the object tends to stick to the platform and pass through it at higher speeds. I'm thinking that Unity's physics would be the best solution - how can I rotate the platform at a constant speed such that it can do what I want? In addition, how can I start and stop the spinning without it speeding up or slowing down? I'm using C#.
If you're looking to incorporate Unity's physics into your platform behaviour, but don't want to deal with adding force/torque to change its rotational speed, consider using Rigidbody.angularVelocity. With this, you can also start and stop the rotation instantly (use FixedUpdate() when you're working with a RigidBody).
So your code may look like:
Vector3 activeVelocity = new Vector3(0, 10, 0);
bool isStopped = false;
RigidBody rBody;
void Start() {
rBody = GetComponent<Rigidbody>();
}
void FixedUpdate() {
if (!isStopped){
rBody.angularVelocity = activeVelocity;
}
else{
rBody.angularVelocity = Vector3.zero;
}
}
public void ActivateRotation() {
isStopped = false;
}
public void FreezeRotation() {
isStopped = true;
}
Hope this helps! Let me know if you have any questions.
Related
In my 2D Unity game, balls can bounce off each other. My goal is to have them bounce off each other as you would expect physically in the real world.
The only difference is that the speed of the balls decreases, but they can never come to a stop.
I have different approaches to map the physical behavior. But none of them leads to a good result.
(1)
private void OnCollisionEnter2D(Collision2D collision) {
var point = collision.GetContact(0);
var curDire = transform.TransformDirection(Vector2.up);
var newDir = Vector2.Reflect(curDire, point.normal);
transform.rotation = Quaternion.FromToRotation(Vector2.up, newDir);
speed *= 0.75f;
}
I don't know how describe exactly: It can happen that the balls push past each other. They collide, but do not bounce off each other, but maintain their direction.
Another approach I have read about is to add an AddForce to the velocity of Rigidbody2D.
Then the following code should do the physics.
private void Start()
{
rb = GetComponent<Rigidbody2D>();
_velocity = new Vector3(1f, 1f, 0f);
_rb.AddForce(_velocity, ForceMode2D.Force);
}
private void OnCollisionEnter2D(Collision2D collision) {
var inDirection = GetComponent<Rigidbody2D>().velocity;
var inNormal = collision.contacts[0].point;
var newVelocity = Vector2.Reflect(inDirection, inNormal);
rb.velocity = newVelocity;
}
The results are really random. I think I use a wrong AddForce or the velocity-Vector is strange. I fall here the deeper mathematical understanding to fully comprehend this solution.
(3) Then I read about Physic Material 2D. This sounds best. I created one (Asset -> Create -> 2D -> Physic Material 2D). Set bounciness to 1 the friction to 0.1. I select my Ball-prefab and add the physic material to my collider. I added it to the Rigidbody2D, too. But this asset has no effect. (My balls have no gravity. I don't know if this is important.)
I imagine Unity has a super simple solution for this problem. But I just can't find it. Does anyone have any ideas or approaches for me? I actually just want shot balls to bounce off each other. This should look as much as possible like it would look in real life.
Update Question
I move the ball like that
private Vector3 _inDirection;
private void Start()
{
_inDirection = Vector3.right * (speed * Time.deltaTime * (_didCollide ? -1 : 1));
}
private void FixedUpdate()
{
transform.Translate(_inDirection);
}
I'm looking not so much for a throw as just maintaining motion after a ball is released by the hand in Hololens 2. Currently, I'm using the MRTK IMixedRealityTouchHandler interface, mainly the functions public void OnTouchStarted(HandTrackingInputEventData data) and OnTouchCompleted(HandTrackingInputEventData data).
On the Hololens 2 Emulator, when I release the ball with my hand (mouse), it drifts off in the air in the general direction I was pointing it towards relatively slowly, which is exactly what I want. I achieved this by reducing drag. However, once I build to the HL2 device itself, this motion is not emulated and the ball stops midair immediately after it is released. Why is this happening?
I've tried adding the line rb.AddRelativeForce(Vector3.forward * magnitude, ForceMode.Force); in OnTouchCompleted which wasn't successful. How can I maintain the ball's motion after it is released by my hand?
In general (I don't see the rest of your code) you can keep updating the velocity relative to the last frame and finally apply it.
Somewhat like e.g. (pseudo code)
private Vector3 velocity;
void BeginDrag()
{
rb.isKinematic = true;
rb.velocity = Vector3.zero;
lastFramePos = rb.position;
}
void WhileDrag(Vector3 position)
{
velocity = position -rb.position;
rb.position = position;
}
void EndDrag()
{
rb.isKinematic = false;
rb.velocity = velocity;
}
or actually even easier and probably more accurate you can directly use the
public void OnTouchCompleted(HandTrackingInputEventData data)
{
rb.velocity = data.Controller.Velocity;
}
See
HandTrackingInputEventData.Controller
IMixedRealityController.Velocity
So I am trying to make a multiplayer game with abilities sort of like Overwatch/Paladins. All in all, one ability should be a sort of projectile that moves across the ground and allows that player to teleport to its position at any time while it is alive. I can't find the solution to teleporting only the player that shot it since thus far in my tests, when one player activated their ability, all players would teleport. How can I solve this?
My code:
void Update()
{
if (Input.GetKeyDown(KeyCode.E))
GetComponent<playerController>().heldAbility = "gateCrash";
if (GetComponent<playerController>().heldAbility == "gateCrash")
holding = true;
else
holding = false;
if (holding && Input.GetMouseButtonDown(0))
PhotonNetwork.Instantiate(Path.Combine("PhotonPrefabs", "GateCrashModel"), spawnPos, transform.rotation, 0);
}
This code is attached to the projectile:
public float speed = 10;
PhotonView pv;
private void Awake()
{
pv = transform.GetComponent<PhotonView>();
}
private void FixedUpdate()
{
transform.Translate(transform.forward * speed * Time.fixedDeltaTime);
}
I guess that I should make have something as instatntiation parameter but idk what.
A simple approach would be to add a shotOwner property to each of your projectiles. Every time a projectile is fired, update shotOwner to point to the player object that fired the shot. (This will also let you implement "Player_X killed Player_Y" functionality, among other things.)
I've got a bullet script with a particle system and a decal.
I think that it has something to do with these events not being able to fire in time or with fps in update. Not sure yet.
So, it's being late.
The ellow points are where the particles start to play. They should be right on these wooden walls. There should be three particles working and three bullet holes, kinda bullet penetrating one wall and getting destroyed on the second one.
THE QUESTION IS HOW TO MAKE IT WORK NORMAL, SO THAT THE TRIGGERS WORK WHEN NEEDED AS WELL AS THE PARTICLES AND THE DECALS? Maybe there's a way to excellerate the code to work on time? Or maybe there's another problem with that?
The screenshot:
The Code:
public class BulletScript : MonoBehaviour {
public bool isThrough = true;
public float BulletSpeed = 100;
public float CurrentDamage;
public float EnterLuft = -0.005f;
public float ExitLuft = 0.05f;
public GameObject woodParticle;
private ContactPoint CollisionPoint;
public GameObject BulletMarkPref;
Rigidbody bullet;
private void Start()
{
bullet = this.GetComponent<Rigidbody>();
}
void FixedUpdate () {
bullet.velocity = Vector3.forward * BulletSpeed;
//this.transform.Translate(Vector3.forward * BulletSpeed * Time.deltaTime);
}
private void OnTriggerEnter(Collider other)
{
Transform hitPoint = this.transform;
LevelObject.LvlObjectType objectType = other.gameObject.GetComponent<LevelObject>().objType;
if(objectType == LevelObject.LvlObjectType.obstacle)
{
if (isThrough)
{
Instantiate(woodParticle, hitPoint.localPosition, Quaternion.LookRotation(-hitPoint.forward)).GetComponent<ParticleSystem>().Play();
LeaveBulletMark(this.transform, true);
}
else
{
Instantiate(woodParticle, hitPoint.localPosition, Quaternion.LookRotation(-hitPoint.forward)).GetComponent<ParticleSystem>().Play();
LeaveBulletMark(hitPoint, true);
Destroy(this.gameObject);
}
}
else if(objectType == LevelObject.LvlObjectType.obstacle)
{
Destroy(this.gameObject);
}
else if(objectType == LevelObject.LvlObjectType.wall)
{
LeaveBulletMark(hitPoint, true);
Destroy(this.gameObject);
}
}
private void OnTriggerExit(Collider other)
{
Transform hitPoint = this.transform;
Instantiate(woodParticle, hitPoint.localPosition, hitPoint.rotation).GetComponent<ParticleSystem>().Play();
LeaveBulletMark(hitPoint, false);
}
void LeaveBulletMark(Transform hitPoint, bool ifEnter)
{
GameObject TemporaryBulletMarkHandler;
TemporaryBulletMarkHandler = Instantiate(BulletMarkPref, hitPoint.localPosition, Quaternion.LookRotation(ifEnter ? hitPoint.forward : CollisionPoint.normal)) as GameObject;
isThrough = false;
TemporaryBulletMarkHandler.transform.Translate(hitPoint.forward * (ifEnter ? 0.005f : -0.005f));
}
}
I don't think your problem is something simple with the code. There is an inherent issue with calculating fast moving objects like bullets with true physics calculations especially if they are small. Often between physics updates, they pass through wall colliders completely without registering.
You have to think of it like this to see the problem. The bullet isn't tracked continuously along its trajectory. It has a starting location, a formula for its movement and it calculates a new location at each physics update. You could fire a bullet straight at a wall, and in one update the bullet would be several meters in front of the wall, and in the next, it would be several meters behind the wall without ever triggering a collision. This is why so many game use ray tracing to calculate bullet trajectories. The bullet movement isn't perfectly accurate, especially for long shots, but obstructions to the bullet path are registered.
By default unity's Physics Engine runs at 50 frames per second. A modern bullet travels between 1200 and 1700 m/s. That gives you a distance between 24 and 34 meters traveled between frames. Even a small object falling at terminal velocity (54 m/s) might pass through a collider unnoticed. If you made a 1-meter thick box collider, you would likely register a falling object but not a bullet.
I think you could do some clever combination of ray tracing and bullet physics to get the best of both worlds. Maybe you could ray trace from the bullet at each fixed update or there may be some better technique already invented for this exact situation that I don't know about.
I'm making 2D mobile game and I have a ball, but my ball doesn't have a constant moving speed. What I need to do?
When I build game on my android device, ball have a various speed. In that case, my game is not playable.
I hope that someone can help me. Thanks.
This is on my start function:
void Start () {
GetComponent<Rigidbody2D> ()
.AddForce (new Vector2 (1f, 0.5f)* Time.deltaTime * force);
}
Is it a good practice if I used in code " Application.LoadLevel ("__Scena_0"); " to load existing scene when I lose " life" ? Problem happens when I lost " life " and try playing game in second chance.
My update function is about OnTriggerEnter2D when my ball hit trigger objects.
EDIT 23.12.2015. : problem solve with adding physics material (fiction 0) and adding to script:
using UnityEngine.SceneManagement;
...
SceneManager.LoadScene ("MainScene");
The problem is the calculation of the force vector:
new Vector2 (1f, 0.5f) * Time.deltaTime * force
You are using Time.deltaTime as a factor, which means that the applied force is not constant, but depending on the deltaTime, which is the duration of the last frame. This explains why it changes randomly.
I don't think Time.deltaTime is what you want here, try just removing the factor and adjusting the "force" factor accordingly. You should now have a constant force applied, independent from the platform you play on.
Create a new Physics Material, set friction zero and add it to your object. If your object has no friction, its speed cannot be decreased. Then, use AddForce() on Rigidbody2D to speed up.
Assuming that your ball and colliding walls have bouncy materials with no friction. Try
public float _ballSpeed = 2.5f;
Rigidbody2D _rb;
void Start()
{
_rb = GetComponent<Rigidbody2D>();
_rb.velocity = Vector2.one * _ballSpeed;
}
void Update()
{
}
From this you can control ball speed through _ballSpeed
//========== OR ==========//
If you want to retain speed even after ball destruction.
Retain _ballSpeed in any global static variable.
Suppose you have a class named Globals, declare a variable like,
public class Globals
{
public static float BALL_SPEED = 2.5f;
}
Now in Ball Script
Rigidbody2D _rb;
void Start()
{
_rb = GetComponent<Rigidbody2D>();
_rb.velocity = Vector2.one * Globals.BALL_SPEED;
}
void Update()
{
}