Enemy AI not working properly with NavMesh - c#

I been trying to create an AI for the enemy to patrol between some points and, when spot player in a certain range, the enemy stop the patrol and follows the player.
The thing is, if I only have the enemy to follow the player, works perfectly the same happens with just the patrol, but both together doesn't seem to work. The enemy acts in a weird way.
My code:
public void Start()
{
_navMeshAgent = this.GetComponent<NavMeshAgent>();
anim = GetComponent<Animator>();
if (_navMeshAgent == null)
{
Debug.LogError("not attached to " + gameObject.name);
}
else
{
if (_patrolPoints != null && _patrolPoints.Count >= 2)
{
_currentPatrolIndex = 0;
anim.SetBool("idle", true);
SetDestination();
}
else
{
Debug.Log("Insufficient patrol points.");
}
}
}
void Update()
{
if (player == null)
{
player = GameObject.Find("Player Character").GetComponent<Transform>();
}
if (Vector3.Distance(player.transform.position, this.transform.position) < 10)
{
chacePlayer();
}
else
{
patrol();
}
bool patrol()
{
Debug.Log("patrolling");
//Check if we're close to the destination.
if (_travelling && _navMeshAgent.remainingDistance <= 1.0f)
{
_travelling = false;
anim.SetBool("idle", false);
anim.SetBool("move", true);
//If we're going to wait, then wait dumbass!
if (_patrolWaiting)
{
_waiting = true;
_waitTimer = 0f;
anim.SetBool("idle", true);
anim.SetBool("move", false);
}
else
{
ChangePatrolPoint();
SetDestination();
}
}
//Instead if we're waiting...
if (_waiting)
{
_waitTimer += Time.deltaTime;
if (_waitTimer >= _totalWaitingTime)
{
_waiting = false;
anim.SetBool("move", true);
anim.SetBool("idle", false);
ChangePatrolPoint();
SetDestination();
}
}
return true;
}
}
private void SetDestination()
{
if (_patrolPoints != null)
{
Vector3 targetVector = _patrolPoints[_currentPatrolIndex].transform.position;
_navMeshAgent.SetDestination(targetVector);
_travelling = true;
////anim.SetBool("idle", false);
////anim.SetBool("move", true);
}
}
//Selects a new patrol point in the available list, but
//also with a small probability allows for us to move forward or backwards.
private void ChangePatrolPoint()
{
//Unity generate random number between 0 and 1
if (UnityEngine.Random.Range(0f, 1f) <= _switchProbability)
{
//decides if go forward or backwards: whatever the value, make the oposite
_patrolForward = !_patrolForward;
}
if (_patrolForward)
{
//if the patrolpoint exceedes patrolpoints.count, go backs to zero
_currentPatrolIndex = (_currentPatrolIndex + 1) % _patrolPoints.Count;
}
else
{
if (--_currentPatrolIndex < 0)
{
_currentPatrolIndex = _patrolPoints.Count - 1;
}
}
}
void chacePlayer()
{
Vector3 direction = player.transform.position - this.transform.position;
this.transform.rotation = Quaternion.Slerp(this.transform.rotation,
Quaternion.LookRotation(direction), 0.1f);
direction.y = 0;
if (direction.magnitude > 2)
{
this.transform.Translate(0, 0, 0.05f);
Debug.Log("chacing");
}
}
At first I thought it was because the code was running both together so I put a Debug to see if it was that, but the debug of the patrol stops every time the enemy is following the player.
Can someone please help me?

Related

Need help translating unity's old input manager to the new input system

I'm new to using Unity and C# and I've been working on creating a movement system for a 2D platformer, and I've decided I want to switch to the new Unity Input System (because I can't find good information on the old one as all the search results I get are for the new one). I have it downloaded and installed and have watched a ton of videos but can't get any inputs to actually work in my game.
Here is the code which I need help translating:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class CharacterLogic : MonoBehaviour
{
private bool playerIsAlive = true;
Vector2 movementInput;
bool jumpInput;
bool doubleJumpInput;
private float sprintTimer;
private bool isSprinting;
private int jumpsRemaining = 1;
private bool facingRight = true;
private bool isGrounded;
private bool wallJumping = false;
[Header("Collision")]
public BoxCollider2D playerCollider;
public LayerMask jumpableGround;
[Header("Movement")]
public Rigidbody2D characterBody;
public float runSpeed = 7;
public float maxSpeed = 10;
public float jumpStrength = 11;
[Header("Camera Tracking")]
public CameraScript mainCamera;
public float zoomSpeed;
public float ZoomAmount;
public float maxZoomAmount;
[Header("Wall Jump System")]
public Transform frontCheck;
public float wallSlidingSpeed;
public float checkRadius;
public float xWallForce;
public float yWallForce;
public float wallJumpTime;
bool isTouchingFront;
bool wallSliding;
[Header("Animation Settings")]
public Animator animator;
private string currentState;
//Animation States
const string PLAYER_IDLE = "Idle";
const string PLAYER_RUN = "Running";
const string PLAYER_SPRINT = "Sprinting";
const string PLAYER_JUMP = "Jumping";
const string PLAYER_WALLSLIDE = "Wallslide";
[Header("Inputs")]
public PlayerInput playerInput;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
movementInput.x = Input.GetAxisRaw("Horizontal");
movementInput.y = Input.GetAxisRaw("Vertical");
isGrounded = Physics2D.BoxCast(playerCollider.bounds.center, playerCollider.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
if (Input.GetButtonDown("Jump"))
{
if (!isGrounded)
{
if (wallSliding)
{
jumpsRemaining += -1;
}else if (jumpsRemaining > 0)
{
jumpInput = true;
doubleJumpInput = true;
}
}
else if (isGrounded)
{
jumpInput = true;
}
// Wall jump
if (!facingRight)
{
if (movementInput.x > 0 && wallSliding == true)
{
wallJumping = true;
}
}else if (facingRight)
{
if (movementInput.x < 0 && wallSliding == true)
{
wallJumping = true;
}
}
}
}
void FixedUpdate()
{
// Flip the character sprite's direction
if (facingRight == false && movementInput.x > 0 && !wallSliding && (isGrounded || doubleJumpInput))
{
Flip();
} else if (facingRight == true && movementInput.x < 0 && !wallSliding && (isGrounded || doubleJumpInput))
{
Flip();
}
// Jump
if (jumpInput && playerIsAlive && wallSliding != true)
{
Jump();
}
// Run
if (movementInput.x != 0 && playerIsAlive && wallSliding == false)
{
Run();
if (characterBody.velocity.x == maxSpeed)
{
mainCamera.xOffset = 6;
//mainCamera.ZoomOut(maxZoomAmount, zoomSpeed);
}else if (characterBody.velocity.x == -maxSpeed)
{
mainCamera.xOffset = -6;
}
else
{
if (movementInput.x > 0)
{
mainCamera.xOffset = 4;
}else if (movementInput.x < 0)
{
mainCamera.xOffset = -4;
}
}
}
// Idle
if (((movementInput.x == 0) && (movementInput.y == 0)) && playerIsAlive && wallSliding == false)
{
Idle();
ChangeAnimationState(PLAYER_IDLE);
}
// Reset sprint timer
if (movementInput.x == 0)
{
sprintTimer = 0;
mainCamera.xOffset = 0;
}
// Reset double jump
if (isGrounded)
{
jumpsRemaining = 1;
}
// Detect wall collisions
isTouchingFront = Physics2D.OverlapCircle(frontCheck.position, checkRadius, jumpableGround);
if (isTouchingFront == true && !isGrounded && Input.GetButton("Fire1"))
{
wallSliding = true;
}
else
{
wallSliding = false;
}
if (wallSliding && !wallJumping)
{
WallSlide();
ChangeAnimationState(PLAYER_WALLSLIDE);
}
if (wallJumping == true)
{
ChangeAnimationState(PLAYER_JUMP);
Invoke("SetWallJumpingToFalse", wallJumpTime);
characterBody.velocity = new Vector2(xWallForce * movementInput.x, yWallForce);
Flip();
}
//Debug.Log(jumpsRemaining);
}
/// <summary>
/// This function sets the character's velocity in the Y axis to the value of `jumpStrength`,.
/// It also preserves the character's current velocity along the Y axis.
/// </summary>
public void Jump()
{
//Debug.Log("Normal Jump");
jumpsRemaining += -1;
Vector2 velocity = characterBody.velocity;
if ((velocity.x > 0 && movementInput.x > 0) || (velocity.x < 0 && movementInput.x < 0))
{
}
else
{
if (movementInput.x > 0)
{
velocity.x = 7;
}
else if (movementInput.x < 0)
{
velocity.x = -7;
}
}
velocity.y = jumpStrength;
characterBody.velocity = velocity;
jumpInput = false;
if (doubleJumpInput == true)
{
doubleJumpInput = false;
}
if (!isGrounded)
{
ChangeAnimationState(PLAYER_JUMP);
}
}
/// <summary>
/// This function sets the character's velocity in the X axis to the value of `runSpeed`.
/// It also preserves the character's current velocity along the Y axis.
/// </summary>
public void Run()
{
sprintTimer += Time.deltaTime;
Vector2 velocity = characterBody.velocity;
if (sprintTimer > 2 && characterBody.velocity.x != 0)
{
if (isGrounded)
{
if (movementInput.x > 0)
{
velocity.x = maxSpeed;
isSprinting = true;
ChangeAnimationState(PLAYER_SPRINT);
}
else if (movementInput.x < 0)
{
velocity.x = -maxSpeed;
isSprinting = true;
ChangeAnimationState(PLAYER_SPRINT);
}
} else
{
if (isSprinting == false)
{
if (velocity.x > 0)
{
velocity.x = runSpeed;
isSprinting = false;
ChangeAnimationState(PLAYER_RUN);
}
else if (velocity.x < 0)
{
velocity.x = -runSpeed;
isSprinting = false;
ChangeAnimationState(PLAYER_RUN);
}
}
}
}
else
{
if (movementInput.x > 0 && isGrounded)
{
velocity.x = runSpeed;
isSprinting = false;
ChangeAnimationState(PLAYER_RUN);
}
else if (movementInput.x < 0 && isGrounded)
{
velocity.x = -runSpeed;
isSprinting = false;
ChangeAnimationState(PLAYER_RUN);
}
}
characterBody.velocity = velocity;
}
public void Idle()
{
characterBody.velocity = new Vector2(0, characterBody.velocity.y);
}
private void Flip()
{
facingRight = !facingRight;
Vector3 scaler = transform.localScale;
scaler.x *= -1;
transform.localScale = scaler;
}
private void WallSlide()
{
//Flip();
characterBody.velocity = new Vector2(characterBody.velocity.x, Mathf.Clamp(characterBody.velocity.y, -wallSlidingSpeed, float.MaxValue));
}
private void ChangeAnimationState(string newState)
{
// Stop the same animation from interrupting itself
if (currentState == newState) return;
//Play the animation
animator.Play(newState);
// Reassign the current state to the new state
currentState = newState;
}
private void SetWallJumpingToFalse()
{
wallJumping = false;
jumpsRemaining = 1;
}
public void OnJump(InputAction.CallbackContext value)
{
Debug.Log("Jump");
}
public void OnMovement(InputAction.CallbackContext value)
{
Vector2 inputMovement = value.ReadValue<Vector2>();
Debug.Log("Jump");
}
}
If anyone can help dumb this down for me I'd be eternally grateful. As you can see from the last two functions, I am trying to trigger unity events, assign the events to functions and write to the Debug.log so that I can see it's working. For instance currently, it should say "Jump" when I press the button I've mapped to "Jump" in the action map, but in reality it just triggers the old input manager stuff normally and the new stuff does nothing.
I have the PlayerInput class correctly attached to the CharacterLogic script in the inspector, and I believe everything is set up correctly with the events calling the right action map and function from my code (screenshot attached)
Help?
I have tried following every guide I could see on youtube and they were overly complicated and I couldn't see how I could translate how my old input system was working over to their methods.
Yeah I figured out the actual issue. When you create a control scheme, you are given the "option" to add a requirement. It's not optional, if you don't add a requirement, it won't work. That should really be made a mandatory field.

problems with enemy melee

I've been working on a 2d game for weeks and nothing works. I'm not the best coder out there I'm still learning! In my game I have a player and then an enemy. I need the enemy to behave by itself so I've been following many youtube tutorials, however, it seems that all of them have some sort of problem. I have checked for spelling and everything but still no result. I followed this tutorial (https://www.youtube.com/watch?v=waj6i9cQ6rM) lately but it doesn't work for me. My enemy just plays the attack animation over and over when the player is not even close and it doesn't move from its position.
This is my code:
void EnemyLogic()
{
distance = Vector2.Distance(transform.position, target.transform.position);
if(distance > attackDistance)
{
Move();
StopAttack();
}
else if (attackDistance >= distance && cooling == false)
{
Attack();
}
if (cooling)
{
Cooldown();
Animator.SetBool("Attack", false);
}
}
void Move()
{
Animator.SetBool("canWalk", false);
if(!Animator.GetCurrentAnimatorStateInfo(0).IsName("LightBandit_Attack"))
{
Vector2 targetPosition = new Vector2(target.transform.position.x, transform.position.y);
transform.position = Vector2.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
}
}
void Attack()
{
timer = intTimer; // reset time when player is in rnge
attackMode = true; // check if enemy can still attack or not
Animator.SetBool("canWalk", false);
Animator.SetBool("attack", true);
//Player.GetComponent<HeroKnight>()?.TakeDamage(attackDamage);
}
void Cooldown()
{
timer -= Time.deltaTime;
if(timer <= 0 && cooling && attackMode)
{
cooling = false;
timer = intTimer;
}
}
void StopAttack()
{
cooling = false;
attackMode = false;
Animator.SetBool("attack", false);
}
void RaycastDebugger()
{
if(distance > attackDistance)
{
Debug.DrawRay(rayCast.position, Vector2.left * rayCastLength, Color.red);
}
else if (attackDistance > distance)
{
Debug.DrawRay(rayCast.position, Vector2.left * rayCastLength, Color.green );
}
}
public void TriggerCooling()
{
cooling = true;
}
You have written a condition here that does not allow movement to occur. Eliminate this condition and limit the enemy logic to distances only.
if (!Animator.GetCurrentAnimatorStateInfo(0).IsName("LightBandit_Attack"))

Unity Gun Ammo not Decreasing Problem in Multiplayer (Maybe Related To my Multiplayer System: Photon)

I have a problem in which my ammo won't decrease when I shoot until I wait for a certain Amount of time. I'm currently using Photon as my Network System for my game and my gun code from Brackeys (https://www.youtube.com/watch?v=kAx5g9V5bcM&lc=UghlAulu5dH90HgCoAEC). This is maybe related to internet problems and delays but I'll show you the code I use:
void Update()
{
if(!photonView.IsMine) return;
if (!canShowAmmo)
{
ammoText.text = "Ammo: " + currentAmmo;
}
if (isStarted && (owner.openPanel || MultiplayerManager.main.roomManager.gameDone))
{
if (isScoped)
{
Scope();
}
return;
}
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
if(autoOrSemi == true){
if(Input.GetButton("Fire1") && Time.time >= nextTime){
nextTime = Time.time + 1f/fireRate;
Shoot();
}
}
if(autoOrSemi == false){
if(Input.GetButtonDown("Fire1") && Time.time >= nextTime){
nextTime = Time.time + 1f/fireRate;
Shoot();
}
}
if (Input.GetButtonDown("Fire2"))
{
Scope();
}
}
public void Shoot(){
MuzzleFlash.Play();
currentAmmo--;
AudioSource.PlayClipAtPoint(shotSound, transform.position);
RaycastHit hit;
if (Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range)){
Debug.Log(hit.transform.name);
IDamageable target = hit.collider.gameObject.GetComponent<IDamageable>();
if (target != null)
{
if (hit.collider != owner.GetComponent<Collider>())
{
target.TakeDamage(damage);
owner.score += (int) damage;
owner.ScoreUpdate();
}
}
if(hit.rigidbody != null){
hit.rigidbody.AddForce(-hit.normal * impactForce);
}
GameObject effect = Instantiate(impactEffect, hit.point, Quaternion.LookRotation(hit.normal));
Destroy(effect, 2f);
}
}
public IEnumerator Reload(){
isReloading = true;
Debug.Log("Reloading");
canShowAmmo = true;
ammoText.text = "Reloading...";
yield return new WaitForSeconds(reloadTime - .25f);
yield return new WaitForSeconds(.25f);
canShowAmmo = false;
currentAmmo = maxAmmo;
isReloading = false;
}
so if I was correct and it's caused by lag or I was wrong and didn't have any relation to the Network, please I need a solution. Thanks.
Sorry my bad, I may just found a solution: just add a new private bool and set it to true inside the if function derHugo presented below or above this comment and if bool is false then shooting is disabled then after reloading inside the enumerator after isReloading = false, make the bool to false
I think you issue are concurrent Coroutines!
you are doing
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
This will start a new routine every frame while the condition is met.
You rather want to do e.g.
if (!isReloading && currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
if(isReloading) return;

Unity2D my character jump more than one when i press jump key

https://pasteboard.co/IrKZbCV.png
void OnCollisionEnter2D(Collision2D col)
{
float angle = Vector3.Angle(Vector3.up, col.contacts[0].normal);
if (col.transform.gameObject.tag == "enemyWalk")
{
Physics2D.IgnoreCollision(col.gameObject.GetComponent<Collider2D>(), GetComponent<Collider2D>(), true);
}
else
{
Physics2D.IgnoreCollision(col.gameObject.GetComponent<Collider2D>(), GetComponent<Collider2D>(), false);
}
if (col.transform.gameObject.tag == "stone")
{
angle = Vector3.Angle(Vector3.up, col.contacts[0].normal);
if (Mathf.Approximately(angle, 0))
{
isGround = true;
taş = true;
}
}
else if (col.transform.gameObject.tag == "ground")
{
angle = Vector3.Angle(Vector3.up, col.contacts[0].normal);
if (Mathf.Approximately(angle, 0))
{
isGround = true;
çimen = true;
}
}
}
if ((isJump.jmp || Input.GetKeyDown(KeyCode.Space)) && !isDeath && isGround)
{
rgd.AddForce(new Vector2(0, 2.750f), ForceMode2D.Impulse);
jumpAudio.Play();
isGround = false;
}
İ want to jump my character only one times when i press jump key,but as i show this situation on picture,sometimes my character jumping too high when i jumped at near of the bottom of the rock.İ mean,as if my jump code working many times at same time.
i'm waiting for your helps.

Check if a set of objects is moving Unity 3D

I have several objects with the same tag, and I want to check if they are moving or not, to call a function when they're not moving. So I used the code bellow, but the aremoving is always false even when some objects still moving! Do you know what's wrong in my code?
Script:
bool aremoving;
void LateUpdate()
{
GameObject[] Cubes = GameObject.FindGameObjectsWithTag("Cube");
foreach (GameObject Cube in Cubes)
{
if (Cube.GetComponent<Rigidbody>() == null)
{
continue;
}
if (Cube.GetComponent<Rigidbody>().velocity.magnitude > 0.01)
{
aremoving = true;
}
if (Cube.GetComponent<Rigidbody>().velocity.magnitude <= 0.01)
{
aremoving = false;
}
}
Debug.Log("Cubes moving: " + aremoving);
}
Write the code like this
bool aremoving;
void LateUpdate()
{
GameObject[] Cubes = GameObject.FindGameObjectsWithTag("Cube");
foreach (GameObject Cube in Cubes)
{
if (Cube.GetComponent<Rigidbody>() == null)
{
continue;
}
if (Cube.GetComponent<Rigidbody>().velocity.magnitude > 0.01f)
{
aremoving = true;
}
Debug.Log("Cubes moving: " + aremoving);
aremoving = false;
}

Categories

Resources