So I'm trying to make a little pushback effect in my tests arena, I've got a sphere collider and here is my script:
// PushBack Class Script
if (Input.GetKeyDown(KeyCode.Q))
{
explosion_ball.transform.position = transform.position;
StartCoroutine(WaitAndPrint());
}
IEnumerator WaitAndPrint()
{
float i = 0;
while (i < 1)
{
i += 0.01f;
explosion_ball.radius = curve.Evaluate(i) * 10;
yield return new WaitForSeconds(0.01f);
}
}
//__________//
Sphere collider is set and stuff, but it doesn't push things back like I thought it would.
Thanks!
Edit:
explosion_ball is a sphere collider, I'm changing it with the point on the animation curve and * it by 10
EDIT:Unity Rigid bodies go to sleep so[Also Change interpolation to continuous if collider changes size too quickly]
A.check if obstacle rigid bodies are Sleeping with onTriggerEnter and Wake Up
void OnTriggerEnter(collider){ if(rb.IsSleeping()){rb.WakeUp();}
or
B.Attach this forceWakeUp Script to all Objects you want to be obstacles.
using UnityEngine;
public class forceWakeUp : MonoBehaviour
{
private Rigidbody rb;
void Start()
{
rb = gameObject.GetComponent<Rigidbody>();
}
void Update()
{
if(rb.IsSleeping()){rb.WakeUp();}
}
}
Forcibly Keeping Many objects awake Will impact performance.So ,your decision.
You need to scale up the collider on the object by radius and all the objects it is supposed to wobble need to have Rigid body component attached to them
2.if you ARE doing above things and its not adding any force you could just add a force on all the overlapping objects using the "OnCollisionEnterTrigger" and AddForceMethod radially away from the Sphere
Obstacle.position - Sphere.position is the vector Radially away from Sphere I think.
You don't need coroutines for this I think.
While searching through the Unity scripting API, found a method in there called
Rigidbody.AddExplosionForce(explosionForce, explosionPosition, explosionRadius, upwardsModifier, mode)
In order to get the rigid bodies that are to be affected by the explosion I would need to get them using Physics.OverlapSphere(position, radius) this gets all of the objects within the radius variable, then get the component.
Combining these two would also look like:
Collider[] colliders = Physics.OverlapSphere(transform.position, radius);
foreach (Collider hit in colliders)
{
if (hit.transform.tag == "Interactable")
{
if (hit.gameObject != hitgameObject)
{
Rigidbody rb = hit.GetComponent<Rigidbody>();
if (rb != null)
rb.AddExplosionForce(power, transform.position, radius, upForce, ForceMode.Impulse);
}
}
}
If there is any explaining that you would like me to do about my variables mentioned I will reply :)
Thanks for the help guys.
I don't know your curve and what values that evaluation produces, but you can check your code visually with Window/Analysis/Physics Debugger, or write a gizmo:
private void OnDrawGizmos()
{
Gizmos.color = new(1.0f, 0.0f, 0.0f, 0.5f);
Gizmos.DrawSphere(explosion_ball.transform.position, explosion_ball.radius);
}
Or simply just use https://docs.unity3d.com/ScriptReference/Rigidbody.AddExplosionForce.html
Related
I am a starter in Unity and developing a soccer game. I have a problem ,my IF statements conflict each other. Let me explain it in detail.
In order for a ball to stick to player, I have used IF operator, so whenever the distance between the player and the ball is less than < 0.5 , the ball sticks to player and move together with it. Now when I try to set up shooting the ball (I try with "addforce") it doesnt let me, cause the ball is still attached to player and distance is <0.5.
This one is the balls script.
public bool sticktoplayer;
public transform player;
//gameobject Player is attached
float distancetoplayer;
Rigidbody rb;
//balls rigidbody
void Awake ()
{
rb = getComponent<Rigidbody>();
}
void Update()
{
If (!sticktoplayer)
{
float distancetoplayer = Vector3.Distance (player.position, transform.position);
if(distancetoplayer < 0.5f)
{
sticktoplayer = true;
}
}
else
{
transform.position = player.position;
}
if(Input.GetKeyDown(KeyCode.Space))
{
rb.addforce(20, 0, 0, ForceMode.Impulse);
sticktoplayer = false;
}
When the player is not controlling the ball the force is succesfully applied to the ball, but when the ball is attached (distancetoplayer<0.5) then the other IF statements blocks it from shooting.
Maybe there are some work arounds ? Thanks.
I tried to make another if statement.
why dont you try sticking the ball to the player by collision? instead of checking the distance, create a collider with the radius or scale you desire and whenever the ball is inside the collider (when it triggers with the collider) stick it to the player. Because you will not be able to let the ball go since the ball will always be less then 0.5f away from the player once it sticks
have you tried it this way?
if(Input.GetKeyDown(KeyCode.Space))
{
sticktoplayer = false;
rb.addforce(20, 0, 0, ForceMode.Impulse);
}
I need some help with Unity.
I try to make an object to detect a collision, but for some reason, the OnColissionEnter function is not called.
Both my objects have rigidBody and Box Collider attached, isTrigger is unenabled as well.
I supposed it's because I have AddForce in my code, but I am not sure. Have anybody a clue what is going wrong there?
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Cuplat2 : MonoBehaviour
{
public Vector3 Target = new Vector3();
private Rigidbody rb;
public float thrust;
private void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
Vector3 NewPosition = transform.position + Target;
Vector3 Position = transform.position;
if (transform.position.x < Target.x)
{
rb.AddForce(transform.position * thrust);
}
else
{
//rb.isKinematic = true;
}
}
public void OnCollisionEnter(Collision collision)
{
Debug.Log("stop");
if (collision.gameObject.name == "Cupla T2")
{
Debug.Log("stop");
}
}
}
One of your rigidbodies has to have isKinematic = false;
If it's not possible in your case I see they have workaround for that:
https://forum.unity.com/threads/collision-detection-for-kinematic-rigidbodies.885778/
Other option would be that the collision is disabled in collision layer mask, but that would cause objects to pass trough each other (I believe that's not the case)
Third option: your rigidbody does not have collider (maybe collider is on parent, has enabled = false, or inactive game object?)
Fourth option: If your object moves very fast you should change Collision Detection Mode to Continous Dynamic
How about the collision layer matrix? Go into Edit > Project Settings, then select the Physics. Check if the layers set to the GameObjects are actually having any collision between them. Collision Layer matrix
I'm creating a basic pool game in Unity with C#, what im trying to do is that if the cue ball is moving, the stick will disappear, and once it becomes stationary again, it will reappear to where the cue ball is located. This is my code so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class stickDeplacement : MonoBehaviour
{
public bool bIsOnTheMove = false;
Vector3 lastPos;
public GameObject Stick;
void Start()
{
}
void Update()
{
var stick = Instantiate(Stick, gameObject.transform.position, gameObject.transform.rotation);
if (this.transform.position != lastPos)
{
Destroy(stick);
Debug.Log("Is moving");
}
else
{
Debug.Log("Is not moving");
}
lastPos = this.transform.position;
}
}
But what happens is that the ball, along with the stick, will just spasm and be buggy right from the start (when I open and play the game). Am I missing something here?
This is extremely inefficient and dangerous!
Why instantiate a stick every frame just to eventually already destroy it in that very same frame? And if the ball is stationary you want an additional stick to be spawned every frame?
Instead of all the time instantiating and destroying it at all you should rather keep one stick and only (de)activate it.
In your case you could do this in a single line
bIsOnTheMove = transform.position == lastPos;
stick.SetActive(!bIsOnTheMove);
Also I doubt a lot you would like the stick to have the same rotation as a rolling ball! Of course this will behave awkward
Most certainly you do not simply want to clone the ball's orientation. I would e.g. try to determine the closest point of the table edge to the current ball's position (iterate through the wall colliders and use Collider.ClosestPoint) and let the stick face the direction from that edge point towars the ball position (+ maybe an offset in X so the stick is slightly inclined by default).
And finally you anyway do not want to assign that rotation every frame, since you most probably later want your users to be able to rotate that stick. You only want to apply this once when the ball becomes stationary.
Something like e.g.
// The stick is not a prefab anymore but simply always exists in the scene!
[SerializeField] private Transform stick;
[SerializeField] private Vector3 eulerOffset;
[SerializeField] private Collider[] wallColliders;
public bool bIsOnTheMove;
private Vector3 lastPos;
private void Start()
{
lastPos = transform.position;
}
private void Update()
{
// is the ball currently moving?
var isMoving = transform.position == lastPos;
last Post = transform.position;
// Did this state change since the last frame?
if(bIsOnTheMove == isMoving) return;
bIsOnTheMove = isMoving;
// (de)activate the stick accordingly
stick.gameObject.SetActive(!isMoving);
// Do this ONCE when ball becomes stanionary
if(!isMoving)
{
var ballPosition = transform.position;
// among the wall colliders find which one is closest to the ball
Vector3 closestPoint;
var smallestDistance = float.PositiveInifinity;
foreach(var wall in wallColliders)
{
var edgePoint = wall.ClosestPoint(ballPosition);
var distane = (edgePoint - ballPosition).sqrMagnitude;
if(distance < smallestDistance)
{
closestPoint = point;
smallestDistance = distance;
}
}
// then make the stick look towards the ball from that edge
var direction = ballPosition - closestPoint;
var rotation = Quaternion.LookRotation(direction);
// optional add the offset
rotation *= Quaternion.Euler(eulerOffset);
stick.rotation = rotation;
}
}
I've followed a C# in Unity tutorial to create a simple Space Invaders game. I'm now trying to understand the different functions being used.
There is this class called PlayerController. It also defines a shot gameobject, a field which is then supplied with a bullet prefab:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Transform player;
public float speed;
public float maxBound, minBound;
public GameObject shot;
public Transform shotSpawn;
public float fireRate;
private float nextFire;
// Start is called before the first frame update
void Start()
{
player = GetComponent<Transform> ();
}
// Update is called once per frame
void FixedUpdate()
{
float h = Input.GetAxis ("Horizontal");
if (player.position.x < minBound && h < 0)
h = 0;
else if (player.position.x > maxBound && h > 0)
h = 0;
player.position += Vector3.right * h * speed;
}
void Update()
{
if (Input.GetButton("Fire1") && Time.time > nextFire)
{
nextFire = Time.time + fireRate;
Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
}
}
}
The bullet gameobject used the class BulletController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
private Transform bullet;
public float speed;
// Start is called before the first frame update
void Start()
{
bullet = GetComponent<Transform>();
}
void FixedUpdate()
{
bullet.position += Vector3.up * speed;
if (bullet.position.y >= 10)
Destroy(gameObject);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Enemy")
{
Destroy(other.gameObject);
Destroy(gameObject);
PlayerScore.playerScore++;
}
else if (other.tag == "Base")
Destroy(gameObject);
}
}
From what I understand, a Transform object has values for position, rotation and scale.
So first, what does declaring x = GetComponent; do?
Second, where does "shotSpawn" takes its values from? From the object to which the code is applied to?
Third, the bullet gets instantiated exactly at the center of the square serving as the player ship's body, but I want it start higher at the y axis so it starts at the end of the cannon shape. It also seems to graphically intersect with the ship's body, so I wanted to move it slightly into the z axis. So how can you write that? I tried adding to the value of shotSpawn.position but it keeps declaring errors.
Thanks in advance.
A GetComponent means basically just grabbing a component of an object. Take a simple example: The Main Camera has a lot of components:
1.1. A Transform component. This component is used, as you understood, to define the position, rotation and scaling of an object
1.2. A Camera component. This has plenty of fields
1.3. A Flare Layer component.
etc.
These components can be grabbed via script. The reason developers use this is for their properties. For example, by saying Transform playerTransformComp = player.GetComponent<Transform>();, you will be able to write playerTransformComp.position. position is a property of objects of type Transform.
I don't think that the GetComponent you saw in the tutorial are useful because every game object has a transform component anyway, so if they declared the player as public GameObject player;, then used player.transform.position instead, it would have been way easier. In fact, I don't think it even makes sense to declare something as Transform, and then grabbing the Transform component. As #BugFinder said in your previous post, the tutorial is pretty bad overall.
shotSpawn takes its values from... itself! It is a public object, so I'm assuming you dragged & dropped the shotSpawn object from the scene into the script's fields. This means that the shotSpawn object from the script is the object you dragged & dropped on the script's fields. You can use all of its features and the dragged & dropped object will be affected. Thus, you can use shotSpawn.position and shotSpawn.rotation. I might be repeating myself here for a little bit, but please notice that shotSpawn is a Transform object, therefore you can use a typical Transform object's properties.
The documentation on Transform.position (as well as the one on Transform.rotation say you have to use Vector3 objects to add or substract values to them.
One would do shotSpawn.position + new Vector3(10f, 5f, 10f).
Naturally, you can also do
value = new Vector3(10f, 5f, 10f);
and then Instantiate(shot, shotSpawn.position + value, shotSpawn.rotation);
Also, please (for the future), try to ask one question per post, otherwise people will ignore your question or even flag it and it will be deleted. I was once like you, so I wouldn't do that, but please take this into consideration when making further posts.
I'm trying to make a BTD game. Since different balloons (enemies) have different speeds, they collide with each other when traveling on the path. I'm currently using this code:
void OnCollisionEnter (Collision coll)
{
if (coll.gameObject.tag == "Enemy")
{
Physics.IgnoreCollision(coll.collider, gameObject.GetComponent<SphereCollider>());
}
}
However, it doesn't appear to be working at all. The enemies still collide with each other. On the otherhand, the collision with the enemies and bullets from towers is working.
void OnTriggerEnter (Collider col)
{
if (col.tag == "Bullet")
{
CurrentHP -= col.GetComponent<TackShooterBullet>().Damage;
}
I've tried layer-collision (enemies to same layer & unchecking of the same layer collision in the layer collision matrix, but that doesn't work either. The enemy contains a sphere mesh filter, sphere collider, mesh renderer, rigidbody, material, and 2 scripts. Is there a better way to avoid collisions between the enemies. I'm asking this question since I've seen duplicates, but their solutions aren't working at all. I can provide more of my code if needed.
Edit for Clarity: Again, what I'm trying to accomplish is have the enemies be able to go through each other.
Edit (Fixed Problem): I found out to avoid Enemy Collisions, I could also remove rigidbody. However, removing the ridigbody would mess up the bullet --> enemy trigger in the enemy class. Therefore, I just wrote the collision between bullet & enemy in the bullet class instead.
using UnityEngine;
public class TackShooterBullet : MonoBehaviour {
private GameObject target;
public float Damage;
// Use this for initialization
void Start () {
target = transform.parent.GetComponent<TackShooterRange>().Target; // Target = Enemy[0] (First Enemy To Enter Range - Enemy is Removed from JList when exiting Range)
}
// Update is called once per frame
void Update()
{
Damage = gameObject.transform.parent.transform.parent.GetComponent<TackShooterLimitingRange1>().level * 20; // Upgrade Level * 20 = Damage Done
if (target == null) // If Enemy Exits Range
{
Destroy(gameObject); // Destroy Bullet
}
if (target != null) // Enemy Exists In Range
{
transform.position = Vector3.MoveTowards(transform.position, target.transform.position, 20 * Time.deltaTime); // Bullet Follows Enemy
Destroy(gameObject); // Destroy Bullet Upon Contact With Enemy
target.GetComponent<HealthOfEnemy>().CurrentHP -= Damage; // Enemy Loses Health
}
}
This allowed me to remove the OnTriggerEnter & OnCollisionEnter methods as well as the RigidBody from the Enemy Class as stated before, so these properties no longer affect the collisions between Enemies.
Unity has a built in function for easier collision detection called layer-based collision detection:
https://docs.unity3d.com/Manual/LayerBasedCollision.html
The documentation is really good. Just comment if you need further clarification.