Hey I just want my bullet to destroy itself when it touch Ground i tried to destroy after 2 seconds but it has the same problem That's My Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyBullet : MonoBehaviour
{
GameObject target;
public float speed;
Rigidbody2D bulletRB;
void Start()
{
bulletRB = GetComponent<Rigidbody2D>();
target = GameObject.FindGameObjectWithTag("Player");
Vector2 moveDir = (target.transform.position - transform.position).normalized * speed;
bulletRB.velocity = new Vector2(moveDir.x, moveDir.y);
Destroy(this.gameObject, 2);
}
}
Destroy the bullet object using the Destroy method.The bullet is destroyed after flying a certain distance.
public float speed;
public float destoryDistance;
private Rigidbody2D rg2d;
private Vector3 startPos;
// Start is called before the first frame update
void Start()
{
rg2d = GetComponent<Rigidbody2D>();
rg2d.velocity = transform.right * speed;
startPos = transform.position;
}
// Update is called once per frame
void Update()
{
float distance = (transform.position - startPos).sqrMagnitude;
if (distance > destoryDistance)
{
Destroy(gameObject);
}
}
Use OnCollisionEnter() to destroy to bullet
void OnCollisionEnter(Collision collider)
{
if (collider.GameObject.tag == "Ground")
{
Destroy (this.GameObject)
}
}
What's happening here is that this function gets called every time it collides with an object, so we put the destroy code here. It takes the collider as a parameter, and then checks if the GameObject has the tag "Ground", and if it does, destroy itself.
Note that you will also have to add a tag to your ground objects in the hiearchy. You can name them anything else too, but make sure to change "Ground" in the code when you do set the tag to anything other than it.
You will probably also have other colliders like walls in your game so you should make a universal tag that destroys bullets and name it something like "Destroy Projectiles" or something.
Edit: You can have multiple functions that destroy the GameObject.
Related
I have a script that moves instantiated game objects depending on their tag. However, the game objects that have been instantiated are not moving.
Instantiation Script:
void Update()
{
tillNextSpawn += Time.deltaTime;
Debug.Log(tillNextSpawn);
if (tillNextSpawn >= 2)
{
UnityEngine.Debug.Log("Instantiating circle");
screenPosition = Camera.main.ScreenToWorldPoint(new Vector3(Random.Range(0, Screen.width), Random.Range(0, Screen.height), Camera.main.farClipPlane / 2));
Instantiate(circle, screenPosition, Quaternion.identity);
tillNextSpawn = 0.0f;
}
}
Enemy controller script(moves the enemies)
void FixedUpdate()
{
/*GameObject[]*/
var objects = GameObject.FindGameObjectsWithTag("Enemy");
var objectCount = objects.Length;
foreach (var obj in objects)
{
// Move the players accordingly
var rb = obj.GetComponent<Rigidbody2D>();
Debug.Log(rb);
Vector2 direction = (player.position - obj.transform.position).normalized;
rb.velocity = direction * moveSpeed;
}
}
You should be able to that, and the issue maybe somewhere else in your project.
I created a sample project that recreates what you're trying to do, trying to be as similar as I could be to the sample code you send, you can find it here:
https://github.com/webocs/unity-so-sample-tags
For what I can see, your console is sending an exception
get_main is not allowed to be called...
What comes to my mind, is that that exception is breaking the entire execution, and that's why nothing is happening.
As a side note, I don't know your project so I don't really know why you're building it this way. Said that, why aren't you creating an Enemy script that's attached to the enemy prefab? If you have many enemies you're going to be finding and iterating through all of them in each update tic. If you create an Enemy script and attach it to the prefab you should be able to handle the movement of the enemy using the transform of the gameObject that the script is attached to. This way each enemy is a standalone entity.
I hope all of this helps!
Edit:
I've edited the repo and added a scene called "IndividualEnemies" that illustrates what I told you in the comments
If you want the enemy to follow the player, try doing the following:
//Attach this script to the enemy
Transform player;
private Rigidbody2D rb;
private Vector2 movement;
public float moveSpeed;
void Awake()
{
player = ScriptNameOnPlayer.instance.gameObject.transform;
}
// Start is called before the first frame update
void Start()
{
rb = this.GetComponent<Rigidbody2D>();
}
void Update()
{
Vector3 direction = player.position - transform.position;
direction.Normalize();
movement = direction;
}
void FixedUpdate()
{
moveCharacter(movement);
}
void moveCharacter(Vector2 direction)
{
rb.MovePosition((Vector2)transform.position + (direction * moveSpeed * Time.deltaTime));
}
//But make sure your player script has this line of code:
public static ScriptNameOnPlayer instance;
Hope this helps !
I'm making a third person sports game and I wish to shoot the ball straight forward from the player.
I have a working script for shooting the ball, however it is attached to the main camera so only shoots in the direction the camera is facing.
I would like to alter this code to attach it to the player instead of the camera.
PS: I am still very new to C#, I assume the problem is in the "camera.main.transform" section but I don't know the code to change it to player.
my code is below;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShootScript : MonoBehaviour
{
public GameObject bulletPrefab;
public float shootSpeed = 300;
Transform cameraTransform;
void Start()
{
cameraTransform = camera.main.transform;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
shootBullet();
}
}
void shootBullet()
{
//Get the Rigidbody that is attached to that instantiated bullet
Rigidbody projectile = GetComponent<Rigidbody>();
//Shoot the Bullet
projectile.velocity = cameraTransform.forward * shootSpeed;
}
}
First of all: You currently do GetComponent<Rigidbody> on that object itself .. this makes no sense since it would fire away "yourself" instead of a bullet. You have to Instantiate a bullet and apply forces/velocity here. You kind of missed the instantiation.
Then simply attach this script to your player Object instead and use transform.forward. transform returns the Transform component of the GameObject this script is attached to.
public class ShootScript : MonoBehaviour
{
// Hint: By making the prefab field Rigidbody you later can skip GetComponent
public Rigidbody bulletPrefab;
public float shootSpeed = 300;
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
shootBullet();
}
}
void shootBullet()
{
// Instantiate a new bullet at the players position and rotation
// later you might want to add an offset here or
// use a dedicated spawn transform under the player
var projectile = Instantiate (bulletPrefab, transform.position, transform.rotation);
//Shoot the Bullet in the forward direction of the player
projectile.velocity = transform.forward * shootSpeed;
}
}
I am trying to make a 2.5D SHMUP type game in which the world continuously moves forward while the player's spaceship and camera stay in place. This means that even if the world is moving, if the player's ship is in the middle of the screen it will stay there.
To do this I've created an empty game object named Moving World and attached the following script to it:
public class movingWorldController : MonoBehaviour
{
private float movementSpeed = 5f;
void Update()
{
transform.position = transform.position + new Vector3(0, 0, movementSpeed * Time.deltaTime);
}
}
I then added the camera and spaceship as children to of this object, and as a result they indeed move with the moving world object. However, I also have a script attached to the spaceship to allows it to move according to the player's input, and if I enable the script above the ship stops responding to the player's input. The ship's script looks like this:
public class ShipController : MonoBehaviour
{
public Rigidbody rb;
public float moveSpeed = 5f;
private Vector3 movement;
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.z = Input.GetAxisRaw("Vertical");
}
private void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.deltaTime);
}
}
The ship controller works just fine when the world-moving script is disabled, so I suspect the world script is somehow overwriting the spaceship position. How may I solve this?
For a POC example see this video: https://www.youtube.com/watch?v=-fVjWgfUKn4&t=282s (jump to 4:00 to see the game in action). Note that in the video gamemaker is used to achieve the effect, while I am trying to achieve a similar effect using just code.
I achieved the effect I was aiming for by doing the following. First, I removed the MovingWorld object and instead applied the following script to the camera:
public class movingWorldController : MonoBehaviour
{
public float movementSpeed = 5f;
void FixedUpdate()
{
transform.position = transform.position + new Vector3(0, 0, movementSpeed * Time.deltaTime);
}
}
This will cause the camera to continuously move forward. Next, to make sure the player's ship keeps up with the camera, and is maneuverable at the same time, I applied the following script to the ship's object:
public class ShipController : MonoBehaviour
{
public Rigidbody rb;
private float shipVelocity = 5f;
public float moveSpeed = 10f;
private Vector3 movement;
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal") * moveSpeed;
movement.z = Input.GetAxisRaw("Vertical") * moveSpeed + shipVelocity;
}
private void FixedUpdate()
{
rb.MovePosition(rb.position + movement * Time.deltaTime);
}
}
Two important notes:
The shipVelocity variable was introduced to make sure the ship continues to cruise at camera-speed.
Even though the camera is not a RigidBody its position update must occur during the FixedUpdate method to make sure it moves on the same frame as the ship. Updating it using the Update method will introduce jittering to the ship due to de-synchronization.
I am having an issue with my character which is not jumping at all. I am new to Unity, but I made sure to apply the script to the player and adjust the speed, I did not touch the Rigidbody 2D. If any one can help me figure our the issue, it will be much appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
public float moveSpeed;
public float jumpSpeed;
public bool grounded = false;
private Rigidbody2D rb;
void Start() {
rb = GetComponent<Rigidbody2D>();
}
void Update () {
transform.Translate (Input.GetAxisRaw ("Horizontal") * moveSpeed * Time.deltaTime, 0, 0);
if (grounded)
{
if (Input.GetButtonDown ("Jump"))
{
rb.AddForce (Vector2.up * jumpSpeed);
grounded = false;
}
}
}
void OnCollisionEnter2D (Collision2D coll){
if (coll.transform.tag == "Ground")
{
grounded = true;
}
}
}
Inspector window of the Player GameObject
Inspector window of the Ground GameObject
Your problem is you haven't tag the Ground GameObject as so. So in the OnCollisionEnter2D the character detects the collision, but the if (coll.transform.tag == "Ground") will never be true. So it means the character can't be grounded
Since to be grounded is the first condition to check if the player pressed the Jump key. It is impossible it will ever jump
if (grounded)
{
if (Input.GetButtonDown ("Jump"))
{
rb.AddForce (Vector2.up * jumpSpeed);
grounded = false;
}
}
To solve this issue: You need to tag the Ground GameObject as so. In case you are not sure how to do that, on the Tag menu, create (if it doesnt exist already) a new tag called Ground. Then assign in that same menu the Ground Tag to the Ground GameObject. Here you can learn how in case you need a visual reference:
https://docs.unity3d.com/Manual/Tags.html
Edit: You can try this script if everything fails. It should work. I used my self some time ago, I cleaned the code so to leave only what you need to move the character in the x and y axis. Hope to have included everything you need:
public class CharacterController2D : MonoBehaviour {
// LayerMask to determine what is considered ground for the player
public LayerMask whatIsGround;
// Transform just below feet for checking if player is grounded
public Transform groundCheck;
// store references to components on the gameObject
Transform transform;
Rigidbody2D rigidbody;
bool isGrounded = false;
float vy;
float vx;
public float jumpForce = 600f;
void Awake () {
transform = GetComponent<Transform> ();
rigidbody = GetComponent<Rigidbody2D> ();
}
void Update()
{
// determine horizontal velocity change based on the horizontal input
vx = Input.GetAxisRaw ("Horizontal");
vy = rigidbody.velocity.y;
// Check to see if character is grounded by raycasting from the middle of the player
// down to the groundCheck position and see if collected with gameobjects on the
// whatIsGround layer
isGrounded = Physics2D.Linecast(transform.position, groundCheck.position, whatIsGround);
if(isGrounded && Input.GetButtonDown("Jump")) // If grounded AND jump button pressed, then allow the player to jump
{
DoJump();
}
// Change the actual velocity on the rigidbody
rigidbody.velocity = new Vector2(_vx * MoveSpeed, _vy);
}
//Make the player jump
void DoJump()
{
// reset current vertical motion to 0 prior to jump
vy = 0f;
// add a force in the up direction
rigidbody.AddForce (new Vector2 (0, jumpForce));
}
}
So things to take into account:
Instead of tag the ground, you create a layer with everything you
consider ground. That will include possible platforms the character
may jump over. Pass as a parameter this layer to the script in the
inspector
You need to place an empty GameObject in the feet of the character.
You will drag and drop that GameObject in the editor onto the
groundCheck public variable.
Instead of OnTriggerEnter, you will use Physics2D.Linecast which
will trave a line from the position of the character to under its
feet (where you should have place the Transform mentioned in the
previous step) and if in the middle there is an element of the
groundLayer, it means the character will be grounded.
Let me know if anything is not clear or if you find some bug.
As mentioned your problem is deffinetly that your missing to tag your ground object :)
A tip: What i like to do when i have problems like this is to use the unitys Debug.Log() to locate where the problem is it. It will let you know easily in the console what code is run and which is not. Try do the following:
void Update () {
transform.Translate (Input.GetAxisRaw ("Horizontal") * moveSpeed * Time.deltaTime, 0, 0);
if (grounded)
{
Debug.Log("Is grounded");
if (Input.GetButtonDown ("Jump"))
{
Debug.Log("Jump clicked");
rb.AddForce (Vector2.up * jumpSpeed);
grounded = false;
}
}
}
My game is a topdown zombie shooter and whenever the zombies get to the player they bunch up underneath them, to the point where the player can just walk over the zombies. I noticed that when I check isKinematic on the Rigidbody the zombies cant push the player up to go underneath him, so they just run into him(which is what I want). Despite this I am then unable to move. How can i fix this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMoving1 : MonoBehaviour {
public float moveSpeed;
private Rigidbody myRigidbody;
private Vector3 moveInput;
private Vector3 moveVelocity;
private Camera mainCamera;
public GunController theGun;
void Start () {
myRigidbody = GetComponent <Rigidbody>();
mainCamera = FindObjectOfType<Camera>();
}
// Update is called once per frame
void Update () {
moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical"));
moveVelocity = moveInput * moveSpeed;
Ray cameraRay = mainCamera.ScreenPointToRay(Input.mousePosition);
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float rayLength;
if(groundPlane.Raycast(cameraRay,out rayLength))
{
Vector3 pointToLook = cameraRay.GetPoint(rayLength);
transform.LookAt(new Vector3(pointToLook.x,transform.position.y,pointToLook.z));
}
if (Input.GetMouseButtonDown(0))
theGun.isFiring = true;
if (Input.GetMouseButtonUp(0))
theGun.isFiring = false;
}
void FixedUpdate(){
myRigidbody.velocity = moveVelocity;
}
}
With isKinematic == true You can't change object position through rigidbody, You can only change transform.position.
I think it could be better, if You set isKinematic to false and add stopping distance to enemies, so they can't get too close to player.
Being that your player can no longer be effected by the physics engine, you'd have to manipulate the object's transform manually. Your script isn't ideally setup for it currently, but if I was to hack it into it and try to make it work it would look something like this:
(you can change it from fixedUpdate to update if you're no longer utilizing the physics engine)
void update(){
float x = Input.GetAxisRaw("Horizontal")* Time.Deltatime;
float z = Input.GetAxisRaw("Vertical") * Time.Deltatime;
transform.position = new Vector3(transform.position.x+x,0,transform.position.z+z);
Another way of doing this is to lock the position of Y for the player (assuming Y is the positive "up" direction). isKinimatic is best when you want to move the player or objects around yourself.
I would say upping the mass is better in this case, and you can keep isKinematic unchecked in this case then too. Also apply the lock for Y movement (again if it is the "up" direction from the plane)
Let me know what your solution is regardless, I've had some issues in the past as well with these types of events happening