// Check only the bottom part of the object protected bool GroundCheck(float sizeY = 0.01f) { Vector2 size = new Vector2(0.1f, sizeY); Vector3 offset = new Vector2(0, sr.bounds.extents.y + size.y); GameDebug.DrawBox(transform.position - offset, size, Color.red); return(Physics2D.BoxCast(transform.position - offset, size, 0, Vector2.down, size.y, LayerMask.GetMask("Ground"))); }
bool CastBox() { Vector2 boxSize = new Vector2(spriteExtents.x / 1.5f, 0.02f); Vector3 boxPos = transform.position - new Vector3(0, spriteExtents.y + boxSize.y + .075f) * Mathf.Sign(rb.gravityScale); GameDebug.DrawBox(boxPos, boxSize, Color.red); return(Physics2D.BoxCast(boxPos, boxSize, 0, Vector2.zero, 0, LayerMask.GetMask("Ground"))); }
bool BoxCast(Vector2 pos, Vector2 size, Color color) { GameDebug.DrawBox(pos, size, color); return(Physics2D.BoxCast(pos, size, 0, Vector2.zero, 0, LayerMask.GetMask("Ground"))); }
void ExecuteBrain(BrainType type) { switch (type) { case BrainType.Maggot: { if (cliffCheck || wallCheck) { targetDir *= -1; } switch (state) { case EnemyState.Normal: { if (!isDelaying) { bool inRange = IsInRangeX(distanceToTeleportX) && IsInRangeY(distanceToTeleportY); if (player.controller.groundCheck && (!inRange || cliffCheck)) { if (canTeleport || cliffCheck) { canTeleport = false; StartCoroutine(Teleport(waitTimeAfterExecute)); } else { StartCoroutine(DelayTeleport(delayTeleportTime)); IEnumerator DelayTeleport(float delayTime) { isDelaying = true; yield return(new WaitForSeconds(delayTime)); canTeleport = true; isDelaying = false; } } } else if (canTeleport) { canTeleport = false; } } if (IsInRange(distanceToExecute)) { StartCoroutine(Explode()); } } break; } } break; case BrainType.NoEyes: { // TODO: Handle cases when the player is still in range after cooldown. switch (state) { case EnemyState.Normal: { if (IsInRange(distanceToExecute)) { StartCoroutine(Dash(true)); } else { targetDir = (player.transform.position - transform.position).normalized; } } break; case EnemyState.Cooldown: { rb.velocity = new Vector2(-Mathf.Sign(player.transform.position.x - transform.position.x), Mathf.Sign(player.transform.position.y - transform.position.y)) * speed * speedAfterDashScale; StartCoroutine(StartState(EnemyState.Charge, abilityCooldownTime)); } break; } } break; case BrainType.FlyDrone: { targetDir = (player.transform.position - transform.position).normalized; if ((targetDir.x < .5f) && (targetDir.x > -.5f)) // between 60-120 degrees { if (targetDir.y > 0) { eye.localPosition = lookUpPos; } else { eye.localPosition = lookDownPos; } } else { eye.localPosition = Vector3.zero; } if (IsInRange(distanceToExecute)) { StartCoroutine(Explode()); StartCoroutine(RotateEnemy(0, timeToReachRot)); } } break; case BrainType.Bat: { targetDir = (player.transform.position - transform.position).normalized; if (IsInRange(distanceToExecute)) { StartCoroutine(Explode()); } } break; case BrainType.GiantEye: { /* * Phase 1: * - Moves like no eyes * - Spawns little eyes * - When dashes and hits wall, create a wave of projectile * Phase 2: * - Moves to the center * - Shoots circle waves of projectiles * - Shoots toward the player * - Shoots big projectiles that explode into smaller projectiles */ switch (state) { case EnemyState.Normal: { // TODO: Sometimes the enemy already collide with wall. Fix it so that the enemy only dash when doesn't collide with wall. if (IsInRange(distanceToExecute)) { StartCoroutine(Dash(false)); // NOTE: Maybe enable trail differently. } #if false else if (Time.time > timer) { timer = Time.time + abilityCooldownTime; int enemyCount = numberOfEnemiesToSpawn.randomValue; for (int i = 0; i < enemyCount; i++) { Vector3 pos; // TODO: Get random position, maybe from RoomManager Instantiate(enemyToSpawn, pos, Quaternion.identity); } anim.Play(""); StartCoroutine(StartState(EnemyState.Charge, anim.GetCurrentAnimatorStateInfo(0).length)); } #endif else { targetDir = (player.transform.position - transform.position).normalized; } } break; case EnemyState.Cooldown: { // Spawn wave of bullets { Vector2 dir = MathUtils.Sign(targetDir); // Make sure the enemy isn't inside wall { float magnitude; // Calculate the magnitude of the ray from the center to the egde of the box collider. // https://stackoverflow.com/questions/1343346/calculate-a-vector-from-the-center-of-a-square-to-edge-based-on-radius { float absCos = Mathf.Abs(Mathf.Cos(targetDir.x)); float absSin = Mathf.Abs(Mathf.Sin(targetDir.y)); if (spriteSize.x * absSin <= spriteSize.y * absCos) { magnitude = spriteSize.x / 2 / absCos; } else { magnitude = spriteSize.y / 2 / absSin; } } Vector2 spriteOrigin = (Vector2)transform.position + spriteOffset * dir.x; RaycastHit2D hitInfo = Physics2D.Raycast(spriteOrigin, targetDir, magnitude, LayerMask.GetMask("Ground")); Debug.DrawRay(spriteOrigin, targetDir * magnitude, Color.white); if (hitInfo) // NOTE: Sometime the enemy stop right before actually touching the ground (because of the raycast's length) so I will need this check. { transform.position -= (Vector3)dir * (magnitude - hitInfo.distance); GameDebug.DrawBox(spriteOrigin - dir * (magnitude - hitInfo.distance), spriteSize, Color.white); } } Vector3 center = transform.position + (Vector3)spriteOffset * dir.x; if (wallCheck) { center.x += (spriteSize.x - 1.5f) / 2 * dir.x; } if (groundCheck) { center.y += (spriteSize.y - 1.5f) / 2 * dir.y; } Vector2 compareOffset = Vector2.Scale(Vector2.one * .2f, dir); // For precision error MathUtils.GenerateCircleOutlineNonAlloc(center, radius, bulletsPos); foreach (var pos in bulletsPos) { if (wallCheck && (Mathf.Sign(pos.x - (center.x + compareOffset.x)) == dir.x)) { continue; } if (groundCheck && (Mathf.Sign(pos.y - (center.y + compareOffset.y)) == dir.y)) { continue; } Vector3 euler = new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, pos - center)); if (euler.z > 90 || euler.z < -90) { euler = new Vector3(0, 180f, 180f - euler.z); } ObjectPooler.Spawn(PoolType.Bullet_Blood, pos, Quaternion.Euler(euler)).GetComponent <MovingEntity>().InitBullet(bulletDamage, false, true); } } anim.Play(""); StartCoroutine(StartState(EnemyState.Charge, waitTimeAfterExecute)); } break; } } break; case BrainType.LittleEye: { // TODO: Behave like no eyes but explode into projectiles when die } break; } }