Loading Now

POPULER

Opposer Vr Script -

using UnityEngine;
using UnityEngine.AI;
using System.Collections;
using Unity.XR.CoreUtils;
public class OpposerVR : MonoBehaviour
[Header("Movement Settings")]
    [SerializeField] private float chaseSpeed = 3.5f;
    [SerializeField] private float patrolSpeed = 1.5f;
    [SerializeField] private float stoppingDistance = 2.0f;
    [SerializeField] private float chaseRange = 10.0f;
    [SerializeField] private float attackRange = 2.0f;
    [SerializeField] private float patrolRadius = 15.0f;
    [SerializeField] private float waitTimeAtPatrolPoint = 2.0f;
[Header("Combat Settings")]
    [SerializeField] private int maxHealth = 100;
    [SerializeField] private int attackDamage = 15;
    [SerializeField] private float attackCooldown = 1.5f;
    [SerializeField] private float attackAnimDuration = 0.5f;
    [SerializeField] private GameObject projectilePrefab;
    [SerializeField] private Transform projectileSpawnPoint;
    [SerializeField] private bool isRangedAttacker = false;
[Header("Senses")]
    [SerializeField] private float fieldOfView = 110f;
    [SerializeField] private float hearingRadius = 12f;
    [SerializeField] private LayerMask obstructionMask;
    [SerializeField] private LayerMask playerLayer;
[Header("Behavior")]
    [SerializeField] private bool useCover = true;
    [SerializeField] private float coverCheckInterval = 1.5f;
    [SerializeField] private float fleeHealthThreshold = 25f;
[Header("Audio")]
    [SerializeField] private AudioClip[] attackSounds;
    [SerializeField] private AudioClip[] hurtSounds;
    [SerializeField] private AudioClip[] deathSounds;
    [SerializeField] private AudioClip[] spottedSounds;
    [SerializeField] private float audioVolume = 0.7f;
// Components
    private NavMeshAgent agent;
    private Animator animator;
    private AudioSource audioSource;
    private Transform player;
    private XROrigin xrOrigin;
    private int currentHealth;
    private bool isDead = false;
    private bool isAttacking = false;
    private float nextAttackTime = 0f;
    private float nextCoverCheck = 0f;
    private Vector3 lastKnownPlayerPosition;
    private bool playerSpotted = false;
    private bool isInvestigating = false;
    private Vector3 investigationPoint;
    private Vector3 currentCoverPoint;
// Patrol variables
    private Vector3 patrolTarget;
    private bool isWaiting = false;
// States
    private enum AIState  Patrol, Chase, Attack, Investigate, Flee, TakeCover 
    private AIState currentState = AIState.Patrol;
void Start()
// Get components
        agent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
        audioSource = GetComponent<AudioSource>();
if (audioSource == null)
            audioSource = gameObject.AddComponent<AudioSource>();
// Find player
        xrOrigin = FindObjectOfType<XROrigin>();
        if (xrOrigin != null)
            player = xrOrigin.transform;
currentHealth = maxHealth;
        agent.speed = patrolSpeed;
// Set initial patrol point
        SetNewPatrolPoint();
// Start coroutines
        StartCoroutine(SensePlayerRoutine());
if (useCover)
            StartCoroutine(CoverCheckRoutine());
void Update()
if (isDead) return;
// State machine
        switch (currentState)
case AIState.Patrol:
                PatrolBehavior();
                break;
            case AIState.Chase:
                ChaseBehavior();
                break;
            case AIState.Attack:
                AttackBehavior();
                break;
            case AIState.Investigate:
                InvestigateBehavior();
                break;
            case AIState.Flee:
                FleeBehavior();
                break;
            case AIState.TakeCover:
                TakeCoverBehavior();
                break;
// Update animator
        UpdateAnimations();
#region Behavior Methods
private void PatrolBehavior()
// Check if reached patrol point
        if (!agent.pathPending && agent.remainingDistance < 0.5f && !isWaiting)
StartCoroutine(PatrolWait());
// Transition to chase if player spotted
        if (playerSpotted && !isInvestigating)
SwitchState(AIState.Chase);
private void ChaseBehavior()
if (!playerSpotted
private void AttackBehavior()
if (isAttacking) return;
float distanceToPlayer = Vector3.Distance(transform.position, player.position);
if (distanceToPlayer <= attackRange)
StartCoroutine(PerformAttack());
else
SwitchState(AIState.Chase);
private void InvestigateBehavior()
if (!isInvestigating)
isInvestigating = true;
            investigationPoint = lastKnownPlayerPosition;
            agent.SetDestination(investigationPoint);
            agent.speed = patrolSpeed;
// Check if reached investigation point
        if (!agent.pathPending && agent.remainingDistance < 0.5f)
StartCoroutine(FinishInvestigation());
// Re-check for player during investigation
        if (playerSpotted)
isInvestigating = false;
            SwitchState(AIState.Chase);
private void FleeBehavior()
// Find direction away from player
        Vector3 fleeDirection = transform.position - player.position;
        Vector3 fleePoint = transform.position + fleeDirection.normalized * 15f;
// Ensure flee point is within navmesh
        NavMeshHit hit;
        if (NavMesh.SamplePosition(fleePoint, out hit, 10f, NavMesh.AllAreas))
agent.SetDestination(hit.position);
            agent.speed = chaseSpeed * 1.2f;
// Regain health or return to chase
        if (currentHealth > fleeHealthThreshold + 15f && playerSpotted)
SwitchState(AIState.Chase);
else if (!playerSpotted)
SwitchState(AIState.Patrol);
private void TakeCoverBehavior()
     !IsCoverValid(currentCoverPoint))
FindBestCover();
if (currentCoverPoint != Vector3.zero)
agent.SetDestination(currentCoverPoint);
// Check if in cover
            if (!agent.pathPending && agent.remainingDistance < 1f)
// Wait in cover
                StartCoroutine(WaitInCover());
else
SwitchState(AIState.Chase);
#endregion
#region Helper Methods
private IEnumerator SensePlayerRoutine()
while (!isDead)
if (player != null && !playerSpotted)
yield return new WaitForSeconds(0.2f);
private bool CanSeePlayer()
if (player == null) return false;
Vector3 directionToPlayer = (player.position - transform.position).normalized;
        float angleToPlayer = Vector3.Angle(transform.forward, directionToPlayer);
if (angleToPlayer < fieldOfView / 2)
float distanceToPlayer = Vector3.Distance(transform.position, player.position);
if (distanceToPlayer <= chaseRange)
// Raycast to check for obstacles
                RaycastHit hit;
                if (Physics.Raycast(transform.position + Vector3.up * 1f, directionToPlayer, out hit, chaseRange, obstructionMask))
if (hit.transform == player
return false;
private bool CanHearPlayer()
if (player == null) return false;
float distanceToPlayer = Vector3.Distance(transform.position, player.position);
// Check if player is moving fast (running)
        CharacterController controller = player.GetComponent<CharacterController>();
        if (controller != null && controller.velocity.magnitude > 2f)
return distanceToPlayer < hearingRadius;
return false;
private bool IsUnderFire()
// Simple check - can be expanded with projectile hit detection
        return currentHealth < maxHealth * 0.7f;
private void FindBestCover()
// Simple cover finding - looks for objects with "Cover" tag
        GameObject[] coverObjects = GameObject.FindGameObjectsWithTag("Cover");
        float bestScore = 0f;
        Vector3 bestCover = Vector3.zero;
foreach (GameObject cover in coverObjects)
Vector3 coverPos = cover.transform.position;
            float distanceToCover = Vector3.Distance(transform.position, coverPos);
            float distanceFromPlayer = Vector3.Distance(player.position, coverPos);
// Score based on distance and protection
            float score = (100f / distanceToCover) + distanceFromPlayer;
if (score > bestScore && IsCoverValid(coverPos))
bestScore = score;
                bestCover = coverPos;
currentCoverPoint = bestCover;
private bool IsCoverValid(Vector3 coverPoint)
if (player == null) return false;
// Check if cover is between enemy and player
        Vector3 directionToPlayer = player.position - transform.position;
        Vector3 directionToCover = coverPoint - transform.position;
float angleDiff = Vector3.Angle(directionToPlayer, directionToCover);
return angleDiff < 45f;
private IEnumerator PerformAttack()
isAttacking = true;
        nextAttackTime = Time.time + attackCooldown;
// Play attack animation
        if (animator != null)
            animator.SetTrigger("Attack");
PlaySound(attackSounds);
// Wait for attack animation
        yield return new WaitForSeconds(attackAnimDuration * 0.5f);
// Deal damage
        if (player != null && Vector3.Distance(transform.position, player.position) <= attackRange)
if (isRangedAttacker && projectilePrefab != null && projectileSpawnPoint != null)
GameObject projectile = Instantiate(projectilePrefab, projectileSpawnPoint.position, Quaternion.LookRotation(player.position - projectileSpawnPoint.position));
                Projectile projectileScript = projectile.GetComponent<Projectile>();
                if (projectileScript != null)
                    projectileScript.Initialize(attackDamage, player.gameObject);
else
// Melee damage
                PlayerHealth playerHealth = player.GetComponent<PlayerHealth>();
                if (playerHealth != null)
                    playerHealth.TakeDamage(attackDamage);
yield return new WaitForSeconds(attackAnimDuration * 0.5f);
isAttacking = false;
        SwitchState(AIState.Chase);
private IEnumerator PatrolWait()
isWaiting = true;
        agent.isStopped = true;
yield return new WaitForSeconds(waitTimeAtPatrolPoint);
agent.isStopped = false;
        SetNewPatrolPoint();
        isWaiting = false;
private IEnumerator FinishInvestigation()
yield return new WaitForSeconds(2f);
        isInvestigating = false;
        playerSpotted = false;
        SwitchState(AIState.Patrol);
private IEnumerator WaitInCover()
agent.isStopped = true;
        yield return new WaitForSeconds(3f);
        agent.isStopped = false;
        SwitchState(AIState.Chase);
private IEnumerator CoverCheckRoutine()
while (!isDead)
nextCoverCheck = Time.time + coverCheckInterval;
            yield return new WaitForSeconds(coverCheckInterval);
private void SetNewPatrolPoint()
Vector3 randomDirection = Random.insideUnitSphere * patrolRadius;
        randomDirection += transform.position;
NavMeshHit hit;
        if (NavMesh.SamplePosition(randomDirection, out hit, patrolRadius, NavMesh.AllAreas))
patrolTarget = hit.position;
            agent.SetDestination(patrolTarget);
private void SwitchState(AIState newState)
if (currentState == newState) return;
// Exit current state
        switch (currentState)
case AIState.Attack:
                StopCoroutine(PerformAttack());
                isAttacking = false;
                break;
currentState = newState;
// Enter new state
        switch (currentState)
case AIState.Patrol:
                agent.speed = patrolSpeed;
                break;
            case AIState.Flee:
                if (animator != null)
                    animator.SetTrigger("Flee");
                break;
private void UpdateAnimations()
if (animator == null) return;
float speed = agent.velocity.magnitude;
        animator.SetFloat("Speed", speed);
        animator.SetBool("IsDead", isDead);
private void PlaySound(AudioClip[] clips)
     clips.Length == 0) return;
AudioClip clip = clips[Random.Range(0, clips.Length)];
        audioSource.PlayOneShot(clip, audioVolume);
#endregion
#region Public Methods
public void TakeDamage(int damage)
if (isDead) return;
currentHealth -= damage;
        PlaySound(hurtSounds);
if (animator != null)
            animator.SetTrigger("Hurt");
if (currentHealth <= 0)
Die();
else
// React to being hit
            playerSpotted = true;
            lastKnownPlayerPosition = player.position;
            SwitchState(AIState.Chase);
private void Die()
isDead = true;
        agent.isStopped = true;
        PlaySound(deathSounds);
if (animator != null)
            animator.SetTrigger("Die");
// Disable collider to prevent further interaction
        Collider col = GetComponent<Collider>();
        if (col != null)
            col.enabled = false;
Destroy(gameObject, 5f);
#endregion
// Optional: Projectile script for ranged attackers
public class Projectile : MonoBehaviour
private int damage;
    private GameObject ignoreTarget;
    [SerializeField] private float speed = 20f;
    [SerializeField] private float lifetime = 5f;
public void Initialize(int dmg, GameObject ignore)
damage = dmg;
        ignoreTarget = ignore;
        Destroy(gameObject, lifetime);
void Update()
transform.Translate(Vector3.forward * speed * Time.deltaTime);
void OnTriggerEnter(Collider other)
if (other.gameObject == ignoreTarget) return;
if (other.CompareTag("Player"))
PlayerHealth playerHealth = other.GetComponent<PlayerHealth>();
            if (playerHealth != null)
                playerHealth.TakeDamage(damage);
Destroy(gameObject);

Script Structure:

The structure of such a script would depend heavily on the platform (e.g., Unity, Unreal Engine) and the programming languages used (e.g., C#, C++, Blueprints).

For example, in Unity with C#, a simple example of a mechanic could be: $$void opponentMovement()$$ $$$$ $$ // Define movement speed$$ $$ public float speed = 5.0f;$$ $$ // Reference to the opponent's transform$$ $$ private Transform opponent;$$ $$ // Update is called once per frame$$ $$ void Update()$$ $$ $$ $$ // Simple movement$$ $$ opponent.position += new Vector3(0, 0, speed * Time.deltaTime);$$ $$ $$ $$ $$ opposer vr script

The Archer (Ranged Opposer)

  • Modification: Remove dodge logic; add projectile prediction.
  • Special Logic: The script uses Vector3.Lerp to lead its shots. It aims not at the player's current head, but where the head will be in 0.2 seconds.

2.1 Reactive Blocking (if player raises hand)

public class VRBlockReaction : MonoBehaviour
public VROpposer opposer;
    public Transform leftHand, rightHand;
    public float blockDetectionAngle = 45f;
void Update()
bool isBlocking = CheckIfPlayerIsBlocking();
    opposer.animator.SetBool("PlayerBlocking", isBlocking);
    if (isBlocking && opposer.enabled)
        opposer.attackCooldown *= 0.7f; // shorter cooldown if blocked
bool CheckIfPlayerIsBlocking()

using UnityEngine;
using UnityEngine.AI;
using System.Collections;
using Unity.XR.CoreUtils;
public class OpposerVR : MonoBehaviour
[Header("Movement Settings")]
    [SerializeField] private float chaseSpeed = 3.5f;
    [SerializeField] private float patrolSpeed = 1.5f;
    [SerializeField] private float stoppingDistance = 2.0f;
    [SerializeField] private float chaseRange = 10.0f;
    [SerializeField] private float attackRange = 2.0f;
    [SerializeField] private float patrolRadius = 15.0f;
    [SerializeField] private float waitTimeAtPatrolPoint = 2.0f;
[Header("Combat Settings")]
    [SerializeField] private int maxHealth = 100;
    [SerializeField] private int attackDamage = 15;
    [SerializeField] private float attackCooldown = 1.5f;
    [SerializeField] private float attackAnimDuration = 0.5f;
    [SerializeField] private GameObject projectilePrefab;
    [SerializeField] private Transform projectileSpawnPoint;
    [SerializeField] private bool isRangedAttacker = false;
[Header("Senses")]
    [SerializeField] private float fieldOfView = 110f;
    [SerializeField] private float hearingRadius = 12f;
    [SerializeField] private LayerMask obstructionMask;
    [SerializeField] private LayerMask playerLayer;
[Header("Behavior")]
    [SerializeField] private bool useCover = true;
    [SerializeField] private float coverCheckInterval = 1.5f;
    [SerializeField] private float fleeHealthThreshold = 25f;
[Header("Audio")]
    [SerializeField] private AudioClip[] attackSounds;
    [SerializeField] private AudioClip[] hurtSounds;
    [SerializeField] private AudioClip[] deathSounds;
    [SerializeField] private AudioClip[] spottedSounds;
    [SerializeField] private float audioVolume = 0.7f;
// Components
    private NavMeshAgent agent;
    private Animator animator;
    private AudioSource audioSource;
    private Transform player;
    private XROrigin xrOrigin;
    private int currentHealth;
    private bool isDead = false;
    private bool isAttacking = false;
    private float nextAttackTime = 0f;
    private float nextCoverCheck = 0f;
    private Vector3 lastKnownPlayerPosition;
    private bool playerSpotted = false;
    private bool isInvestigating = false;
    private Vector3 investigationPoint;
    private Vector3 currentCoverPoint;
// Patrol variables
    private Vector3 patrolTarget;
    private bool isWaiting = false;
// States
    private enum AIState  Patrol, Chase, Attack, Investigate, Flee, TakeCover 
    private AIState currentState = AIState.Patrol;
void Start()
// Get components
        agent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
        audioSource = GetComponent<AudioSource>();
if (audioSource == null)
            audioSource = gameObject.AddComponent<AudioSource>();
// Find player
        xrOrigin = FindObjectOfType<XROrigin>();
        if (xrOrigin != null)
            player = xrOrigin.transform;
currentHealth = maxHealth;
        agent.speed = patrolSpeed;
// Set initial patrol point
        SetNewPatrolPoint();
// Start coroutines
        StartCoroutine(SensePlayerRoutine());
if (useCover)
            StartCoroutine(CoverCheckRoutine());
void Update()
if (isDead) return;
// State machine
        switch (currentState)
case AIState.Patrol:
                PatrolBehavior();
                break;
            case AIState.Chase:
                ChaseBehavior();
                break;
            case AIState.Attack:
                AttackBehavior();
                break;
            case AIState.Investigate:
                InvestigateBehavior();
                break;
            case AIState.Flee:
                FleeBehavior();
                break;
            case AIState.TakeCover:
                TakeCoverBehavior();
                break;
// Update animator
        UpdateAnimations();
#region Behavior Methods
private void PatrolBehavior()
// Check if reached patrol point
        if (!agent.pathPending && agent.remainingDistance < 0.5f && !isWaiting)
StartCoroutine(PatrolWait());
// Transition to chase if player spotted
        if (playerSpotted && !isInvestigating)
SwitchState(AIState.Chase);
private void ChaseBehavior()
if (!playerSpotted
private void AttackBehavior()
if (isAttacking) return;
float distanceToPlayer = Vector3.Distance(transform.position, player.position);
if (distanceToPlayer <= attackRange)
StartCoroutine(PerformAttack());
else
SwitchState(AIState.Chase);
private void InvestigateBehavior()
if (!isInvestigating)
isInvestigating = true;
            investigationPoint = lastKnownPlayerPosition;
            agent.SetDestination(investigationPoint);
            agent.speed = patrolSpeed;
// Check if reached investigation point
        if (!agent.pathPending && agent.remainingDistance < 0.5f)
StartCoroutine(FinishInvestigation());
// Re-check for player during investigation
        if (playerSpotted)
isInvestigating = false;
            SwitchState(AIState.Chase);
private void FleeBehavior()
// Find direction away from player
        Vector3 fleeDirection = transform.position - player.position;
        Vector3 fleePoint = transform.position + fleeDirection.normalized * 15f;
// Ensure flee point is within navmesh
        NavMeshHit hit;
        if (NavMesh.SamplePosition(fleePoint, out hit, 10f, NavMesh.AllAreas))
agent.SetDestination(hit.position);
            agent.speed = chaseSpeed * 1.2f;
// Regain health or return to chase
        if (currentHealth > fleeHealthThreshold + 15f && playerSpotted)
SwitchState(AIState.Chase);
else if (!playerSpotted)
SwitchState(AIState.Patrol);
private void TakeCoverBehavior()
     !IsCoverValid(currentCoverPoint))
FindBestCover();
if (currentCoverPoint != Vector3.zero)
agent.SetDestination(currentCoverPoint);
// Check if in cover
            if (!agent.pathPending && agent.remainingDistance < 1f)
// Wait in cover
                StartCoroutine(WaitInCover());
else
SwitchState(AIState.Chase);
#endregion
#region Helper Methods
private IEnumerator SensePlayerRoutine()
while (!isDead)
if (player != null && !playerSpotted)
yield return new WaitForSeconds(0.2f);
private bool CanSeePlayer()
if (player == null) return false;
Vector3 directionToPlayer = (player.position - transform.position).normalized;
        float angleToPlayer = Vector3.Angle(transform.forward, directionToPlayer);
if (angleToPlayer < fieldOfView / 2)
float distanceToPlayer = Vector3.Distance(transform.position, player.position);
if (distanceToPlayer <= chaseRange)
// Raycast to check for obstacles
                RaycastHit hit;
                if (Physics.Raycast(transform.position + Vector3.up * 1f, directionToPlayer, out hit, chaseRange, obstructionMask))
if (hit.transform == player
return false;
private bool CanHearPlayer()
if (player == null) return false;
float distanceToPlayer = Vector3.Distance(transform.position, player.position);
// Check if player is moving fast (running)
        CharacterController controller = player.GetComponent<CharacterController>();
        if (controller != null && controller.velocity.magnitude > 2f)
return distanceToPlayer < hearingRadius;
return false;
private bool IsUnderFire()
// Simple check - can be expanded with projectile hit detection
        return currentHealth < maxHealth * 0.7f;
private void FindBestCover()
// Simple cover finding - looks for objects with "Cover" tag
        GameObject[] coverObjects = GameObject.FindGameObjectsWithTag("Cover");
        float bestScore = 0f;
        Vector3 bestCover = Vector3.zero;
foreach (GameObject cover in coverObjects)
Vector3 coverPos = cover.transform.position;
            float distanceToCover = Vector3.Distance(transform.position, coverPos);
            float distanceFromPlayer = Vector3.Distance(player.position, coverPos);
// Score based on distance and protection
            float score = (100f / distanceToCover) + distanceFromPlayer;
if (score > bestScore && IsCoverValid(coverPos))
bestScore = score;
                bestCover = coverPos;
currentCoverPoint = bestCover;
private bool IsCoverValid(Vector3 coverPoint)
if (player == null) return false;
// Check if cover is between enemy and player
        Vector3 directionToPlayer = player.position - transform.position;
        Vector3 directionToCover = coverPoint - transform.position;
float angleDiff = Vector3.Angle(directionToPlayer, directionToCover);
return angleDiff < 45f;
private IEnumerator PerformAttack()
isAttacking = true;
        nextAttackTime = Time.time + attackCooldown;
// Play attack animation
        if (animator != null)
            animator.SetTrigger("Attack");
PlaySound(attackSounds);
// Wait for attack animation
        yield return new WaitForSeconds(attackAnimDuration * 0.5f);
// Deal damage
        if (player != null && Vector3.Distance(transform.position, player.position) <= attackRange)
if (isRangedAttacker && projectilePrefab != null && projectileSpawnPoint != null)
GameObject projectile = Instantiate(projectilePrefab, projectileSpawnPoint.position, Quaternion.LookRotation(player.position - projectileSpawnPoint.position));
                Projectile projectileScript = projectile.GetComponent<Projectile>();
                if (projectileScript != null)
                    projectileScript.Initialize(attackDamage, player.gameObject);
else
// Melee damage
                PlayerHealth playerHealth = player.GetComponent<PlayerHealth>();
                if (playerHealth != null)
                    playerHealth.TakeDamage(attackDamage);
yield return new WaitForSeconds(attackAnimDuration * 0.5f);
isAttacking = false;
        SwitchState(AIState.Chase);
private IEnumerator PatrolWait()
isWaiting = true;
        agent.isStopped = true;
yield return new WaitForSeconds(waitTimeAtPatrolPoint);
agent.isStopped = false;
        SetNewPatrolPoint();
        isWaiting = false;
private IEnumerator FinishInvestigation()
yield return new WaitForSeconds(2f);
        isInvestigating = false;
        playerSpotted = false;
        SwitchState(AIState.Patrol);
private IEnumerator WaitInCover()
agent.isStopped = true;
        yield return new WaitForSeconds(3f);
        agent.isStopped = false;
        SwitchState(AIState.Chase);
private IEnumerator CoverCheckRoutine()
while (!isDead)
nextCoverCheck = Time.time + coverCheckInterval;
            yield return new WaitForSeconds(coverCheckInterval);
private void SetNewPatrolPoint()
Vector3 randomDirection = Random.insideUnitSphere * patrolRadius;
        randomDirection += transform.position;
NavMeshHit hit;
        if (NavMesh.SamplePosition(randomDirection, out hit, patrolRadius, NavMesh.AllAreas))
patrolTarget = hit.position;
            agent.SetDestination(patrolTarget);
private void SwitchState(AIState newState)
if (currentState == newState) return;
// Exit current state
        switch (currentState)
case AIState.Attack:
                StopCoroutine(PerformAttack());
                isAttacking = false;
                break;
currentState = newState;
// Enter new state
        switch (currentState)
case AIState.Patrol:
                agent.speed = patrolSpeed;
                break;
            case AIState.Flee:
                if (animator != null)
                    animator.SetTrigger("Flee");
                break;
private void UpdateAnimations()
if (animator == null) return;
float speed = agent.velocity.magnitude;
        animator.SetFloat("Speed", speed);
        animator.SetBool("IsDead", isDead);
private void PlaySound(AudioClip[] clips)
     clips.Length == 0) return;
AudioClip clip = clips[Random.Range(0, clips.Length)];
        audioSource.PlayOneShot(clip, audioVolume);
#endregion
#region Public Methods
public void TakeDamage(int damage)
if (isDead) return;
currentHealth -= damage;
        PlaySound(hurtSounds);
if (animator != null)
            animator.SetTrigger("Hurt");
if (currentHealth <= 0)
Die();
else
// React to being hit
            playerSpotted = true;
            lastKnownPlayerPosition = player.position;
            SwitchState(AIState.Chase);
private void Die()
isDead = true;
        agent.isStopped = true;
        PlaySound(deathSounds);
if (animator != null)
            animator.SetTrigger("Die");
// Disable collider to prevent further interaction
        Collider col = GetComponent<Collider>();
        if (col != null)
            col.enabled = false;
Destroy(gameObject, 5f);
#endregion
// Optional: Projectile script for ranged attackers
public class Projectile : MonoBehaviour
private int damage;
    private GameObject ignoreTarget;
    [SerializeField] private float speed = 20f;
    [SerializeField] private float lifetime = 5f;
public void Initialize(int dmg, GameObject ignore)
damage = dmg;
        ignoreTarget = ignore;
        Destroy(gameObject, lifetime);
void Update()
transform.Translate(Vector3.forward * speed * Time.deltaTime);
void OnTriggerEnter(Collider other)
if (other.gameObject == ignoreTarget) return;
if (other.CompareTag("Player"))
PlayerHealth playerHealth = other.GetComponent<PlayerHealth>();
            if (playerHealth != null)
                playerHealth.TakeDamage(damage);
Destroy(gameObject);

Script Structure:

The structure of such a script would depend heavily on the platform (e.g., Unity, Unreal Engine) and the programming languages used (e.g., C#, C++, Blueprints).

For example, in Unity with C#, a simple example of a mechanic could be: $$void opponentMovement()$$ $$$$ $$ // Define movement speed$$ $$ public float speed = 5.0f;$$ $$ // Reference to the opponent's transform$$ $$ private Transform opponent;$$ $$ // Update is called once per frame$$ $$ void Update()$$ $$ $$ $$ // Simple movement$$ $$ opponent.position += new Vector3(0, 0, speed * Time.deltaTime);$$ $$ $$ $$ $$

The Archer (Ranged Opposer)

  • Modification: Remove dodge logic; add projectile prediction.
  • Special Logic: The script uses Vector3.Lerp to lead its shots. It aims not at the player's current head, but where the head will be in 0.2 seconds.

2.1 Reactive Blocking (if player raises hand)

public class VRBlockReaction : MonoBehaviour
public VROpposer opposer;
    public Transform leftHand, rightHand;
    public float blockDetectionAngle = 45f;
void Update()
bool isBlocking = CheckIfPlayerIsBlocking();
    opposer.animator.SetBool("PlayerBlocking", isBlocking);
    if (isBlocking && opposer.enabled)
        opposer.attackCooldown *= 0.7f; // shorter cooldown if blocked
bool CheckIfPlayerIsBlocking()

Post Comment

You cannot copy content of this page