2023-05-18 06:41:26 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using Godot;
|
|
|
|
using Godot.Collections;
|
|
|
|
|
2023-05-21 04:42:38 +00:00
|
|
|
namespace Pong.Scripts.Objects;
|
2023-05-18 06:41:26 +00:00
|
|
|
|
|
|
|
public partial class Enemy : RigidBody2D
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// draw shapes to the screen (like <see cref="_scanArea"/>).
|
|
|
|
/// </summary>
|
|
|
|
[Export] private bool _drawDebugShapes;
|
|
|
|
[Export] private double _moveSpeed;
|
|
|
|
|
|
|
|
private CollisionShape2D _collisionShape;
|
|
|
|
private Rect2 _scanArea;
|
2023-05-22 01:19:05 +00:00
|
|
|
|
|
|
|
private PhysicsDirectSpaceState2D _spaceState;
|
|
|
|
private readonly Variant _collider = "collider";
|
|
|
|
private PhysicsShapeQueryParameters2D _query;
|
2023-05-18 06:41:26 +00:00
|
|
|
|
|
|
|
public override void _Ready()
|
|
|
|
{
|
|
|
|
_collisionShape = GetNode<CollisionShape2D>("CollisionShape2D");
|
|
|
|
GenerateCastArea();
|
2023-05-22 01:19:05 +00:00
|
|
|
|
|
|
|
_spaceState = GetWorld2D().DirectSpaceState;
|
|
|
|
_query = new PhysicsShapeQueryParameters2D
|
|
|
|
{
|
|
|
|
Shape = new RectangleShape2D { Size = _scanArea.Size },
|
|
|
|
Exclude = new Array<Rid>(new[] { GetRid() })
|
|
|
|
};
|
2023-05-18 06:41:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public override void _PhysicsProcess(double delta)
|
|
|
|
{
|
|
|
|
Scan(delta);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void _Draw()
|
|
|
|
{
|
|
|
|
if (!_drawDebugShapes) return;
|
|
|
|
DrawRect(_scanArea, Colors.Aqua);
|
|
|
|
}
|
2023-05-21 04:42:38 +00:00
|
|
|
|
2023-05-18 06:41:26 +00:00
|
|
|
private void Scan(double delta)
|
|
|
|
{
|
2023-05-22 01:19:05 +00:00
|
|
|
var result = _spaceState.IntersectShape(_query);
|
2023-05-18 06:41:26 +00:00
|
|
|
|
|
|
|
if (result.Count <= 0)
|
|
|
|
{
|
|
|
|
LinearVelocity = Vector2.Zero;
|
|
|
|
return;
|
|
|
|
}
|
2023-05-21 04:42:38 +00:00
|
|
|
|
2023-05-18 06:41:26 +00:00
|
|
|
TrackBall(delta, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// track the distance between the ball and the enemy paddle on the y axis and move velocity accordingly.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="delta">how long it took to complete the last frame in seconds. this should be constant as
|
|
|
|
/// should be executed in the physics process method which should be separate from the main frame rate.</param>
|
|
|
|
/// <param name="result">a dictionary of objects that collided with the cast. this method only works if
|
|
|
|
/// theres an object that has the Ball class.</param>
|
|
|
|
private void TrackBall(double delta, IReadOnlyList<Dictionary> result)
|
|
|
|
{
|
|
|
|
// checks if the collider is a ball, if not, return.
|
2023-05-22 01:19:05 +00:00
|
|
|
if (result[0][_collider].As<Ball>() is not { } ball) return;
|
2023-05-21 04:42:38 +00:00
|
|
|
|
2023-05-18 06:41:26 +00:00
|
|
|
// gets the sign of the distance between the ball and the paddle on the y axis
|
2023-05-21 04:42:38 +00:00
|
|
|
var normalisedDistance = new Vector2 { Y = Mathf.Sign(ball.Position.Y - Position.Y) };
|
2023-05-18 06:41:26 +00:00
|
|
|
var linearVelocity = normalisedDistance * _moveSpeed * Constants.Meter;
|
2023-05-21 04:42:38 +00:00
|
|
|
|
2023-05-18 06:41:26 +00:00
|
|
|
// lerp the velocity to smooth out jerky movement.
|
|
|
|
LinearVelocity = LinearVelocity.Lerp(linearVelocity, delta);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// generate the shape that the cast uses to detect collisions.
|
|
|
|
/// </summary>
|
|
|
|
/// <exception cref="InvalidOperationException">if the collision shape is not a rectangle shape.</exception>
|
|
|
|
private void GenerateCastArea()
|
|
|
|
{
|
|
|
|
if (_collisionShape.Shape is not RectangleShape2D shape)
|
|
|
|
throw new InvalidOperationException("the collision shape needs to be a rectangle shape");
|
2023-05-21 04:42:38 +00:00
|
|
|
|
2023-05-18 06:41:26 +00:00
|
|
|
// grow the area the enemy can see by around half of the screen area.
|
|
|
|
_scanArea = shape.GetRect().GrowSide(Side.Left, 400).GrowIndividual(0, 190, 0, 190);
|
|
|
|
}
|
|
|
|
}
|