I'm making a simple game as a means to learn C#. However, I've run into issues with generating multiple enemies.
First, the cloned enemies do not move down the screen. And second, if the enemies collide with each other it produces an infinite loop of new (spawning) enemies. I figured out part of the movement problem, I need to enable the script on the clones inside Unity, but I am unsure how to "properly" fix it (i.e. non-manually).
Here is the script for the enemies:
using UnityEngine;
using System.Collections;
public class Enemy : MonoBehaviour {
public Transform TS;
public float minSpeed = 3f, maxSpeed = 8f, currentSpeed;
public float llocation = -9.15f, rlocation = 9.15f, ylocation = 7.65f; //Above visible screen
// Use this for initialization
void Start () {
TS = transform; //Cache Transform.
currentSpeed = Random.Range(minSpeed, maxSpeed); //Randomize enemy speed;
TS.position = new Vector3 (Random.Range (llocation, rlocation), ylocation, 0); //Randomize enemy spawn point.
}
// Update is called once per frame
void Update () {
TS.position += (Vector3.down * currentSpeed * Time.deltaTime); //Bring enemy down the screen.
if (TS.position.y < -5.35f) {
TS.position = new Vector3 (Random.Range (llocation, rlocation), ylocation, 0);
currentSpeed = Random.Range(minSpeed, maxSpeed);
} //end new spawnpoint and speed.
}
void OnTriggerEnter(Collider collider)
{
if (collider.CompareTag("Laser") || collider.CompareTag("Player")) { //Tag is name of prefab.
//When the laser hits the enemy, destroy the enemy.
Destroy(this.gameObject);
}
if (Player.score < 500 || Player.playerLives >= 1) {
for (int enemies = 0; enemies < 3; enemies++) {
print("Enemies: " + enemies);
Vector3 nposition = new Vector3 (Random.Range (llocation, rlocation), ylocation, 0);
Instantiate(this, nposition, Quaternion.identity);
//TS.position += (Vector3.down * currentSpeed * Time.deltaTime);
}
}
}
}
Try the following code for function "OnTriggerEnter" :
void OnTriggerEnter(Collider collider)
{
if (collider.CompareTag("Laser") || collider.CompareTag("Player")) { //Tag is name of prefab.
//When the laser hits the enemy, destroy the enemy.
Destroy(this.gameObject);
}
if(collider.CompareTag("Enemy")) {
if (Player.score < 500 || Player.playerLives >= 1) {
for (int enemies = 0; enemies < 3; enemies++) {
print("Enemies: " + enemies);
Vector3 nposition = new Vector3 (Random.Range (llocation, rlocation), ylocation, 0);
Instantiate(gameObject, nposition, Quaternion.identity);
//TS.position += (Vector3.down * currentSpeed * Time.deltaTime);
}
}
}
}
Related
I've been trying to learn how to use Raycast2D for days and I'm not able to, I want my raycast to detect when it has collided with an NPC to make some kind of interaction system, but as much as I try the maximum progress I've managed to make is that the raycast works in the direction it should but not the distance, it always reports on screen that it has found the limit map collider, even if I rotate on myself to detect any other collider, first of all thank you very much for reading and for your effort! <3
private void Update() {
movimiento();
if (posesion) {
Debug.Log("ENCONTRADO");
}
hit = Physics2D.Raycast(transform.position, transform.position + direccion2 * 500, 0);
Debug.DrawRay(transform.position, transform.position + direccion2 * 500, Color.red);
if (true) {
Debug.Log(hit.transform.name);
}
if (hit.transform.tag == "NPC" && !posesion) {
Debug.Log("Estamos dentro");
if (Input.GetButtonDown("Fire2")) {
timer = Time.time;
}
if (Input.GetButtonUp("Fire2")) {
timerB = Time.time;
if (timerB - timer >= 3) {
timer = 0;
timerB = 0;
hit.transform.gameObject.GetComponent < NPC > ().turnPosession();
startPossesion();
}
}
}
}
The firsts lines of the code
[SerializeField]
private float velocidadMovimiento;
[SerializeField]
private Vector2 direccion;
private Vector3 direccion2;
private Rigidbody2D rb2D;
private float movimientoX;
private float movimientoY;
private Animator animator;
private bool posesion;
private float timer, timerB;
private RaycastHit2D hit;
private void Start() {
animator = GetComponent < Animator > ();
rb2D = GetComponent < Rigidbody2D > ();
posesion = false;
timer = 0;
timerB = 0;
}
private void movimiento() {
movimientoY = Input.GetAxisRaw("Horizontal");
movimientoX = Input.GetAxisRaw("Vertical");
animator.SetFloat("MovimientoX", movimientoX);
animator.SetFloat("MovimientoY", movimientoY);
direccion = new Vector2(
Input.GetAxisRaw("Horizontal"),
Input.GetAxisRaw("Vertical")
).normalized;
if (movimientoX != 0 || movimientoY != 0) {
direccion2 = new Vector3(
Input.GetAxisRaw("Horizontal"),
Input.GetAxisRaw("Vertical"), 0
).normalized;
animator.SetFloat("UltimoX", movimientoX);
animator.SetFloat("UltimoY", movimientoY);
}
}
This part is wrong:
hit = Physics2D.Raycast(transform.position, transform.position + direccion2 * 500, 0);
It should be:
hit = Physics2D.Raycast(transform.position, direccion2, 500);
when I command or set an enemy to go left and then at reaching a particular state or position i say my enemy to go right but it is not going right and not reaching to perfect position here is the code I think there is no issue in the code but it is not working properly so here are some images of the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enem : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position = transform.position + new Vector3(-3f, 0f, 0f)* 1 * Time.deltaTime;
if (transform.position.x > -29)
{
transform.position = transform.position + new Vector3(3f, 0f, 0f) * 1 * Time.deltaTime;
}
}
}
Before adding any bool logic, try first simply moving your element:
using UnityEngine;
public class SimeMoveMove : MonoBehaviour
{
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
transform.position += new Vector3(3f, 0f, 0f);
}
}
}
I smiled a little the moment I understood what you were trying to do.
I wrote the code imagining the result you were trying to make!
Create a cube, attach this code as component, and run the game.
// Gift for you friend
public class MoveTest : MonoBehaviour
{
private int _direction = 1;
void Start()
{
transform.position = Vector3.zero;
}
void Update()
{
Vector3 position = transform.position;
int direction = ShouldWeSwitchDirection(position.x, 0f);
if (direction != 0)
{
_direction = direction;
}
transform.position += _direction * new Vector3(3f, 0f, 0f) * 3f * Time.deltaTime;
}
private int ShouldWeSwitchDirection(float value, float center = 0f)
{
float direction = Mathf.Sign(value - center);
float distance = Mathf.Abs(value - center);
// If X Position is larger than 29
if (Mathf.Abs(distance) > 29)
{
// If X is on right side
if (direction >= 0)
{
return -1;
}
// If X is on left side.
else
{
return 1;
}
}
else
{
return 0;
}
}
}
I started programming my first computer game today and therefore I picked an easy one: Pong.
The core game is already working but I'm currently trying to add some features like a velocity increase, every time player1 scores. (enemy is currently also a controllable character put I'm planing to create a simple KI for that). It works out well in the beginning but at some point during the game, the ball starts bugging, means: the ball isn't bouncing away from the players1's character box anymore and is trying to keep going in the direction it bounced to after colliding with the enemy. Is the speed too high? Do I have to change something about the players1's box?
Video how it looks like: https://youtu.be/qzHGoQtRmEM
The script is currently looking like that:
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using UnityEngine;
using UnityEngine.UI;
public class Ball : MonoBehaviour
{
//variables
public float speed;
public float restartspeed;
int scorePlayer1;
int scoreEnemy;
public Text txtPlayer1;
public Text txtEnemy;
public float pausetime;
bool quit = false;
void Start()
{
GetComponent<Rigidbody2D>().velocity = new Vector2(1, 0) * speed * Time.deltaTime;
}
void Update()
{
}
//Collision Physics
private void OnCollisionEnter2D(Collision2D col)
{
//print(col.gameObject.name);
if (col.gameObject.name == "Player1")
{
//Collision Player1
float y = hitObject(transform.position, col.transform.position, col.collider.bounds.size.y);
//Calculate Direction
Vector2 dir = new Vector2(1, y);
//Directionvector Physics
GetComponent<Rigidbody2D>().velocity = dir * speed * Time.deltaTime;
}
if (col.gameObject.name == "Enemy")
{
//collision Enemy
float y = hitObject(transform.position, col.transform.position, col.collider.bounds.size.y);
//Calculate Direction
Vector2 dir = new Vector2(-1, y);
//Directionvector Physics
GetComponent<Rigidbody2D>().velocity = dir * speed * Time.deltaTime;
}
if (col.gameObject.name == "WallLeft")
{
scorePlayer1 = scorePlayer1 + 1;
txtPlayer1.text = scorePlayer1.ToString();
//Restart with a pause x sec
StartCoroutine(waiter());
}
if (col.gameObject.name == "WallRight")
{
scoreEnemy = scoreEnemy + 1;
txtEnemy.text = scoreEnemy.ToString();
//Restart with a pause of x sec
StartCoroutine(waiter());
}
}
float hitObject(Vector2 ballPos, Vector2 playerPos, float playerhight)
{
return (ballPos.y - playerPos.y) / playerhight;
}
//pausefunction + reset to origin
IEnumerator waiter()
{
float counter = 0;
Vector2 temp = new Vector2(0, 0);
gameObject.transform.position = temp;
Vector2 freeze = new Vector2(0, 0);
GetComponent<Rigidbody2D>().velocity = freeze;
float waitTime = pausetime;
while (counter < waitTime)
{
counter += Time.deltaTime;
Debug.Log("Waited for: " + counter + "seconds");
if (quit)
{
yield break;
}
yield return null;
}
//push ball again to players direction with higher velocity
GetComponent<Rigidbody2D>().velocity = new Vector2(1, 0) * (restartspeed + scorePlayer1);
}
}
Lots of love to everyone ^^ (Sorry if the Script is too long but i dont know which lines are relevant for the problem)
If the waypoints are small size for example cubes at size 0.1 or 1 it's fine.
When i change the cubes size to 20-30 if there is a situation that there are two waypoints on the way but the enemy should get to the second waypoint he will stuck on the wall of the first waypoint will shake/stutter and will try to go to one of the sides and then in the end he will pass this waypoint and continue to the waypoint he should get the target.
It happen only when the waypoints(cubes) are very big and if a waypoint block the waypoint the enemy should get.
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityStandardAssets.Characters.ThirdPerson;
public class WayPoints : MonoBehaviour {
public GameObject[] waypoints;
public Transform target;
public float moveSpeed = 10f;
public float moveSpeed1 = 10f;
public float slowDownSpeed = 3f;
public float reverseSlowDownSpeed = 3f;
public float rotationSpeed = 1f;
private Transform myTransform;
private int targetsIndex = 0;
private Vector3 originalPosition;
private GameObject[] robots;
public Transform reverseTarget;
private int reverseTargetsIndex = 0;
private Vector3 reverseOriginalPosition;
public bool random = false;
void Awake()
{
myTransform = transform;
}
// Use this for initialization
void Start()
{
waypoints = GameObject.FindGameObjectsWithTag("ClonedObject");
robots = GameObject.FindGameObjectsWithTag("Robots");
AddColliderToWaypoints();
originalPosition = robots[0].transform.position;
reverseOriginalPosition = robots[1].transform.position;
}
// Update is called once per frame
void Update()
{
if (MyCommands.walkbetweenwaypoints == true)
{
WayPointsAI();
ReverseWayPointsAI();
}
DrawLinesInScene();
}
private void WayPointsAI()
{
if (targetsIndex == waypoints.Length)
targetsIndex = 0;
target = waypoints[targetsIndex].transform;
float distance = Vector3.Distance(robots[0].transform.position, target.transform.position);
robots[0].transform.rotation = Quaternion.Slerp(robots[0].transform.rotation, Quaternion.LookRotation(target.position - robots[0].transform.position), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
robots[0].transform.position += robots[0].transform.forward * slowDownSpeed * Time.deltaTime;
}
else
{
robots[0].transform.position += robots[0].transform.forward * moveSpeed * Time.deltaTime;
}
if (distance < target.transform.localScale.magnitude)
{
targetsIndex++;
}
}
private void ReverseWayPointsAI()
{
if (reverseTargetsIndex == 0)
reverseTargetsIndex = waypoints.Length -1;
reverseTarget = waypoints[reverseTargetsIndex].transform;
float distance = Vector3.Distance(robots[1].transform.position, reverseTarget.transform.position);
robots[1].transform.rotation = Quaternion.Slerp(robots[1].transform.rotation, Quaternion.LookRotation(reverseTarget.position - robots[1].transform.position), rotationSpeed * Time.deltaTime);
//move towards the player
if (distance < 30)
{
robots[1].transform.position += robots[1].transform.forward * reverseSlowDownSpeed * Time.deltaTime;
}
else
{
robots[1].transform.position += robots[1].transform.forward * moveSpeed1 * Time.deltaTime;
}
if (distance < reverseTarget.transform.localScale.magnitude)
{
reverseTargetsIndex--;
}
}
void RandomWayPointsAI()
{
if (random == true)
{
int index = Random.Range(0, waypoints.Length);
target = waypoints[index].transform;
}
}
void DrawLinesInScene()
{
// draw lines between each checkpoint //
for (int i = 0; i < waypoints.Length - 1; i++)
{
Debug.DrawLine(waypoints[i].transform.position, waypoints[i + 1].transform.position, Color.blue);
}
// draw a line between the original transform start position
// and the current transform position //
Debug.DrawLine(originalPosition, robots[0].transform.position, Color.red);
Debug.DrawLine(reverseOriginalPosition, robots[1].transform.position, Color.red);
// draw a line between current transform position and the next waypoint target
// each time reached a waypoint.
if (target != null)
Debug.DrawLine(target.transform.position, robots[0].transform.position, Color.green);
if (reverseTarget != null)
Debug.DrawLine(reverseTarget.transform.position, robots[1].transform.position, Color.green);
}
void AddColliderToWaypoints()
{
foreach (GameObject go in waypoints)
{
SphereCollider sc = go.AddComponent<SphereCollider>() as SphereCollider;
sc.isTrigger = true;
}
}
}
I tried to make
if (distance < reverseTarget.transform.localScale.magnitude)
I tried before it to make
if (distance < reverseTarget.tranform.localscale.x)
Or
if (distance < reverseTarget.tranform.localscale.x / 2)
Same with target and the first AI function.
But nothing is working. Maybe i should find the waypoints radius ?
Not sure how to solve it.
What OP seems to have wanted was a way to give the AI pathfinding so that when the AI wanted to go from (dynamic/code generated) point A to B and there was an obstacle between, the AI wouldn't get stuck in the obstacle.
Unity offers NavMesh and NavMesh Obstacle, a simple pathfinding tool Unity gives us to achieve a smart AI with little effort.
I have a script for waypoints, which I find here. It works fine for objects, which move on the horizontal axes. But it don't move objects up and down. Can't understand, why.
Elevator are just decoration and it will randomly move from one floor to another.
public Transform[] waypoint; // The amount of Waypoint you want
float patrolSpeed = 3.0f; // The walking speed between Waypoints
float dampingLook = 6.0f; // How slowly to turn
public float pauseDuration; // How long to pause at a Waypoint
float curTime;
int currentWaypoint;
CharacterController character;
void Start()
{
character = GetComponent<CharacterController>();
}
void Update()
{
if (currentWaypoint < waypoint.Length)
Patrol();
else
currentWaypoint = 0;
}
void Patrol()
{
Vector3 target = waypoint[currentWaypoint].position;
target.y = transform.position.y; // Keep waypoint at character's height
Vector3 moveDirection = target - transform.position;
if(moveDirection.magnitude < 0.5)
{
if (curTime == 0)
curTime = Time.time; // Pause over the Waypoint
if ((Time.time - curTime) >= pauseDuration)
{
currentWaypoint = Random.Range(0, waypoint.Length);
curTime = 0;
}
}
else
{
var rotation = Quaternion.LookRotation(target - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * dampingLook);
character.Move(moveDirection.normalized * patrolSpeed * Time.deltaTime);
}
}
Edit1:
Here is the video how it works.
Try this, without a rigidbody:
using UnityEngine;
using System.Collections;
public class Elevator : MonoBehaviour {
public Transform[] waypoint; // The amount of Waypoint you want
float patrolSpeed = 3.0f; // The walking speed between Waypoints
float dampingLook = 6.0f; // How slowly to turn
public float pauseDuration; // How long to pause at a Waypoint
float curTime;
int currentWaypoint;
void Update()
{
if (currentWaypoint < waypoint.Length)
Patrol();
else
currentWaypoint = 0;
}
void Patrol()
{
Vector3 target = waypoint[currentWaypoint].position;
Vector3 moveDirection = target - transform.position;
if(moveDirection.magnitude < 0.5)
{
if (curTime == 0)
curTime = Time.time; // Pause over the Waypoint
if ((Time.time - curTime) >= pauseDuration)
{
currentWaypoint = Random.Range(0, waypoint.Length);
curTime = 0;
}
}
else
{
transform.Translate(moveDirection.normalized * patrolSpeed * Time.deltaTime);
}
}
}
Edit: Correct the script by removing two rotation lines.