PaintBot.cs
using Sandbox;
using System;
using System.Linq;
/// <summary>
/// Автоматичний тестовий бот/турель, який знаходить гравця ворожої команди
/// та стріляє в нього слизом для перевірки механік влучання та смерті.
/// </summary>
public sealed class PaintBot : Component
{
/// <summary>
/// Команда бота: 0 (Синя) або 1 (Червона). За замовчуванням ворожа (1 - Червона).
/// </summary>
[Property, Category( "Settings" )]
public int TeamId { get; set; } = 1;
/// <summary>
/// Частота стрільби (кожні X секунд)
/// </summary>
[Property, Category( "Settings" )]
public float FireRate { get; set; } = 1.5f;
/// <summary>
/// Швидкість польоту снаряда
/// </summary>
[Property, Category( "Settings" )]
public float ProjectileSpeed { get; set; } = 1200f;
/// <summary>
/// Префаб декалі слизу, який буде спавнитися при влучанні
/// </summary>
[Property, Category( "Settings" )]
public GameObject DecalPrefab { get; set; }
/// <summary>
/// Колір слизу бота. Автоматично оновлюється під команду при старті.
/// </summary>
[Property, Category( "Colors" )]
public Color PaintColor { get; set; } = new Color( 1f, 0f, 0f );
private TimeSince timeSinceLastShot;
protected override void OnStart()
{
timeSinceLastShot = 0f;
// Автоматично підбираємо колір під обрану команду
if ( TeamId == 0 )
PaintColor = new Color( 0f, 0.3f, 1f ); // Яскравий синій
else
PaintColor = new Color( 1f, 0f, 0f ); // Яскравий червоний
}
protected override void OnUpdate()
{
// Бот стріляє тільки якщо раунд на карті активний
var gameManager = Scene.GetAllComponents<GameManager>().FirstOrDefault();
if ( gameManager.IsValid() && !gameManager.IsRoundActive ) return;
if ( timeSinceLastShot >= FireRate )
{
ShootAtEnemyPlayer();
timeSinceLastShot = 0f;
}
}
private void ShootAtEnemyPlayer()
{
// Знаходимо локального гравця на сцені
var targetPlayer = Scene.GetAllComponents<PlayerController>().FirstOrDefault( x => !x.IsProxy );
if ( !targetPlayer.IsValid() ) return;
// Переконуємось, що гравець належить до ворожої команди (інакше не стріляємо)
var playerTeam = targetPlayer.Components.Get<PlayerTeam>();
if ( playerTeam.IsValid() )
{
if ( playerTeam.TeamId == TeamId )
{
return; // Це наш союзник, не стріляємо
}
if ( playerTeam.IsDead )
{
return; // Не стріляємо в уже мертвих гравців
}
}
// Розраховуємо напрямок стрільби в голову гравця
Vector3 targetPos = targetPlayer.EyePosition;
Vector3 startPos = WorldPosition;
Vector3 direction = ( targetPos - startPos ).Normal;
// Створюємо об'єкт снаряда
var go = new GameObject();
go.Name = "BotPaintProjectile";
go.WorldPosition = startPos + direction * 50f;
go.LocalScale = Vector3.One * 0.12f;
var renderer = go.Components.Create<ModelRenderer>();
renderer.Model = Model.Load( "models/dev/sphere.vmdl" );
renderer.Tint = PaintColor;
// Додаємо і налаштовуємо скрипт снаряда
var paint = go.Components.Create<PaintProjectile>();
paint.DecalPrefab = DecalPrefab;
paint.PaintColor = PaintColor;
paint.TeamId = TeamId;
paint.Shooter = GameObject; // Бот є стрільцем, кулі ігноруватимуть його тіло
paint.Velocity = direction * ProjectileSpeed;
}
}