Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
  • Need help?

    Create a topic in the appropriate section
    Don't write everything in the chat!
  • Take a look at the marketplace

    There you can buy
    everything related to game servers
  • Don't want a ban?

    Please read our rules
    Don't disturb the order!
  • Sell or buy?

    Use services of the guarantor
    We will make your deal safe
  • 0
Sign in to follow this  
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>

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

Share this post


Link to post
Share on other sites

0 answers to this question

Recommended Posts

There have been no answers to this question yet

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

By using this site, you automaticly agree to our Guidelines and Privacy Policy.
We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.

Поддержка