Unity 2D Game - Making rigidbodies fly in a straight line - c#

I want to create a 2D game and for that i need to create a number of rigidbodies 2D that fly in a constant speed without stopping (at least for the start). I created an array of GameObjects and everythink was good (I also created a bounds check).
My problem is that I gave every gameobject an equal velocity that remains equal (every fixedupdate), but for some reason they do not keep moving in a straight line (one gameobject is getting closer to another and away from another gameobject etc).
Here is the physics code:
private void FixedUpdate(){
if (ballsAreMoving) {
foreach(GameObject ball in balls){
ball.gameObject.GetComponent<Rigidbody2D> ().velocity = ball.gameObject.GetComponent<Rigidbody2D> ().velocity.normalized * ballSpeed;
}
}
}
IEnumerator FireBalls() {
foreach(GameObject ball in balls){
////////////////Create ball
ball.transform.position = transform.position;
ball.SetActive(true);
////////////////Realese ball
ball.gameObject.GetComponent<Rigidbody2D> ().velocity = (new Vector2(lineDirection, 10) * ballSpeed);
yield return new WaitForSeconds(shootDelay);// Delay
}
}
The FireBalls function is called once after the balls are created and the ballsAreMoving bool is true after FireBalls is called.
Thanks in advance.

Related

Conflicting IF statements in Unity C# , Soccer Game

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);
}

How to make a pushable rigidbody not get stuck in a non-pushable rigidbody

Brand new to Unity/C# so this might be a stupid error. I have a player and a push-able box that when pushed towards another object (that usually the player cannot walk through) causes the box to stop moving and the player to get stuck and be unable to move but stuck mid-animation.
They basically just all get stuck in eachother
https://i.stack.imgur.com/rkNtu.png
I followed tutorials for a lot of these things but couldn't manage to find one for pushing the box so I did it by myself, which is what I'm thinking caused these issues.
The player has a 2D circle collider and a 2D rigidbody (with a dynamic body type and discrete collision detection).
It also has all of its code to do with walking that looks like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
//Movement speed variable
public float moveSpeed;
//Giving information of where the collisions layer is (edited in actual unity)
public LayerMask collisionsLayer;
//Variable to check if the character is moving
private bool isMoving;
private Vector2 input;
//Animation SetUp
private Animator animator;
private void Awake()
{
animator = GetComponent<Animator>();
}
//End of Animation SetUp
private void Update()
{
//If the player is NOT moving
if (!isMoving)
{
//'GetAxisRaw' gives 1 or -1 --> right = 1, left = -1
input.x = Input.GetAxisRaw("Horizontal");
input.y = Input.GetAxisRaw("Vertical");
//Making it so that the player cannot move diagonally
if (input.x != 0) input.y = 0;
if (input != Vector2.zero)
{
//Animation section
animator.SetFloat("moveX",input.x);
animator.SetFloat("moveY",input.y);
//End of animation section
var targetPos = transform.position;
//Adds 1 or -1 depending on the key input (GetAxisRaw)
targetPos.x += input.x;
targetPos.y += input.y;
if (IsWalkable(targetPos))
//Calls coroutine 'IEnumerator Move'
StartCoroutine(Move(targetPos));
}
}
//for animation
animator.SetBool("isMoving",isMoving);
//Special type of function w/ 'IEnumerator' as return type. Used to do something over a period of time.
IEnumerator Move(Vector3 targetPos)
{
isMoving = true;
//Checks if the diff between the target position & the players current position is greater than a vry small value
while ((targetPos - transform.position).sqrMagnitude > Mathf.Epsilon)
{
//If there is a diff btwn targetpos & the current position --> we will move the player towards the target position by a very small amount
transform.position = Vector3.MoveTowards(transform.position, targetPos, moveSpeed * Time.deltaTime);
//Stops execution of the coroutine, resumes it in the next update function
yield return null;
}
//Sets the players current position to the target position
transform.position = targetPos;
isMoving = false;
}
}
//Checking if the next available tile is actually able to be walked on / if the next tile is blocked
private bool IsWalkable(Vector3 targetPos)
{
if(Physics2D.OverlapCircle(targetPos, 0.1f, collisionsLayer) != null)
{
return false;
}
return true;
}
}
The box has a box collider 2D and a 2D rigidbody (dynamic bodytype; discrete collision detection)
And the collisions tilemap (which is set to be used by the composite) has a tilemap collider 2D, rigidbody 2D (static) and a composite collider 2D
If anyone actually knows how to make it so that the entire game doesn't break when I try to move the box past objects, that'd be really helpful because I've been working on this for ages and haven't figured anything out at all
You should try running the debugger. I think you're finding yourself in an interlocked condition, where your character can't get to the target position (because it's blocked), but it hasn't reached the target position (because it's blocked), so it keeps trying to move, which prevents you from giving it a new command.
I think the easiest way to work around this is to cache your target directions - should be in positive x, positive y, or negative x, or negative y. Then, if you detect the user trying to move in the opposite direction you cancel the move and start a new one.
There are lots of ways to work around this, though, and I do see you are trying to check the target before moving to it, but you're checking the raw input, which may overshoot an obstacle. For example, if the tree is at 0.5 meters, but you're looking at a target of 1 meter, then the target is clear. You get blocked by the tree at 0.5 meters, and because you never reach 1 meter you never exit the coroutine.
You've got to run a debugger and step through the code and see what specifically isn't responding.

How to check how hard an object hits the ground and create an explosive "force" around it

Recently I have started my first 2D game project on unity and everything has been going well. My only problem so far is with my enemy. My enemy, when attacking, jumps in the air and then falls and hits the ground. I want my script to detect when it falls and how hard it falls then create a force that pushes the player back as if its an "explosion."
So my questions are how do I detect the enemy hitting the ground, after a fall, and then add a force?
I tried using onCollisionEnter2D on Unity but it does not work since technically even when the enemy is moving it's still "falling."
Here is my attempt at checking if the enemy fell then searching for the player and calling the explosion force function.
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.tag == "Ground")
{
foreach (Collider2D Obj in Physics2D.OverlapCircleAll(transform.position, radius))
{
if (Obj.GetComponent<Rigidbody2D>() != null && Obj.gameObject != gameObject)
{
Debug.Log("Calling Function");
Rigidbody2D rb = Obj.GetComponent<Rigidbody2D>();
ExplosionForce2D forceScript = GetComponent<ExplosionForce2D>();
forceScript.AddExplosionForce(rb, force, transform.position, radius);
}
}
}
}
This is my code for adding a force to the object.
public void AddExplosionForce (Rigidbody2D body, float expForce, Vector3 expPosition, float expRadius)
{
var dir = (body.transform.position - expPosition);
float calc = 1 - (dir.magnitude / expRadius);
if (calc <= 0) {
calc = 0;
}
body.AddForce (dir.normalized * expForce * calc);
}
I expect that, if the player is in the enemy radius, and the enemy jumps, falls, and hits the floor it will push the player back as if it was an explosion.
you can use a flag that can check that if the enemy is falling or not, so when your enemy is actually falling set this as true, if not (means moving) then set as false.
Checking for Velocity is a good solution.
So you can do like,
body.velocity.magnitude
// magnitude to remove the direction issue.
// now apply all this as
body.AddForce(dir.normalized * expForce * calc * body.velocity.magnitude);

Ball object slows down without gravity

I'm making a 2D Block breaker game; the issue is that my ball will slow down after a while, yet there isn't any gravity and the bounciness is at 100% so it should keep all its kinetic energy. I just need the ball to stay at a constant speed.
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ball : MonoBehaviour {
public Paddle paddle;
private Vector3 paddleToBallVector;
private bool Started = false;
void Start () {
paddleToBallVector = this.transform.position
paddle.transform.position;
print(paddleToBallVector);
//this.GetComponent<Rigidbody2D>().drag = 0f;
}
void FixedUpdate () {
if (!Started) {
this.transform.position = paddle.transform.position + paddleToBallVector;
if (Input.GetMouseButtonDown(0))
{
Debug.Log("mouse clicked, Started = " + Started);
Started = true;
this.GetComponent<Rigidbody2D>().velocity = new Vector2(2f, 10f);
}
}
}
}
The issue isn't in the code - it's in the game Gravity settings. You could solve it in one of two ways:
1) change the gravity scale of the ball - go to the ball game object or Prefab, and look at the RigidBody2D component. In there, you have a field called "Gravity Scale", usually set to 1. Changing it to 0.1 will make your ball light and quick. However, this setup isn't ideal for a game with multiple levels.
2) Change the global gravity in the project settings. Go in the Edit Menu to the Project Settings and in the menu choose Physics2D:
In the panel that is opened you usually have a realistic gravity scale of -9.81. Change it to something like -1.
This will make all the objects in your game light, and lessen the hold of gravity for all levels. In a brick-breaker type game when only the ball is loose and thrown around, it makes the most sense.
If you want the ball to have constant velocity, you could set it each frame in Update
myRigidbody.velocity = speed * (myRigidbody.velocity.normalized);
Where myRigidBody is a private RigidBody declared somewhere in your script, and set in Start() like this
myRigidbody = this.GetComponent<Rigidbody>();
Because you dont want to have to call GetComponent every single frame.
Create a physics material 2D. Keep the bounciness at 1 but reduce the friction to zero. Now attach that material to your Ball Collider. Your ball won't lose any speed when colliding now

Simple code doesn't work

I try to move my character but he moves through the border of the scene.
When I debug it sayscharTransform has 0 0 0 coords in Vector3.
Transform charTransform;
float leftHorizontalBound;
float rightHorizontalBound;
void Start()
{
charTransform = this.transform;
leftHorizontalBound = camera.ViewportToWorldPoint (new Vector3 (0,0, camera.nearClipPlane)).x;
rightHorizontalBound= camera.ViewportToWorldPoint (new Vector3 (1,0, camera.nearClipPlane)).x;
}
void Update()
{
if(charTransform.position.x <= leftHorizontalBound)
{
charTransform.position = new vector2(leftHorizontalBound + 0.1f);
return;
}
if(charTransform.position.x >= rightHorizontalBound)
{
charTransform.position = new vector2(rightHorizontalBound - 0.1f);
return;
}
//MAKE HERE YOUR MOVEMENT BASED ON INPUT.
}
i cant exactly say what is your problem and wish you assume your problem more accurate but i think you are working something like a boad game with a fixed camera and something like a ball always moves and you just want to keep that object in the scene.
in your code you defined a position by variables and made a position check for every frame. thats not what basically is done in unity and there will be problems. you can make an empty object and put in on the borders you want and check the position of that object with your moving object.
your next way is make an object and add a collider component to it. if your game is 3d add a collider and if its 2d game add a 2d collider and a collider to moving object and after that it never moves toward the borders but still there will be some limits so if it didnt work i think you should add a rigidBody to both of them.

Categories

Resources