/// <summary> /// Gets the 9 tiles that are hopefully nearest to the given position. The actual indices ARE IMPORTANT - don't change them without good reason /// </summary> /// <param name="entityPosition">The position of the object to get tiles nearby to</param> /// <returns></returns> public Tile[] getNearbyTiles(Vector2 entityPosition) { int nearestX = (int) (entityPosition.X-tileWidth/2) / tileWidth; int nearestY = (int) (entityPosition.Y-tileHeight/2) / tileHeight; Tile[] temp; if (nearestX > 0 && nearestY > 0) { temp = new Tile[9]; temp[0] = layout[nearestX, nearestY]; temp[1] = (layout[nearestX, nearestY - 1]); temp[2] = (layout[nearestX, nearestY + 1]); temp[3] = (layout[nearestX - 1, nearestY]); temp[4] = (layout[nearestX - 1, nearestY - 1]); temp[5] = (layout[nearestX - 1, nearestY + 1]); temp[6] = (layout[nearestX + 1, nearestY]); temp[7] = (layout[nearestX + 1, nearestY - 1]); temp[8] = (layout[nearestX + 1, nearestY + 1]); } //things with negative positions are actually outside of the level, and shouldn't collide with anything else { temp = new Tile[1]; temp[0] = layout[0, 0]; } return temp; }
private Boolean nextTileIsSolid(Tile[] nearby) { Boolean shouldMove = true; if (nearby.Length >= 9) { Tile nextTile = getNextTile(nearby); shouldMove = nextTile.isSolid; } return shouldMove; }
//determine whether or not the enemy has a direct line of sight to the player private Boolean canSeePlayer(Vector2 playerPosition, Tile[,] layout) { Vector2 distance = this.position - playerPosition; //if the player is within the viewing corridor and isn't too far away if ((Math.Abs(this.position.Y - playerPosition.Y) <= vertViewRange) && isFacingPlayer(distance) && distance.Length() <= horizViewRange) { Line meToPlayer = new Line(this.position, playerPosition); foreach (Tile block in layout) { if (block.isSolid) { Vector2 tilesize = new Vector2(Level.tileWidth, Level.tileHeight); Line diag1 = new Line(block.position - tilesize /2, block.position + tilesize / 2); Line diag2 = new Line(new Vector2(block.position.X - Level.tileWidth /2, block.position.Y + Level.tileHeight / 2), new Vector2(block.position.X + Level.tileWidth / 2, block.position.Y - Level.tileHeight / 2)); if (Intersects(meToPlayer, diag1) || Intersects(meToPlayer, diag2)) { return false; } } } return true; } else { return false; } }
//gets the next tile that the enemy will be walking on - assumes that motion is left to right ONLY private Tile getNextTile(Tile[] nearby) { if (velocity.X > 0 || (this.velocity == Vector2.Zero && (this.destination.X - this.position.X) > 0)) { return nearby[8]; } else if (velocity.X < 0 || (this.velocity == Vector2.Zero && (this.destination.X - this.position.X < 0))) { return nearby[2]; } else //velocity is zero, choose either { if (!nearby[2].isSolid) return nearby[2]; else return nearby[8]; } }
//update things. will eventually check line-of-sight, shooting, and walking public int Update(float dt, Player player, Bullet[] bullets,Tile[,] layout, Boolean noise,Boolean fallNoise, Tile[] nearby) { Vector2 playerPosition = player.position; int retval = -1; //if the guard is patrolling, let it patrol if (this.isPatrolling) { drawQuestionMark = false; if (patrolRange == 0 && Math.Abs(this.position.X - patrolStart) <= 5) { velocity.X = 0; } else if (position.X >= patrolStart + patrolRange || this.collideRight) { velocity.X = -patrolspeed; } else if (position.X <= patrolStart - patrolRange || this.collideLeft) { velocity.X = patrolspeed; } } //if it can see the player, shoot at it! if (this.canSeePlayer(playerPosition, layout)) { drawQuestionMark = false; drawExclamationPoint = true; //dont resume patrol if we can see the player! waitTimer = 0; if (weaponType == 1) { timeSinceLastFire += dt; if (timeSinceLastFire > fireInterval) { fireBullet(this.position - playerPosition, bullets); timeSinceLastFire = 0; retval = 1; } } else if (weaponType == 2) { if (!hasStartedLazer) { hasStartedLazer = true; timeSinceLastFire = 0; Particle_Engine.ParticleEngine.removeEmmiter(emitter); emitter = new Particle_Engine.LazerChargeEmitter(this.position, lazerChargeTime); Particle_Engine.ParticleEngine.addEmitter(emitter); } else { timeSinceLastFire += dt; velocity.X = 0; if (timeSinceLastFire > lazerChargeTime) { shouldFire = true; } if (timeSinceLastFire + 1 > lazerChargeTime) retval = 2; } } isPatrolling = false; isInvestigating = true; destination = playerPosition; } else { if (hasStartedLazer) Particle_Engine.ParticleEngine.removeEmmiter(emitter); shouldFire = false; drawExclamationPoint = false; hasStartedLazer = false; timeSinceLastFire = fireInterval + LAZER_CHARGE_TIME + 100; } //if there is noise while patrolling if (noise) { Vector2 distance = player.theHook.position - this.position; //if the guard can actually hear it if (distance.Length() < soundRange) { waitTimer = 0; this.isPatrolling = false; this.isInvestigating = true; drawQuestionMark = true; this.destination = player.theHook.position; } } if (fallNoise) { Vector2 distance = player.position - this.position; //if the guard can actually hear it if (distance.Length() < soundRange) { waitTimer = 0; this.isPatrolling = false; drawQuestionMark = true; this.isInvestigating = true; this.destination = player.position; } } //if we're investigating something (like a noise, say) if (this.isInvestigating) { drawQuestionMark = true; Vector2 distance = this.destination - this.position; //if we're close or if the next tile isn't solid, stop or if we seem to have gotten stuck if (Math.Abs(distance.X) <= 5 || !this.nextTileIsSolid(nearby) || collideLeft || collideRight) { this.velocity.X = 0; waitTimer += dt; if (waitTimer > investigateMaxWait) { isInvestigating = false; drawQuestionMark = false; isPatrolling = true; this.velocity.X = -patrolspeed * ((this.position.X - this.patrolStart) / (Math.Abs(this.position.X - this.patrolStart))); waitTimer = 0; } } //otherwise continue (or start) moving at PATROLSPEED towards the noise else if (distance.X * velocity.X <= 0 && !hasStartedLazer) { this.velocity.X = patrolspeed * (distance.X / Math.Abs(distance.X)); } } if (this.hasStartedLazer) { if (timeSinceLastFire - lazerChargeTime >= lazerDuration) { timeSinceLastFire = 0; this.hasStartedLazer = false; } } if (velocity.X < -.1f) facingRight = false; if (velocity.X > .1f) facingRight = true; if (!nextTileIsSolid(nearby)) { this.velocity.X *= -1; } applyGravity(); base.Update(dt); return retval; }