I am trying to code a drone that is shooting a laser-bullet to the last position of the player. The bullet should also rotate to the players position.
I have following script, but it is not shooting for some reason.
using System.Collections.Generic;
using UnityEngine;
public class DroneShoot: MonoBehaviour
{
public Transform bulletspawn;
public Rigidbody2D bulletPrefab;
public float bulletSpeed = 750;
public float bulletDelay;
private Transform player;
private Rigidbody2D clone;
// Use this for initialization
void Start()
{
player = GameObject.FindGameObjectWithTag("spieler").GetComponent<Transform>();
StartCoroutine(Attack());
}
IEnumerator Attack()
{
yield return new WaitForSeconds(bulletDelay);
if (Vector3.Distance(player.transform.position, bulletspawn.transform.position) < 20)
{
Quaternion rotation = Quaternion.LookRotation(player.transform.position, bulletspawn.transform.position);
bulletspawn.rotation = rotation;
clone = Instantiate(bulletPrefab, bulletspawn.position, bulletspawn.rotation);
clone.AddForce(bulletspawn.transform.right * bulletSpeed);
StartCoroutine(Attack());
}
}
}
It looks like it will only try to fire again if it is able to fire the first time because StartCoroutine is inside the distance check.
I think it should keep trying to shoot forever.
IEnumerator Attack()
{
while(true){
yield return new WaitForSeconds(shootDelay);
if (Vector3.Distance(player.transform.position, bulletspawn.transform.position) < 20)
{
Quaternion rotation = Quaternion.LookRotation(player.transform.position);
bulletspawn.rotation = rotation;
clone = Instantiate(bulletPrefab, bulletspawn.position, bulletspawn.rotation);
clone.AddForce(bulletspawn.transform.right * bulletSpeed);
}
}
}
I have a solution.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DroneShoot: MonoBehaviour
{
public Transform bulletspawn;
public Rigidbody2D bulletPrefab;
public float bulletSpeed = 750;
public float bulletDelay;
private Transform player;
private Rigidbody2D clone;
// Use this for initialization
void Start()
{
player = GameObject.FindGameObjectWithTag("spieler").GetComponent<Transform>();
StartCoroutine(Attack());
}
IEnumerator Attack()
{
yield return new WaitForSeconds(bulletDelay);
if (Vector3.Distance(player.transform.position, bulletspawn.transform.position) < 20)
{
Vector3 difference = player.position - bulletspawn.position;
float rotationZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
bulletspawn.rotation = Quaternion.Euler(0.0f, 0.0f, rotationZ);
clone = Instantiate(bulletPrefab, bulletspawn.position, bulletspawn.rotation);
clone.AddForce(bulletspawn.transform.right * bulletSpeed);
StartCoroutine(Attack());
}
}
}
Related
I have an enemy prefab with and a bullet prefab with rigidbody2D and boxcolliders to both of them. I have made a TakeDamage function for the enemy when i made meelee combat and also a bullet shooting script. I made a simple OnCollisionEnter2D on the enemy(code is below) and they do collide and give the collision effect but the function doesn't work, it doesn't give any errors either... What do I do now?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemy : MonoBehaviour
{
public Transform player;
private Rigidbody2D rb;
[SerializeField] private SpriteRenderer sr;
private Vector2 movement;
public float moveSpeed = 5f;
public int maxHealth = 100;
int currentHealth;
Color32 colorRes = new Color32(255, 100, 50, 255);
public ParticleSystem deathParticles;
public GameObject projectile;
public int enemyDamage = 50;
public LayerMask rock;
// Start is called before the first frame update
void Start()
{
rb = this.GetComponent<Rigidbody2D>();
sr = GetComponent<SpriteRenderer>();
currentHealth = maxHealth;
}
// Update is called once per frame
void Update()
{
sr.flipX = player.position.x - transform.position.x > 0;
Vector3 direction = player.position - transform.position;
direction.Normalize();
movement = direction;
}
private void FixedUpdate()
{
moveCharacter(movement);
}
void moveCharacter(Vector2 direction)
{
rb.MovePosition((Vector2)transform.position + (direction * moveSpeed));
}
public void TakeDamage()
{
currentHealth -= enemyDamage;
if(currentHealth <= 0)
{
Die();
}
StartCoroutine(BecomeRed());
}
void Die()
{
Instantiate(deathParticles, transform.position, Quaternion.identity);
Destroy(gameObject);
}
IEnumerator BecomeRed()
{
sr.color = colorRes;
yield return new WaitForSeconds(0.6f);
sr.color = Color.white;
}
void OnCollisionEnter2D(Collision2D coll)
{
Debug.Log("test");
if (coll.gameObject.name == "rock")
{
TakeDamage();
Destroy(projectile);
}
}
}
I Have been trying to figure out how the Enemy doesn't return multiple GameObjects it only returns one.Im not sure whether it is my Bullet script that it allows only one object to return. I'm currently trying to develop a Game with multiple players like Slither.io so I'm not sure if the performance is affected I would like to use (List Function) but dont know where to start and I'm using a later version Unity 2017.3.1f1. Much Appreciated for your help.The scripts are below.
public class RandomAIProjectile
{
private GameObject[] target;
public float speed;
Rigidbody2D bulletRB;
public GameObject explosionEffect;
// Find Targets Section.
void Start ()
{
if (target == null)
target = GameObject.FindGameObjectsWithTag("Player");
for (int i = 0; i < target.Length; i++)
{
bulletRB = GetComponent<Rigidbody2D> ();
Vector2 moveDir = (target[i].transform.position - transform.position).normalized * speed;
bulletRB.velocity = new Vector2 (moveDir.x, moveDir.y);
Destroy (this.gameObject, 2);
}
}
private void OnTriggerEnter2D(Collider2D other)
{
// Decoy Script To Destroy Players.
if (other.gameObject.GetComponent<BlackthronpodDiePlayer>() != null)
{
Destroy (other.gameObject);
Destroy (gameObject);
}
// Damage Effect.
if (other.gameObject.tag == "Player") {
Instantiate (explosionEffect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
// Player (Bullet) Destroy Enemy.
if (other.CompareTag ("Bullet"))
{
Destroy (other.gameObject);
Destroy (gameObject);
}
}
}
Here is the Player Script
public class RandomAIEnemy
{
//Random Movement
public float speed;
public float waitTime;
public float startWaitTime;
public Transform moveSpots;
public float minX;
public float minY;
public float maxX;
public float maxY;
//Enemy AI Shooting
public float lineOfSite;
public float shootingRange;
public float fireRate = 1f;
private float nextFireTime;
public GameObject bullet;
public GameObject bulletParent;
// My Current Player
private BlackthronpodPlayerX playerX;
// Player AI
private GameObject[] player;
public GameObject blood;
Vector3 respawn = new Vector3 (-34f,0,0);
//Additional Info
void FixedUpdate ()
{
EnemyS ();
}
// Use this for initialization
void Start ()
{
//My Player AI Tag.
player = GameObject.FindGameObjectsWithTag("Player");
waitTime = startWaitTime;
//My Current Player Tag.
playerX = GameObject.FindGameObjectWithTag ("Player").GetComponent<BlackthronpodPlayerX>();
//Random Movement Reference
moveSpots.position = new Vector2 (Random.Range (minX, maxX), Random.Range (minY, maxY));
}
//Closest (My Player Including Player AI.)
private bool TryGetClosestPlayer(out GameObject closest)
{
var playersSortedByDistance = player.OrderBy(p => ((Vector2)p.transform.position - (Vector2)transform.position).sqrMagnitude);
closest = playersSortedByDistance.FirstOrDefault();
return closest;
}
void EnemyS ()
{
GameObject closestPlayer = null;
if(TryGetClosestPlayer (out closestPlayer))
{
var distanceFromPlayer = Vector2.Distance (closestPlayer.transform.position, transform.position);
if (distanceFromPlayer <= shootingRange && nextFireTime < Time.time)
{
Instantiate (bullet, bulletParent.transform.position, Quaternion.identity);
nextFireTime = Time.time + fireRate;
}
}
}
// Range And Shooting Boundary For Player Including Player AI.
private void OnDrawGizmosSelected ()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere (transform.position, lineOfSite);
Gizmos.DrawWireSphere (transform.position, shootingRange);
}
// Random Movement (I).
void RandomMove ()
{
//Rotate Movement Of Enemy.
transform.position = Vector2.MoveTowards (transform.position, moveSpots.position, speed * Time.deltaTime);
if (Vector2.Distance (transform.position, moveSpots.position) < 0.2f)
{
if(waitTime <= 0)
{
moveSpots.position = new Vector2 (Random.Range (minX, maxX), Random.Range (minY, maxY));
waitTime = startWaitTime;
} else {
waitTime -= Time.deltaTime;
}
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
// Damage Effect On Enemy.
if (collision.gameObject.tag.Equals ("Player"))
{
Instantiate(blood,transform.position, Quaternion.identity);
}
// My Players Health.
if (collision.CompareTag ("Player"))
{
playerX.health --;
Debug.Log(playerX.health);
Destroy(gameObject);
}
// Player Score Manager.
if (collision.tag == "Bullet")
{
Game.AddToScore(1);
Destroy(gameObject);
}
}
}
Make sure that you have Rigidbody2d attached on your enemy and player. And also, is there any error coming in the code?
I'm new to unity and I'm trying to make an isometric 3d game, but I have some problem, I would like that the player stops moving when I stop using the virtual joystick. Here's my 2 scripts for movement. The first one is in the virtual joystick to make it move and the second one is in the player and make it move in the direction of the joystick.
Joystick script:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
public class VirtualJoystick : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
{
private Image bgImg;
private Image joystickImg;
private Vector3 inputVector;
private void Start()
{
bgImg = GetComponent<Image>();
joystickImg = transform.GetChild(0).GetComponent<Image>();
}
public virtual void OnDrag(PointerEventData ped)
{
Vector2 pos;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(bgImg.rectTransform, ped.position, ped.pressEventCamera, out pos))
{
pos.x = (pos.x / bgImg.rectTransform.sizeDelta.x);
pos.y = (pos.y / bgImg.rectTransform.sizeDelta.x);
inputVector = new Vector3(pos.x * 2 + 1, 0, pos.y * 2 - 1);
inputVector = (inputVector.magnitude > 1.0f) ? inputVector.normalized : inputVector;
// Move joystickImg
joystickImg.rectTransform.anchoredPosition =
new Vector3(inputVector.x * bgImg.rectTransform.sizeDelta.x / 3
, inputVector.z * (bgImg.rectTransform.sizeDelta.y / 3));
}
}
public virtual void OnPointerDown(PointerEventData ped)
{
OnDrag(ped);
}
public virtual void OnPointerUp(PointerEventData ped)
{
inputVector = Vector3.zero;
joystickImg.rectTransform.anchoredPosition = Vector3.zero;
}
public float Horizontal()
{
if (inputVector.x != 0)
return inputVector.x;
else
return Input.GetAxis("Horizontal");
}
public float Vertical()
{
if (inputVector.x != 0)
return inputVector.z;
else
return Input.GetAxis("Vertical");
}
}
Player Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public float moveSpeed = 20f;
public VirtualJoystick moveJoystick;
private void Update()
{
Vector3 dir = Vector3.zero;
dir.x = moveJoystick.Horizontal();
dir.z = moveJoystick.Vertical();
GetComponent<Rigidbody>().AddForce(dir * moveSpeed);
}
}
For stopping the player when you let go of the virtual joystick, we can tell the player's rigidbody to sleep. This will make the player halt until another force is added to it.
Update your Player script to the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public float moveSpeed = 20f;
public VirtualJoystick moveJoystick;
public Rigidbody rb;
private Vector3 dir = Vector3.zero;
private bool wasMoving = false;
private void Update()
{
dir.x = moveJoystick.Horizontal();
dir.z = moveJoystick.Vertical();
if (dir.magnitude > 0)
{
wasMoving = true;
}
}
private void FixedUpdate()
{
if (wasMoving && dir.magnitude == 0f)
{
wasMoving = false;
rb.Sleep();
}
rb.AddForce(dir * moveSpeed);
}
}
It's also a good idea to store the Rigidbody as a variable so you don't recompute it every update. Be sure to drag it into the script from the inspector.
I have been working on a project recently and there is a scene where there are mountains, forests and a car.
When the car moves on the terrain, the car penetrates through the terrain
I just want to know how to stop this from happening.
On the Car there is Mesh Collider and RigidBody is attached
On Terrain There is Mesh Collider with Convex to False.
public class Motor : MonoBehaviour {
public float moveSpeed = 5.0f;
public float drag = 0.5f;
public float terminalRoatationSpeed = 25.0f;
public Virtualjoystick moveJoystick;
private Rigidbody controller;
private Transform camTransform;
// Use this for initialization
void Start () {
controller = GetComponent<Rigidbody> ();
controller.maxAngularVelocity = terminalRoatationSpeed;
controller.drag = drag;
camTransform = Camera.main.transform;
}
// Update is called once per frame
void FixedUpdate () {
Vector3 dir = Vector3.zero;
dir.x = Input.GetAxis ("Horizontal");
dir.z = Input.GetAxis ("Vertical");
if(dir.magnitude > 1)dir.Normalize();
if(moveJoystick.InputDirection != Vector3.zero)
{
dir = moveJoystick.InputDirection;
}
// Rotate our Direction vector with Camera
Vector3 rotatedDir = camTransform.TransformDirection(dir);
rotatedDir = new Vector3 (rotatedDir.x, 0, rotatedDir.z);
rotatedDir = rotatedDir.normalized * dir.magnitude;
controller.AddForce (rotatedDir * moveSpeed);
}
}
I've answered this question before but can't find the other answer to mark this as a duplicate. You use WheelCollider for cars.
You need to attach WheelCollider to all the wheels of your car. By doing this your car will always be on top of the Terrain Collider.
WheelCollider.motorTorque is used to move the car forward or backwards.
WheelCollider.brakeTorque is used to brake the car.
WheelCollider.steerAngle is used to steer the car.
There are many tutorials out there and here is one example directly from Unity's doc:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class AxleInfo {
public WheelCollider leftWheel;
public WheelCollider rightWheel;
public bool motor;
public bool steering;
}
public class SimpleCarController : MonoBehaviour {
public List<AxleInfo> axleInfos;
public float maxMotorTorque;
public float maxSteeringAngle;
// finds the corresponding visual wheel
// correctly applies the transform
public void ApplyLocalPositionToVisuals(WheelCollider collider)
{
if (collider.transform.childCount == 0) {
return;
}
Transform visualWheel = collider.transform.GetChild(0);
Vector3 position;
Quaternion rotation;
collider.GetWorldPose(out position, out rotation);
visualWheel.transform.position = position;
visualWheel.transform.rotation = rotation;
}
public void FixedUpdate()
{
float motor = maxMotorTorque * Input.GetAxis("Vertical");
float steering = maxSteeringAngle * Input.GetAxis("Horizontal");
foreach (AxleInfo axleInfo in axleInfos) {
if (axleInfo.steering) {
axleInfo.leftWheel.steerAngle = steering;
axleInfo.rightWheel.steerAngle = steering;
}
if (axleInfo.motor) {
axleInfo.leftWheel.motorTorque = motor;
axleInfo.rightWheel.motorTorque = motor;
}
ApplyLocalPositionToVisuals(axleInfo.leftWheel);
ApplyLocalPositionToVisuals(axleInfo.rightWheel);
}
}
}
I am extremely close to finishing my game, every code I posted works well but I want my player to die whether it collides with the box (which is the enemy). However, I've tried to do some research and I can't seem to find the solution. How do I do this? Here's the code for the Player (JugadorScript.cs):
using UnityEngine;
using System.Collections;
public class JugadorScript : MonoBehaviour
{
public float velocidad = -10f;
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void moverIzquierda()
{
transform.Translate(Vector2.right * velocidad * Time.deltaTime);
transform.eulerAngles = new Vector2(0, 0);
}
public void moverDerecha()
{
transform.Translate(Vector2.right * velocidad * Time.deltaTime);
transform.eulerAngles = new Vector2(0, 180);
}
}
The EnemySpawner.cs code, which works excellent:
using UnityEngine;
using System.Collections;
using System;
public class EnemySpawner : MonoBehaviour
{
public GameObject BlockPrefab;
float maxSpawnRateInSeconds = 2.5f;
void Start()
{
Invoke("SpawnEnemy", maxSpawnRateInSeconds);
InvokeRepeating("IncreaseSpawnRate", 0f, 30f);
}
// Update is called once per frame
void Update()
{
}
void SpawnEnemy()
{
Vector2 min = Camera.main.ViewportToWorldPoint(new Vector2(0, 0));
Vector2 max = Camera.main.ViewportToWorldPoint(new Vector2(1, 1));
GameObject anEnemy = (GameObject)Instantiate(BlockPrefab);
anEnemy.transform.position = new Vector2(UnityEngine.Random.Range(min.x, max.x), max.y);
ScheduleNextEnemySpawn();
}
void ScheduleNextEnemySpawn()
{
float spawnInNSeconds;
if (maxSpawnRateInSeconds > 1f)
{
spawnInNSeconds = UnityEngine.Random.Range(1f, maxSpawnRateInSeconds);
}
else
spawnInNSeconds = 1f;
Invoke("SpawnEnemy", spawnInNSeconds);
}
void IncreaseSpawnRate()
{
if (maxSpawnRateInSeconds > 1f)
maxSpawnRateInSeconds--;
if (maxSpawnRateInSeconds == 1f)
CancelInvoke("IncreaseSpawnRate");
}
}
And the BlockScript.cs, which is my enemy script:
using UnityEngine;
using System.Collections;
public class BlockScript : MonoBehaviour
{
private GameObject wayPoint;
private Vector3 wayPointPos;
private Rigidbody2D rigidBody2D;
public bool inGround = true;
private float jumpForce = 400f;
private float speed = 6.0f;
void Start()
{
wayPoint = GameObject.Find("wayPoint");
}
private void awake()
{
rigidBody2D = GetComponent<Rigidbody2D>();
}
void Update()
{
if (inGround)
{
inGround = false;
rigidBody2D.AddForce(new Vector2(0f, jumpForce));
}
wayPointPos = new Vector3(wayPoint.transform.position.x, transform.position.y,
wayPoint.transform.position.z);
transform.position = Vector3.MoveTowards(transform.position,
wayPointPos, speed * Time.deltaTime);
Vector2 min = Camera.main.ViewportToWorldPoint(new Vector2(0, 0));
if (transform.position.y < min.y)
{
Destroy(gameObject);
}
}
}
As you can see in the doc, the function you are looking for is OnCollisionEnter.
Check this tutorial:
https://unity3d.com/es/learn/tutorials/topics/physics/detecting-collisions-oncollisionenter