Перейти к публикации
Поиск в
  • Дополнительно...
Искать результаты, содержащие...
Искать результаты в...
  • Нужна помощь?

    Создайте тему в соответствующем разделе
    Не нужно писать всё в чат!
  • Загляните на торговую площадку

    Там вы можете купить
    всё что касается игровых серверов
  • Не хотите бан?

    Пожалуйста, ознакомьтесь с нашими правилами
    Не нарушайте порядок!
  • Продаёте или покупаете?

    Пользуйтесь услугами гаранта
    Мы сделаем вашу сделку безопасной
  • 0
SoarinSparkle

Делаю тепловизор, но ничего не рабоает

Вообщем, привет все, кто это читает, хочу поделиться с вами своей разработкой/наработкой тепловизора

И так, я его пытался делать, но у меня ничего не выходит, мод просто у меня не работает и постоянно сыпятся разные ошибки, как я понял движок игры очень капризный. Сам мод решил делать через 
UI пятно на игроке, но короче у меня ничего не вышло, если есть те, кому эта тема тоже интересна, смотрите файлы ниже:

config.cpp:
 

class CfgPatches
{
    class ThermalScopes
    {
        units[] = {};
        weapons[] = {};
        requiredVersion = 0.1;
        requiredAddons[] =
        {
            "DZ_Data",
            "DZ_Weapons_Optics",
            "DZ_Gear_Optics",
            "DZ_Characters"
        };
    };
};

class CfgMods
{
    class ThermalScopes_Mod
    {
        dir = "ThermalScopes";
        name = "Thermal Vision";
        author = "SoarinSparkle";
        version = "1.0";
        type = "mod";
        dependencies[] = {"Game", "World", "Mission"};
        class defs
		{
			class worldScriptModule
			{
			value = "";
			files[] = {"ThermalScopes/Scripts/4_World"};
			};
			class missionScriptModule
			{
			value = "";
			files[] = {"ThermalScopes/Scripts/5_Mission"};
			};
		};
    };
};

// ─────────────────────────────────────
// ПРЕДМЕТЫ
// ─────────────────────────────────────

class CfgVehicles
    class NVGoggles;
    class KazuarOptic;
    class StarlightOptic;
    class NBCJacketGray;

    // ── Тепловые очки ──
    class ThermalGoggles : NVGoggles
    {
        scope = 2;
        displayName = "Очки-тепловизор";
        descriptionShort = "Показывает тепловые сигнатуры. Требует батарейку 9V.";
        weight = 350;
        
        class EnergyManager
        {
            hasIcon = 1;
            energyUsagePerSecond = 0.12;  // батарейка на ~83 секунды
            plugType = 1;
            attachmentAction = 1;
            updateInterval = 1;
        };
    };

    // ── Тепловой прицел под АК
    class KazuarOptic_Thermal : KazuarOptic
    {
        scope = 2;
        displayName = "Тепловой прицел Казуар";
        descriptionShort = "Тепловизионный прицел под крепление АК. Требует батарейку 9V.";
        
        class EnergyManager
        {
            hasIcon = 1;
            energyUsagePerSecond = 0.08;
            plugType = 1;
            attachmentAction = 1;
            updateInterval = 1;
        };
    };

    // ── Тепловой прицел под НАТО ──
    class StarlightOptic_Thermal : StarlightOptic
    {
        scope = 2;
        displayName = "Тепловой прицел AN/PVS-4";
        descriptionShort = "Тепловизионный прицел под НАТО крепление. Требует батарейку 9V.";
        
        class EnergyManager
        {
            hasIcon = 1;
            energyUsagePerSecond = 0.08;
            plugType = 1;
            attachmentAction = 1;
            updateInterval = 1;
        };
    };

    // ── Термокамуфляж (контрмера) ──
    class ThermalCamouflageJacket : NBCJacketGray
    {
        scope = 2;
        displayName = "Термокамуфляжная куртка";
        descriptionShort = "Маскирует тепловую сигнатуру владельца от тепловизоров.";
    };
};

ThermalScopes\Scripts\4_World\PlayerBase.c :
 

// PLAYERBASE — подключение ThermalManager к игроку
modded class PlayerBase
{
    // ── Наш менеджер ──
    protected ref ThermalVisionManager m_ThermalManager;
    protected float m_ThermalTimer;
    protected float m_ThermalInterval = 0.1;

    
    override void OnPlayerLoaded()
    {
        super.OnPlayerLoaded();

        // Создаём менеджер только на клиенте и только для себя
        if (GetGame().IsClient() && IsControlledPlayer())
        {
            m_ThermalManager = new ThermalVisionManager(this);
            Print("[THERMAL] PlayerBase: менеджер создан");
        }
    }

    
    // ГЛАВНЫЙ ТИК
    
    override void EOnFrame(IEntity other, float timeSlice)
    {
        super.EOnFrame(other, timeSlice);

        // Только клиент, только наш игрок
        if (!GetGame().IsClient()) return;
        if (!IsControlledPlayer()) return;
        if (!m_ThermalManager) return;
		
        m_ThermalTimer += timeSlice;
        if (m_ThermalTimer < m_ThermalInterval) return;
        m_ThermalTimer = 0;

        m_ThermalManager.Update(m_ThermalInterval);
    }

    
    // СМЕРТЬ — чистим менеджер
    
    override void EEKilled(Object killer)
    {
        super.EEKilled(killer);

        if (m_ThermalManager)
        {
            m_ThermalManager = null;
            Print("[THERMAL] PlayerBase: менеджер удалён (смерть)");
        }
    }

    
    // ГЕТТЕР — HUD берёт менеджер отсюда
    
    ThermalVisionManager GetThermalManager()
    {
        return m_ThermalManager;
    }
};

ThermalScopes\Scripts\4_World\ThermalHUD.c :
 

// 
// THERMAL HUD

class ThermalHUD : UIScriptedMenu
{
    protected ref array<ref Widget> m_SpotWidgets;
    protected PlayerBase m_Player;
    protected ThermalVisionManager m_Manager;
    protected float m_UpdateTimer;
    protected float m_UpdateInterval = 0.05;
    protected int m_ScreenW;
    protected int m_ScreenH;
    protected Widget m_layoutRoot;

    override Widget Init()
	{
		m_SpotWidgets = new array<ref Widget>;

		m_layoutRoot = GetGame().GetWorkspace().CreateWidgets("ThermalScopes/GUI/layouts/thermal_hud.layout");

		Print("[THERMAL HUD] Инициализирован");
		return m_layoutRoot;
	}

    // ГЛАВНЫЙ АПДЕЙТ
    override void Update(float timeslice)
    {
        super.Update(timeslice);

        if (!m_Player)
        {
            m_Player = PlayerBase.Cast(GetGame().GetPlayer());
            if (!m_Player) return;
        }

        if (!m_Manager)
        {
            m_Manager = m_Player.GetThermalManager();
            if (!m_Manager) return;
        }

        m_UpdateTimer += timeslice;
        if (m_UpdateTimer < m_UpdateInterval) return;
        m_UpdateTimer = 0;

        if (!m_Manager.IsActive())
        {
            HideAllSpots();
            return;
        }

        DrawThermalSpots();
    }

    // РИСОВАНИЕ ВСЕХ ПЯТЕН
    protected void DrawThermalSpots()
    {
        ClearSpotWidgets();

        if (!m_Manager) return;
        map<Object, ref ThermalTarget> targets = m_Manager.GetTargets();
        if (!targets) return;

        int screenWi, screenHi;
        GetScreenSize(screenWi, screenHi);
        
        float screenW = screenWi;
        float screenH = screenHi;

        for (int i = 0; i < targets.Count(); i++)
        {
            ThermalTarget target = targets.GetElement(i);
            
            if (!target || !target.m_Object) continue;
            if (target.m_Heat < 0.05) continue;

            vector worldPos = target.m_Object.GetPosition();
            worldPos[1] = worldPos[1] + 1.3; 

            vector screenPosRelative = GetGame().GetScreenPosRelative(worldPos);

            if (screenPosRelative[2] <= 0) continue;

            float posX = screenPosRelative[0] * screenW;
            float posY = screenPosRelative[1] * screenH;

            // Проверка границ экрана
            if (posX < 0 || posX > screenW) continue;
            if (posY < 0 || posY > screenH) continue;
            
            // Собираем вектор для отрисовки
            vector finalPos = Vector(posX, posY, 0);
            
            DrawSpot(finalPos, target);
        }
    }

    // РИСОВАНИЕ ОДНОГО ПЯТНА
	
    protected void DrawSpot(vector screenPos, ThermalTarget target)
    {
        float heat = target.m_Heat;
        float spotSize = 40.0 * heat;

        if (target.m_IsAnimal)
        {
            spotSize = spotSize * 1.3;
        }

        int r, g, b, a;
        a = Math.Clamp(heat * 200, 30, 220);

        if (heat < 0.5)
        {
            r = 180; g = 60; b = 0;
        }
        else if (heat < 1.0)
        {
            r = 255; g = 100; b = 0;
        }
        else if (heat < 1.5)
        {
            r = 255; g = 160; b = 30;
        }
        else
        {
            r = 255; g = 220; b = 180;
        }

        float posX = screenPos[0] - spotSize * 0.5;
        float posY = screenPos[1] - spotSize * 0.5;


        Widget spotWidget = GetGame().GetWorkspace().CreateWidgets("gui/layouts/debug/thermal_hud.layout", m_layoutRoot);
        

        ImageWidget spot = ImageWidget.Cast(spotWidget);

        if (spot)
        {
            spot.SetPos(posX, posY);
            spot.SetSize(spotSize, spotSize);
            
            spot.SetColor(ARGB(a, r, g, b));
            
            // ВАЖНО: Делаем его круглым! 
            spot.LoadImageFile(0, "set:dayz_gui image:circle"); 
            
            // Добавляем в массив, чтобы потом удалить
            m_SpotWidgets.Insert(spot);
        }
    }

    // КОЛЬЦО СВЕЧЕНИЯ
	
    protected void DrawGlowRing(vector screenPos, float size, int color)
    {
        float posX = screenPos[0] - size * 0.5;
        float posY = screenPos[1] - size * 0.5;

        Widget ringWidget = GetGame().GetWorkspace().CreateWidgets("gui/layouts/debug/thermal_hud.layout", m_layoutRoot);
        ImageWidget ring = ImageWidget.Cast(ringWidget);
        
        if (ring)
        {
            ring.SetPos(posX, posY);
            ring.SetSize(size, size);
            
            // Устанавливаем переданный цвет
            ring.SetColor(color);
            
            // Загружаем кружок, чтобы это выглядело как свечение, а не квадрат
            ring.LoadImageFile(0, "set:dayz_gui image:circle");
            
            m_SpotWidgets.Insert(ring);
        }
    }

    // ОЧИСТКА
	
    protected void ClearSpotWidgets()
    {
        foreach (Widget w : m_SpotWidgets)
        {
            if (w)
            {
                w.Unlink();
            }
        }
        m_SpotWidgets.Clear();
    }

    protected void HideAllSpots()
    {
        ClearSpotWidgets();
    }

    override void OnHide()
    {
        ClearSpotWidgets();
        super.OnHide();
    }
};

ThermalScopes\Scripts\4_World\ThermalManager.c :
 

enum EThermalMode
{
    NONE,
    SCOPE,
    GOGGLES
}

class ThermalTarget
{
    Object m_Object;
    float m_Heat;
    float m_TargetHeat;
    bool m_IsPlayer;
    bool m_IsZombie;
    bool m_IsAnimal;

    void ThermalTarget(Object obj)
    {
        m_Object = obj;
        m_Heat = 0.0;
        m_TargetHeat = 0.0;
        m_IsPlayer = obj.IsInherited(SurvivorBase);
        m_IsZombie = obj.IsInherited(ZombieBase);
        m_IsAnimal = obj.IsInherited(AnimalBase);
    }
}

class ThermalVisionManager
{
    protected PlayerBase m_Player;
    protected EThermalMode m_Mode;
    protected ref map<Object, ref ThermalTarget> m_Targets;
    protected float m_ScanTimer;
    protected float m_ScanInterval = 0.25;
    protected float m_ScanRadius;
    protected float m_ConeDot;

    void ThermalVisionManager(PlayerBase player)
    {
        m_Player = player;
        m_Mode = EThermalMode.NONE;
        m_Targets = new map<Object, ref ThermalTarget>;
        Print("[THERMAL] Manager инициализирован");
    }

    void ~ThermalVisionManager()
    {
        m_Targets.Clear();
        Print("[THERMAL] Manager уничтожен");
    }

    void Update(float deltaTime)
    {
        if (!m_Player || !m_Player.IsAlive()) return;

        EThermalMode newMode = DetectMode();
        if (newMode != m_Mode)
        {
            m_Mode = newMode;
            OnModeChanged();
        }

        if (m_Mode == EThermalMode.NONE)
        {
            UpdateTargetHeats(deltaTime);
            return;
        }

        m_ScanTimer += deltaTime;
        if (m_ScanTimer >= m_ScanInterval)
        {
            m_ScanTimer = 0;
            ScanTargets();
        }

        UpdateTargetHeats(deltaTime);
    }

    protected EThermalMode DetectMode()
    {
        EntityAI headgear = m_Player.GetInventory().FindAttachment(InventorySlots.HEADGEAR);
        if (headgear && headgear.IsKindOf("ThermalGoggles"))
        {
            ComponentEnergyManager em = headgear.GetCompEM();
            if (em && em.IsSwitchedOn())
            {
                return EThermalMode.GOGGLES;
            }
        }

        if (m_Player.IsInOptics())
        {
            Weapon_Base weapon = Weapon_Base.Cast(m_Player.GetHumanInventory().GetEntityInHands());
            if (weapon && HasThermalScope(weapon))
            {
                return EThermalMode.SCOPE;
            }
        }

        return EThermalMode.NONE;
    }

    protected bool HasThermalScope(Weapon_Base weapon)
    {
        int count = weapon.GetInventory().AttachmentCount();
        for (int i = 0; i < count; i++)
        {
            EntityAI att = weapon.GetInventory().GetAttachmentFromIndex(i);
            if (!att) continue;

            if (att.IsKindOf("KazuarOptic_Thermal") || att.IsKindOf("StarlightOptic_Thermal"))
            {
                ComponentEnergyManager em = att.GetCompEM();
                if (em && em.IsSwitchedOn())
                {
                    return true;
                }
            }
        }
        return false;
    }

    protected void OnModeChanged()
    {
        switch (m_Mode)
        {
            case EThermalMode.NONE:
                m_ScanRadius = 0;
                m_ConeDot = 0;
                Print("[THERMAL] Режим: ВЫКЛЮЧЕН");
                break;

            case EThermalMode.SCOPE:
                m_ScanRadius = 600;
                m_ConeDot = 0.85;
                Print("[THERMAL] Режим: ПРИЦЕЛ");
                break;

            case EThermalMode.GOGGLES:
                m_ScanRadius = 150;
                m_ConeDot = 0.3;
                Print("[THERMAL] Режим: ОЧКИ");
                break;
        }
    }

    protected void ScanTargets()
    {
        vector camPos = GetGame().GetCurrentCameraPosition();
        vector camDir = m_Player.GetDirection();

        array<Object> foundObjects = new array<Object>;
        array<CargoBase> foundCargo = new array<CargoBase>;
        GetGame().GetObjectsAtPosition(camPos, m_ScanRadius, foundObjects, foundCargo);

        array<Object> visibleNow = new array<Object>;

        foreach (Object obj : foundObjects)
        {
            if (!obj || obj == m_Player) continue;

            if (!obj.IsInherited(SurvivorBase) && !obj.IsInherited(ZombieBase) && !obj.IsInherited(AnimalBase)) continue;

            vector toTarget = obj.GetPosition() - camPos;
            toTarget.Normalize();
            float dot = toTarget * camDir;
            if (dot < m_ConeDot) continue;

            vector targetPos = obj.GetPosition();
            targetPos[1] = targetPos[1] + 1.3;

            Object hitObj;
            vector hitPos, hitNormal;
            float hitFraction;

            int mask = PhxInteractionLayers.BUILDING | PhxInteractionLayers.VEHICLE | PhxInteractionLayers.TERRAIN;

            bool blocked = DayZPhysics.RayCastBullet(camPos, targetPos, mask, m_Player, hitObj, hitPos, hitNormal, hitFraction);
            if (blocked) continue;

            visibleNow.Insert(obj);

            if (!m_Targets.Contains(obj))
            {
                m_Targets.Set(obj, new ThermalTarget(obj));
                Print("[THERMAL] Новая цель: " + obj.GetType());
            }

            m_Targets[obj].m_TargetHeat = CalculateHeat(obj);
        }

        for (int i = m_Targets.Count() - 1; i >= 0; i--)
        {
            Object key = m_Targets.GetKey(i);
            if (visibleNow.Find(key) == -1)
            {
                m_Targets.GetElement(i).m_TargetHeat = 0.0;
            }
        }
    }

    protected float CalculateHeat(Object obj)
	{
		if (obj.IsInherited(AnimalBase))
		{
			return 1.8;
		}

		if (obj.IsInherited(ZombieBase))
		{
			return 1.4;
		}

		if (obj.IsInherited(SurvivorBase))
		{
			PlayerBase pb = PlayerBase.Cast(obj);
			if (!pb) return 1.0;

			float heat = 1.0;

			// Проверяем состояние движения
			HumanMovementState hms = new HumanMovementState();
			pb.GetMovementState(hms);

			int stance = hms.m_iStanceIdx;
			int movem  = hms.m_iMovement;

			// movem: 0=стоит, 1=шагает, 2=бежит, 3=спринт
			if (movem == 3)
			{
				heat += 1.0;
			}
			else if (movem == 2)
			{
				heat += 0.6;
			}
			else if (movem == 1)
			{
				heat += 0.2;
			}
			else
			{
				heat -= 0.2;
			}

			// Лежит — дополнительно холоднее
			if (stance == 2)
			{
				heat -= 0.2;
			}

			if (pb.GetItemOnSlot("Body")) heat -= 0.15;
			if (pb.GetItemOnSlot("Legs")) heat -= 0.10;
			if (pb.GetItemOnSlot("Feet")) heat -= 0.05;
			if (pb.GetItemOnSlot("Head")) heat -= 0.05;

			EntityAI body = pb.GetItemOnSlot("Body");
			if (body && body.IsKindOf("ThermalCamouflageJacket"))
			{
				heat = 0.1;
			}

			if (pb.IsInWater())
			{
				heat = 0.0;
			}

			return Math.Clamp(heat, 0.0, 2.0);
		}

		return 0.0;
	}

    protected void UpdateTargetHeats(float deltaTime)
    {
        array<Object> toRemove = new array<Object>;

        for (int i = 0; i < m_Targets.Count(); i++)
        {
            ThermalTarget target = m_Targets.GetElement(i);
            if (!target || !target.m_Object) continue;

            float speed;
            if (target.m_Object.IsInherited(SurvivorBase))
            {
                PlayerBase pb = PlayerBase.Cast(target.m_Object);
                if (pb && pb.IsInWater())
                {
                    speed = 0.5;
                }
                else
                {
                    speed = 0.05;
                }
            }
            else
            {
                speed = 0.03;
            }

            target.m_Heat = Math.Lerp(target.m_Heat, target.m_TargetHeat, speed);

            if (target.m_Heat < 0.05 && target.m_TargetHeat == 0.0)
            {
                toRemove.Insert(target.m_Object);
            }
        }

        foreach (Object obj : toRemove)
        {
            m_Targets.Remove(obj);
            Print("[THERMAL] Цель остыла, удалена из списка");
        }
    }

    EThermalMode GetMode()
    {
        return m_Mode;
    }

    map<Object, ref ThermalTarget> GetTargets()
    {
        return m_Targets;
    }

    bool IsActive()
    {
        return m_Mode != EThermalMode.NONE;
    }
}

ThermalScopes\Scripts\5_Mission\ThermalMission.c :
 

modded class MissionGameplay
{
    protected ref ThermalHUD m_ThermalHUD;

    override void OnInit()
    {
        super.OnInit();
        m_ThermalHUD = new ThermalHUD();
        GetGame().GetUIManager().ShowScriptedMenu(m_ThermalHUD, null);
        Print("[THERMAL] HUD зарегистрирован");
    }

    override void OnMissionFinish()
    {
        if (m_ThermalHUD)
        {
            GetGame().GetUIManager().HideScriptedMenu(m_ThermalHUD);
            m_ThermalHUD = null;
        }
        super.OnMissionFinish();
    }
};

ThermalScopes\GUI\layouts\thermal_hud.layout :

<?xml version="1.0" encoding="utf-8"?>
<panel name="ThermalRoot" x="0" y="0" width="1" height="1" type="CANVAS_WIDGET">
</panel>

Вообщем если кто-то хочет помочь, я рад буду, у меня нету глубоко понимания работы движка игры =(
 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Рекомендованные сообщения

Нет ответов на вопрос

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас

×
×
  • Создать...

Важная информация

Используя этот сайт, вы автоматически обязуетесь соблюдать наши Правила и Политика конфиденциальности.
Чтобы сделать этот веб-сайт лучше, мы разместили cookies на вашем устройстве. Вы можете изменить свои настройки cookies, в противном случае мы будем считать, что вы согласны с этим.

Поддержка