Unity RigidBody2D.AddForce() method stopped player movement, stuck without move - c#

I'm trying to move my player using RigidBody2D.AddForce() method but whenever and i apply force to player on any direction then player moves for sometime then immediately stuck at random locations on level (Tile) and doesn't move ahead until opposite direction is pressed.
I wanted to move player normally without immediately making velocity = 0 like experience. It should follow slow decrease in acceleration as per force rule. I have checked my player movement on normal rigidbody without using Tilemap tiles. It's working fine but player stuck when using Tilemap tile level.
I'm calling methods using Pointer Down and Pointer Up event system for my 100px x 100px sized sprites as shown in image.
My Code:
public class PlayerScript : MonoBehaviour
{
Rigidbody2D playerRigidBody;
float speed=15f;
float forceX,forceY;
float maxVeloX,maxVeloY;
bool isMoveLeft,isMoveRight,isMoveUp;
void Start()
{
playerRigidBody=GetComponent<Rigidbody2D>();
isMoveLeft=isMoveRight=isMoveUp=false;
}
void Update()
{
forceX=forceY=0f;
maxVeloX=Mathf.Abs(playerRigidBody.velocity.x);
maxVeloY=Mathf.Abs(playerRigidBody.velocity.y);
if(isMoveRight) {
if(maxVeloX<6){
forceX= speed;
transform.localScale=new Vector3(1,1,1); // to face player right direction
}
}else if(isMoveLeft ){
if(maxVeloX<6){
forceX= -speed;
transform.localScale=new Vector3(-1,1,1); // to face left direction
}
}
else if(isMoveUp )
forceY=25f;
playerRigidBody.AddForce(new Vector2(forceX,forceY));
}
public void MoveLeftStart(){ // button left press
isMoveLeft=true;
}
public void MoveLeftEnd(){ // button left release
isMoveLeft=false;
}
public void MoveRightStart(){
isMoveRight=true;
}
public void MoveRightEnd(){
isMoveRight=false;
}
public void MoveUpStart(){
isMoveUp=true;
}
public void MoveUpEnd(){
isMoveUp=false;
}
}
My Tilemap level:

If understand right:
Your problem is caused by the fact that you are using a tilemap system made of squares colliders. And your Rigidbody is always pushed to the ground due to gravity. So everytime you collide with a corner of these colliders your character is stuck.
I suppose you are using one object to store your whole tilemap.\
If it's the case:
Go to the object your tilemap sit on.
Add component, Composite Collider 2D
On your Tilemap Collider 2D check "Used by composite"
Still in the object that contains your Tilemap:
Go on the rigidbody and set it to static
The composite collider will remove all those separate squares and regroup them.
It will remove all those little spikes.
And now (i hope) your problem is gone...

Related

Unsure how to script my AI GameObject to aim at player with bullet, taking into account for gravity and drag (UNITY)

I'm currently working on a unity project where I'm testing out how to create a projectile trajectory calculation method, which'll be applied to my overall larger Unity project. Inside of this sub-project is simply a ground plane, a square target GameObject, and my AI Enemy GameObject. For reference, here's what the hierarchy of my enemy GameObject looks like:
Enemy (capsule)
GunPivot (empty, is an anchor to rotate the Gun GameObject)
Gun (square)
BulletSpawn (empty, is the spawn point for any instantiated bullet)
Now how my bullet works inside of this scene is that my bullet has a rigidbody, and moves through the scene using the Unity's physics engine, and my gun GameObject has the script that spawns, aligns, and shoots the bullet forward. It just uses AddForce() and a FirePower variable, which can be set in the unity editor. Below is what the code looks like:
public class EnemyGunController : MonoBehaviour
{
//
// Properties & Fields
//
public GameObject BulletPrefab;
public GameObject BulletSpawn;
public float FireRate;
public float FirePower;
public bool CanFire;
//
// Method(s)
//
void Update()
{
StartCoroutine(Fire());
}
// Fires a bullet.
IEnumerator Fire()
{
if (CanFire)
{
CanFire = false;
// Instantiate a bullet. Set the rotation to be looking forwards relative to BulletSpawn
GameObject bullet = Instantiate(BulletPrefab, BulletSpawn.transform.position,
Quaternion.LookRotation(BulletSpawn.transform.up));
// Set bullet so that it ignores collisions with the gun.
Physics.IgnoreCollision(bullet.GetComponent<Collider>(), GetComponent<Collider>());
// Apply force to the bullet.
bullet.GetComponent<Rigidbody>().AddForce(BulletSpawn.transform.forward * FirePower, ForceMode.Impulse);
// Wait for the fire rate before firing again.
yield return new WaitForSeconds(FireRate);
CanFire = true;
}
}
}
Now here's where the issue now lies. I want my Enemy GameObject to hold a method that'll calculate at what rotational value GunPivot needs to be at in order for the Bullet to hit the target GameObject. I already know that Quaternion.LookAt() will rotate the gun to where the target is, but that only solves half of the issue. That rotates the gun horizontally to where the gun is (y-axis I believe), but now I need to check at which rotational value GunPivot needs to be at so that the bullet, which is a rigidbody and has non-zero values for its mass and drag, will hit the target GameObject.
I did look into this a bit and found out the Physics.Simulate() method and how I can calculate this in a separate scene, however when I ran the unity editor, it just froze and then crashed. I attached it to a separate GameManager GameObject, and here's the code for it below:
public class BulletPredictor : MonoBehaviour
{
//
// Properties & Fields
//
public GameObject BulletPrefab;
Scene _mainScene;
Scene _bulletPredictorScene;
PhysicsScene _mainPhysicsScene;
PhysicsScene _bulletPredictorPhysicsScene;
//
// Method(s)
//
void Start()
{
// Disable auto simulation.
Physics.autoSimulation = false;
// Set the main scene and main physics scene fields.
_mainScene = SceneManager.GetSceneByName("MainScene");
_mainPhysicsScene = _mainScene.GetPhysicsScene();
// Set the bullet predictor scene and bullet predictor physics scene fields.
CreateSceneParameters bulletPredictorSceneParameters = new(LocalPhysicsMode.Physics3D);
_bulletPredictorScene = SceneManager.CreateScene("BulletPredictorScene", bulletPredictorSceneParameters);
_bulletPredictorPhysicsScene = _bulletPredictorScene.GetPhysicsScene();
}
// FixedUpdate is called once per frame (fixed at 50 fps).
void FixedUpdate()
{
// Main scene physics need to work, so simulate main scene normally. Needs to be within a fixed update because variable fps can effect the physics simulation.
if (_mainPhysicsScene.IsValid())
{
_mainPhysicsScene.Simulate(Time.fixedDeltaTime);
}
}
// Simulates various shot trajectories to find an optimal shooting angle to hit target, then rotates enemy's gun in main scene to that angle.
public Quaternion ShootBullet(GameObject shooter, GameObject target, Vector3 shooterPos, Vector3 targetPos)
{
// Checks if the main or bullet predictor physics scene is valid. If it isn't just return a default rotation.
if (!_mainPhysicsScene.IsValid() || !_bulletPredictorPhysicsScene.IsValid())
return Quaternion.identity;
// Clone shooter, and move it to the bullet predictor scene.
GameObject shooterClone = Instantiate(shooter, shooterPos, Quaternion.identity);
SceneManager.MoveGameObjectToScene(shooterClone, _bulletPredictorScene);
// Also clone target, and move it to the bullet predictor scene.
GameObject targetClone = Instantiate(target, targetPos, Quaternion.identity);
SceneManager.MoveGameObjectToScene(targetClone, _bulletPredictorScene);
// Get a reference to shooterClone's GunPivot gameobject.
GameObject gunPivot = shooterClone.transform.Find("GunPivot").gameObject;
// Rotate gunPivot to face targetClone.
gunPivot.transform.LookAt(targetClone.transform);
while (gunPivot.transform.rotation.x > -90)
{
// Instantiate a bullet, and move it to the bullet predictor scene. Set the rotation to be the shooterClone's BulletSpawn's rotation.
GameObject bullet = Instantiate(BulletPrefab, gunPivot.transform.position, Quaternion.LookRotation(gunPivot.transform.up));
// Add force to the bullet.
bullet.GetComponent<Rigidbody>().AddForce(gunPivot.transform.forward * bullet.GetComponent<BulletBehavior>().InitialSpeed, ForceMode.Impulse);
// Loop for 200 iterations, and simulate the bullet.
for (int i = 0; i < 200; i++)
{
// Simulate bullet predictor scene.
_bulletPredictorPhysicsScene.Simulate(Time.fixedDeltaTime);
}
// if the bullet is destroyed, break.
if (bullet == null)
{
break;
}
Destroy(bullet);
gunPivot.transform.Rotate(-0.1f, 0, 0);
}
return gunPivot.transform.rotation;
}
}
For debugging purposes, I just added a variable that referenced the GunPivot on my Gun GameObject, and called the ShootBullet() before I actually started the Fire() method, but my unity editor ended up crashing every single time I ran with this code. I'm not entirely sure why this didn't work, although I believe that this happened since I was using Simulate() in a numerical calculation, which probably is VERY VERY computationally expensive.
I'd really appreciate any insight or tips on how to either improve the simulate code I have above or perhaps try out a different approach from it what I'm doing. Also FYI, you can assume that the target isn't moving, so that might make things easier I suppose?

Unity OnBecameInvisible() fires though object is still visible

I have a Mesh Renderer and a script assigned to a rotating sphere with a hole in it. The sphere has no specific or special place in hierarchy, its just next to the camera. The script part looks like this:
void OnBecameInvisible() {
Destroy(gameObject);
}
Problem is, that when I pass the sphere with my ball, even though the sphere is still half visible, it gets deleted. I have no other camera in the scene, and the one Im using is marked as the main camera.
Video
Instead of using OnBecameInvisible for culling objects you've passed, just check if it's sufficiently behind the camera in Update:
Camera mainCam;
[SerializeField] float maxBehindDistance = 0.5f;
void Awake() { mainCam = Camera.main; }
void Update()
{
Vector3 relPos = mainCam.transform.InverseTransformPoint(transform.position);
if (relPos.z < -maxBehindDistance)
{
Destroy(gameObject);
}
}

What code do I need for my Unity character to shoot the bullet correctly?

I am not new to programming, but I am new to C#. I am experienced in Python, Java, and HTML. My game is 2D I have a game where my character currently has to touch the enemy to kill it. Now I added code for shooting a bullet to kill the enemy. I also want the bullet to be shot if the spacebar is pressed. The character is supposed to a shoot bullet in either direction. I have taken my code from an example my professor gave me which was originally Javascript and I converted it to C#. Unity no longer supports Javascript. The example code he gave me was basically a rocket shooting as many bullets as I clicked (clicking the mouse shoots bullets) to eliminate an enemy, however the rocket in that example does not move. In my game, the character moves, so the bullet has to get the position of the character. What is the correct code for getting the character position and shooting a bullet correctly?
I tested my game with my current code. The bullet is being spit out of nowhere (from the bottom of my background wallpaper [smack in the middle of the bottom] to a little below the wallpaper). Not even from the character...
Also, I added the Hit class script to my Bullet category in Unity.
Complete Camera Controller (no issues here at all)
using UnityEngine;
using System.Collections;
public class CompleteCameraController : MonoBehaviour {
public GameObject player; //Public variable to store a reference to the player game object
private Vector3 offset; //Private variable to store the offset distance between the player and camera
// Use this for initialization
void Start ()
{
//Calculate and store the offset value by getting the distance between the player's position and camera's position.
offset = transform.position - player.transform.position;
}
// LateUpdate is called after Update each frame
void LateUpdate ()
{
// Set the position of the camera's transform to be the same as the player's, but offset by the calculated offset distance.
transform.position = player.transform.position + offset;
}
}
Complete Player Control Class (If you read the comments in the code that say the "BULLET CODE", that's new code I have placed in the game for the bullets.
using UnityEngine;
using System.Collections;
//Adding this allows us to access members of the UI namespace including Text.
using UnityEngine.UI;
public class CompletePlayerController : MonoBehaviour
{
public float speed; //Floating point variable to store the player's movement speed.
public Text countText; //Store a reference to the UI Text component which will display the number of pickups collected.
public Text winText; //Store a reference to the UI Text component which will display the 'You win' message.
private Rigidbody2D rb2d; //Store a reference to the Rigidbody2D component required to use 2D Physics.
private int count; //Integer to store the number of pickups collected so far.
Rigidbody2D bullet;
float speed2 = 30f; //BULLET CODE
// Use this for initialization
void Start()
{
//Get and store a reference to the Rigidbody2D component so that we can access it.
rb2d = GetComponent<Rigidbody2D> ();
//Initialize count to zero.
count = 0;
//Initialze winText to a blank string since we haven't won yet at beginning.
winText.text = "";
//Call our SetCountText function which will update the text with the current value for count.
SetCountText ();
}
//FixedUpdate is called at a fixed interval and is independent of frame rate. Put physics code here.
void FixedUpdate()
{
//Store the current horizontal input in the float moveHorizontal.
float moveHorizontal = Input.GetAxis ("Horizontal");
//Store the current vertical input in the float moveVertical.
float moveVertical = Input.GetAxis ("Vertical");
Rigidbody2D bulletInstance; //BULLET CODE
//Use the two store floats to create a new Vector2 variable movement.
Vector2 movement = new Vector2 (moveHorizontal, moveVertical);
//Call the AddForce function of our Rigidbody2D rb2d supplying movement multiplied by speed to move our player.
rb2d.AddForce (movement * speed);
if(Input.GetKeyDown(KeyCode.Space)&& Hit.hit == false) //BULLET CODE IN HERE
{
// ... instantiate the bullet facing right and set it's velocity to the right.
bulletInstance = Instantiate(bullet, transform.position, Quaternion.Euler(new Vector3(0,0,0)));
bulletInstance.velocity = new Vector2(speed2, 0);
bulletInstance.name = "Bullet";
}
}
//OnTriggerEnter2D is called whenever this object overlaps with a trigger collider.
void OnTriggerEnter2D(Collider2D other)
{
//Check the provided Collider2D parameter other to see if it is tagged "PickUp", if it is...
if (other.gameObject.CompareTag ("PickUp"))
{
//... then set the other object we just collided with to inactive.
other.gameObject.SetActive(false);
transform.localScale += new Vector3(0.1f, 0.1f, 0);
//Add one to the current value of our count variable.
count = count + 1;
//Update the currently displayed count by calling the SetCountText function.
SetCountText ();
}
}
//This function updates the text displaying the number of objects we've collected and displays our victory message if we've collected all of them.
void SetCountText()
{
//Set the text property of our our countText object to "Count: " followed by the number stored in our count variable.
countText.text = "Count: " + count.ToString ();
//Check if we've collected all 12 pickups. If we have...
if (count >= 12)
//... then set the text property of our winText object to "You win!"
winText.text = "You win!";
}
}
Hit code. All code in this class is made for the bullet.
using UnityEngine;
using System.Collections;
public class Hit : MonoBehaviour
{
GameObject[] gameObjects;
public static bool hit = false;
void Removal ()
{
gameObjects = GameObject.FindGameObjectsWithTag("Bullet");
for(var i= 0 ; i < gameObjects.Length ; i ++)
Destroy(gameObjects[i]);
}
void OnCollisionEnter2D ( Collision2D other )
{
if(other.gameObject.name=="Bullet")
{
Removal();
Destroy(gameObject);
hit = true;
}
}
}
I see several issues with the code you wrote. as #Kyle Delaney suggested, I'd also highly recommend you check out the Unity Learn website, and go through several tutorials before moving through. I've highlighted a few issues below that may help solve your problem, but you could really benefit from changing your approach in the first place to avoid many of these issues. See below.
In your camera controller class, why not make the offset public so you can set it yourself in the inspector>
In Player controller class:
changed:
if (Input.GetKeyDown(KeyCode.Space)) //Shoot bullet
{
// ... instantiate the bullet facing right and set it's velocity to the right.
Rigidbody2D bulletRB = Instantiate(bullet, transform.position, transform.rotation);
bulletRB.AddForce(new Vector2(speed2,0), ForceMode2D.Impulse);
}
On a click, this instantiates the bullet prefab and sets its transform to copy the position and rotation of the player. It then adds a force to it to the right. You should avoid setting the velocity manually with rigidbodies, this can cause unwanted behaviour. Use the Addforce/addTorque methods instead. The ForceMode says to ignore its mass and set its velocity.
Then delete your Hit class, and replace with this Bullet class, which you drag onto the bullet prefab. Your player shouldn't be in charge of checking for bullet hits. that's the bullet's job. The player just launches the bullets and then the bullets do what bullets do. this just checks to see if the bullet hit anything, if so it destroys it. You can make this more complicated if you want. I would recommend using layers to determine which layers the bullet checks collisions with. You probably don't want bullets destroying your terrain. and you definitely don't want bullets destroying the player itself!
public class Bullet : MonoBehaviour
{
private void OnCollisionEnter2D(Collision2D collision)
{
Destroy(collision.gameObject);
Destroy(this.gameObject);
}
}
Also you shouldn't need to set the name of the bullet, since your prefab bullet should already be named "bullet".
I hope this gets you started in the right direction. But based on your code, I HIGHLY recommend you work through the tutorials before continuing with any projects. The unity staff that make them are super helpful and the tutorials start off really simple but get really complicated fast, so you actually come away learning a ton!
Perhaps the problem has to do with the player's parent transform. You could try something like this to make sure the bullet has the right parent:
bulletInstance = Instantiate(bullet);
bulletInstance.transform.parent = transform.parent;
bulletInstance.transform.position = transform.position;
bulletInstance.velocity = new Vector2(speed2, 0);
bulletInstance.name = "Bullet";
If that doesn't work it may be worthwhile to check the player's Rect Transform to see where the anchors and pivot are. Perhaps the player's actual "position" coordinates aren't where you think they are.
Have you done the Space Shooter tutorial? It has a segment about shooting bullets.

Why the waypoints are working when they are spheres but with cylinder not?

The waypoints example is from the unity docs tutorial site.
When i put two spheres the enemies will go between them and also not good when they get to one way point they are not turning back sharp 180 degrees but they are like moving backward without turning and then turning. What i want to do is when they get to a way point to turn sharp 180 degrees on the place then to start walking to the other way point. How can i do it ? Shoud i add a state in the animator for that ?
The second problem is when i put the cylinder as waypoint with one sphere the enemies will go to the sphere and will stay there then will make rounds around the sphere they will never get to the cylinder.
This is a screenshot of the scene after baking it.
I set the Terrain to be Navigation Static and Walkable.
I also set the Spheres and the Cylinder to be Naviagtion Static and Walkable.
Guard and Guard 1 are the enemies(ThirdPersonController)
This is a screenshot of the scene the two enemies of the left the two spheres and the big cylinder.
This is the patrol script:
using UnityEngine;
using System.Collections;
public class Ai : MonoBehaviour {
public Transform[] points;
private int destPoint = 0;
private NavMeshAgent agent;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent> ();
agent.autoBraking = false;
GotoNextPoint ();
}
void GotoNextPoint()
{
if (points.Length == 0)
return;
agent.destination = points [destPoint].position;
destPoint = (destPoint + 1) % points.Length;
}
// Update is called once per frame
void Update () {
if (agent.remainingDistance < 1.5f)
GotoNextPoint ();
}
}
This is a shot video clip i recorded show how they are patrolling.
And also the main player is getting angry all the time not sure why.
Clip

Unity3D Collider2D don't collide with translated Collider2D

I am trying to bounce the tile above the circle on top of the platform, there is no problem when the platform is fixed, but when the script who make the platform move is activated, the tile crash the circle.
This is the script for moving the platform:
using UnityEngine;
using System.Collections;
public class PlatformMoveH : MonoBehaviour {
public float min;
public float max;
public float speed;
public float sens;
void Start(){
sens *= speed;
}
void Update () {
if (transform.localPosition.x > max) {
sens = -speed;
} else if (transform.localPosition.x < min){
sens = speed;
}
transform.Translate (sens * Time.deltaTime, 0, 0);
}
}
i can't add pictures here but in unity answers you can understand the problem better with pictures
http://answers.unity3d.com/questions/1009619/collider2d-and-translate-problem.html
i have no idea what is the problem.
can anyone help me please
You have to add a kinematic Rigidbody2D to your moving colliders. Colliders without a rigidbody are treated as static colliders by Unity and should never be moved.
From the official documentation:
The physics engine assumes that static colliders never move or change and can make useful optimizations based on this assumption. Consequently, static colliders should not be disabled/enabled, moved or scaled during gameplay. If you do change a static collider then this will result in extra internal recomputation by the physics engine which causes a major drop in performance. Worse still, the changes can sometimes leave the collider in an undefined state that produces erroneous physics calculations. For example a raycast against an altered Static Collider could fail to detect it, or detect it at a random position in space.

Categories