Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
vJass
Тип:
Наработка
Версия Warcraft:
1.26
Пример того как можно использовать тип Directional у источника света вне DNC моделей.
Можно заметить что каждый раз свет падает под разными углами.
Суть в том чтобы использовать модель dummy.mdx со 180 анимациями и крепить к ней эффектом модель с источником света. Таким образом можно управлять направлением света молнии с помощью поворота юнита и сменой его анимации.
устройство модели с источником света
Version {
	FormatVersion 800,
}
Model "L_1.2" {
	BlendTime 0,
	BoundsRadius 1.0E9,
}
Sequences 2 {
	Anim "Stand" {
		Interval { 1000, 1100 },
		BoundsRadius 1.0E9,
	}
	Anim "Death" {
		Interval { 10000, 10100 },
		NonLooping,
		BoundsRadius 1.0E9,
	}
}
GlobalSequences 1 {
	Duration 0,
}
Light "Lightning" {
	ObjectId 0,
	Directional,
	static AttenuationStart 0.0,
	static AttenuationEnd 0.0,
	static Intensity 1.2,
	static Color { 1.0, 0.7529412, 0.5019608 },
	static AmbIntensity 0.0,
	static AmbColor { 0.0, 0.0, 0.0 },
	Visibility 2 {
		DontInterp,
		1000: 1.0,
		10000: 0.0,
	}
	Rotation 1 {
		DontInterp,
		GlobalSeqId 0,
		0: { 0.707107, 0.0, -0.707107, 0.0 },
	}
}
PivotPoints 1 {
	{ 0.0, 0.0, 0.0 },
}

На каждый вариант интенсивности и цвета света нужно делать отдельную модель.
  • Intensity - Означает яркость вспышки света (в данном примере 1.2).
  • Color - Означает цвет вспышки света (в данном примере светло-голубой).
Так же есть возможность смены цвета тумана под цвет молнии.
Если используете динамический туман, можете динамически менять соответствующие значения в глобалках чтобы оно автоматом подстраивалось.
Для отображения света нужно чтобы в момент создания и удаления эффекта на даммике он был в позиции цели камеры игрока. Так что в эти моменты дамми перемещается в GetCameraTargetPosition, это не вызывает десинха само по себе.
Однако свет изредка багуется если быстро дергать камеру, тогда свет пропадает только через 5 сек (дефолт значение в константах), пока думаю как решить эту проблему. Есть идеи у кого?
Вроде стало норм когда у модели dummy.mdx установил Bounds Radius большой и время смерти дамика увеличил (мб не успевала проиграться анимация смерти эффекта).
Звук пока не проигрывается с первого раза, нужно бы заюзать прелоад для этого, но у меня почему-то никак это не получалось - звук все равно не проигрывался. Еще конечно неплохо было бы заюзать какой-нибудь ресайклер для звуков, но то уже такое.
В карте - примере присутствуют:
3 модели источника света светло-голубого цвета разной интенсивности.
3 звука грома и фоновый звук дождя которые были скомунизжены отсюда.
Сама мапа взята отсюда.
код
library Storm initializer Init
    
    // Storm v1.2
    // by OVOgenez

    globals
        private constant integer DUMMY_ID  = 'h000'     // Unit unit ID
        public  constant integer VAR_COUNT = 3          // Number of storm variations
        
        private string array LightningPath              // Path to lightning models
        private string array ThunderPath                // Path to thunder sounds
        
        private real   array L_intensity                // Light sources intensity
        private real   array L_red                      // Red color of light sources
        private real   array L_green                    // Green color of light sources
        private real   array L_blue                     // Blue color of light sources
        
        //------------------------------------------
        // These values can be dynamically changed if dynamic fog is used.
        //
        public boolean TF         = true                // Whether fog is used
        public integer TF_style   = 0                   // Fog style
        public real    TF_zstart  = 1000.0              // Fog start Z value
        public real    TF_zend    = 3000.0              // Fog end Z value
        public real    TF_density = 0.0                 // Fog density
        public real    TF_red     = 0.0                 // Red color of fog
        public real    TF_green   = 0.0                 // Green color of fog
        public real    TF_blue    = 0.0                 // Blue color of fog
        //------------------------------------------
    endglobals
    
    //==========================================
    // Initialization of array values. NOT related to the number of variations (VAR_COUNT).
    // 
    private function Init takes nothing returns nothing
        set LightningPath[1] = "L1.mdx"
        set LightningPath[2] = "L2.mdx"
        set LightningPath[3] = "L3.mdx"
        set ThunderPath[1]   = "T1.wav"
        set ThunderPath[2]   = "T2.wav"
        set ThunderPath[3]   = "T3.wav"
        
        set L_intensity[1] = 0.4
        set L_intensity[2] = 0.8
        set L_intensity[3] = 1.2
        set L_red[1]       = 0.5
        set L_red[2]       = 0.5
        set L_red[3]       = 0.5
        set L_green[1]     = 0.75
        set L_green[2]     = 0.75
        set L_green[3]     = 0.75
        set L_blue[1]      = 1.0
        set L_blue[2]      = 1.0
        set L_blue[3]      = 1.0
    endfunction
    
    private module Settings
        static constant real PERIOD = 0.03125  // Timer period
        
        //------------------------------------------
        // These values can be used in the methods below to determine the result.
        //
        readonly integer Variant     // Storm variation            (from 1 to VAR_COUNT)
        readonly integer Count       // Number of light flashes    (from 1 to ...)
        readonly integer Current     // Current light flash        (from 1 to Count; 0 when delay before thunder)
        readonly integer Azimuth     // Horizontal light angle     (from -180 to 180)
        readonly integer Zenith      // Vertical light angle       (from -90 to 90)
        readonly integer LIndex      // Current lightning model index for LightningPath array
        readonly integer TIndex      // Current thunder sound index for ThunderPath array
        //------------------------------------------
        
        //==========================================
        // Return the lightning model index for LightningPath array.
        //
        method operator GetLightningIndex takes nothing returns integer
            return .Variant
        endmethod
        
        //==========================================
        // Return the thunder sound index for ThunderPath array.
        //
        method operator GetThunderIndex takes nothing returns integer
            return .Variant
        endmethod
        
        //==========================================
        // Return the duration of lightning flash.
        //
        method operator GetPlayDuration takes nothing returns real
            return GetRandomInt(2, 4)*PERIOD
        endmethod
        
        //==========================================
        // Return the duration between lightning flashes.
        //
        method operator GetStopDuration takes nothing returns real
            return GetRandomInt(1, 3)*PERIOD
        endmethod
        
        //==========================================
        // Return the delay before thunder sound.
        //
        method operator GetSoundDelay takes nothing returns real
            return (10*(VAR_COUNT*VAR_COUNT - .Variant*.Variant) + GetRandomInt(0, 10))*PERIOD
        endmethod
        
        //==========================================
        // Return the volume of thunder sound.
        //
        method operator GetSoundVolume takes nothing returns integer
            return GetRandomInt(R2I(127*0.8), 127)
        endmethod
        
        //==========================================
        // Return the pitch of thunder sound.
        //
        method operator GetSoundPitch takes nothing returns real
            return GetRandomReal(0.9, 1.1)
        endmethod
    endmodule
    
    //==================================================================================================================
    
    private module Array
        private static thistype array ARRAY
        private static integer SIZE = 0
        private integer INDEX = 0
        
        static method operator size takes nothing returns integer
            return SIZE
        endmethod
        static method operator [] takes integer i returns thistype
            return ARRAY[i]
        endmethod
        
        method remove takes nothing returns nothing
            if INDEX != 0 then
                set ARRAY[SIZE].INDEX = INDEX
                set ARRAY[INDEX] = ARRAY[SIZE]
                set ARRAY[SIZE] = 0
                set INDEX = 0
                set SIZE = SIZE - 1
            endif
        endmethod
        
        method add takes nothing returns nothing
            if INDEX == 0 then
                set SIZE = SIZE + 1
                set INDEX = SIZE
                set ARRAY[SIZE] = this
            endif
        endmethod
    endmodule
    
    private struct TStorm
        implement Array
        implement Settings
        
        private static boolean TempTF         = TF
        private static integer TempTF_style   = TF_style
        private static real    TempTF_zstart  = TF_zstart
        private static real    TempTF_zend    = TF_zend
        private static real    TempTF_density = TF_density
        private static real    TempTF_red     = TF_red
        private static real    TempTF_green   = TF_green
        private static real    TempTF_blue    = TF_blue
        
        private static timer Timer = CreateTimer()
        
        private unit    Unit
        private effect  Effect
        private real    Time
        private boolean Mode
        private boolean Local
        
        private method toCamera takes nothing returns nothing
            call SetUnitX(.Unit, GetCameraTargetPositionX())
            call SetUnitY(.Unit, GetCameraTargetPositionY())
        endmethod
        
        method destroy takes nothing returns nothing
            call this.remove()
            // ====================
            call .toCamera()
            call DestroyEffect(.Effect)
            call KillUnit(.Unit)
            set .Effect = null
            set .Unit = null
            // ====================
            call this.deallocate()
        endmethod
        
        private method Function takes nothing returns nothing
            local sound s
            call .toCamera()
            set .Time = .Time - PERIOD
            if .Time <= 0 then
                if .Current > 0 and .Current <= .Count then
                    if not .Mode then
                        set .Mode = true
                        set .Time = .GetPlayDuration
                        set .LIndex = .GetLightningIndex
                        if .Local then
                            set .Effect = AddSpecialEffectTarget(LightningPath[.LIndex], .Unit, "origin")
                        else
                            set .Effect = AddSpecialEffectTarget("", .Unit, "origin")
                        endif
                    else
                        set .Mode = false
                        set .Time = .GetStopDuration
                        set .Current = .Current + 1
                        if .Current > .Count then
                            set .Current = 0
                            set .Time = .GetSoundDelay
                        endif
                        call DestroyEffect(.Effect)
                        set .Effect = null
                    endif
                elseif .Current == 0 then
                    set .TIndex = .GetThunderIndex
                    if .Local then
                        set s = CreateSound(ThunderPath[.TIndex], false, false, false, 10, 10, "DoodadsEAX")
                        call SetSoundChannel(s, 10)
                    else
                        set s = CreateSound("", false, false, false, 10, 10, "")
                        call SetSoundChannel(s, -1)
                    endif
                    call SetSoundVolume(s, .GetSoundVolume)
                    call SetSoundPitch(s, .GetSoundPitch)
                    call StartSound(s)
                    call KillSoundWhenDone(s)
                    set s = null
                    call this.destroy()
                endif
            endif
        endmethod
        
        private static method Periodic takes nothing returns nothing
            local real r = TF_red
            local real g = TF_green
            local real b = TF_blue
            local integer i = thistype.size
            loop
                exitwhen i <= 0
                call thistype[i].Function()
                if TF and thistype[i] > 0 and thistype[i].Current > 0 and thistype[i].Mode and thistype[i].Local then
                    set r = RMinBJ(1, r + L_red[thistype[i].LIndex]*L_intensity[thistype[i].LIndex])
                    set g = RMinBJ(1, g + L_green[thistype[i].LIndex]*L_intensity[thistype[i].LIndex])
                    set b = RMinBJ(1, b + L_blue[thistype[i].LIndex]*L_intensity[thistype[i].LIndex])
                endif
                set i = i - 1
            endloop
            if TF then
                if TempTF         != TF         or /*
                */ TempTF_style   != TF_style   or /*
                */ TempTF_zstart  != TF_zstart  or /*
                */ TempTF_zend    != TF_zend    or /*
                */ TempTF_density != TF_density or /*
                */ TempTF_red     != r          or /*
                */ TempTF_green   != g          or /*
                */ TempTF_blue    != b          then
                    set TempTF_style   = TF_style
                    set TempTF_zstart  = TF_zstart
                    set TempTF_zend    = TF_zend
                    set TempTF_density = TF_density
                    set TempTF_red     = r
                    set TempTF_green   = g
                    set TempTF_blue    = b
                    call SetTerrainFogEx(TF_style, TF_zstart, TF_zend, TF_density, r, g, b)
                endif
            elseif TempTF != TF then
                call ResetTerrainFog()
            endif
            set TempTF = TF
        endmethod
        
        static method create takes integer variant, integer count, integer azimuth, integer zenith, boolean localplayer returns thistype
            local thistype this = thistype.allocate()
            // ====================
            set .Variant = variant
            set .Count = count
            set .Current = 1
            set .Azimuth = azimuth
            set .Zenith = zenith
            set .Local = localplayer
            set .Time = 0
            set .Mode = false
            set .Unit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, 0, 0, azimuth)
            call SetUnitAnimationByIndex(.Unit, zenith + 90)
            // ====================
            call this.add()
            return this
        endmethod
        
        private static method onInit takes nothing returns nothing
            call TimerStart(Timer, PERIOD, true, function thistype.Periodic)
        endmethod
    endstruct
    
    //==================================================================================================================
    
    //==========================================
    // Imitate storm with local player:
    //   variant     - Storm variation           (from 1 to VAR_COUNT)
    //   count       - Number of light flashes   (from 1 to ...)
    //   azimuth     - Horizontal light angle    (from -180 to 180)
    //   zenith      - Vertical light angle      (from -90 to 90)
    //   localplayer - Logical expression
    //
    public function ImitateLocal takes integer variant, integer count, integer azimuth, integer zenith, boolean localplayer returns nothing
        if variant > 0 and variant <= VAR_COUNT and count > 0 then
            call TStorm.create(variant, count, azimuth, zenith, localplayer)
        endif
    endfunction
    
    //==========================================
    // Imitate randomized storm with local player:
    //   variant     - Storm variation           (from 1 to VAR_COUNT)
    //   localplayer - Logical expression
    //
    public function ImitateRandomLocal takes integer variant, boolean localplayer returns nothing
        call ImitateLocal(variant, GetRandomInt(2, 4), GetRandomInt(-180, 180), GetRandomInt(-90, -30), localplayer)
    endfunction
    
    //==========================================
    // Imitate storm:
    //   variant - Storm variation           (from 1 to VAR_COUNT)
    //   count   - Number of light flashes   (from 1 to ...)
    //   azimuth - Horizontal light angle    (from -180 to 180)
    //   zenith  - Vertical light angle      (from -90 to 90)
    //
    public function Imitate takes integer variant, integer count, integer azimuth, integer zenith returns nothing
        call ImitateLocal(variant, count, azimuth, zenith, true)
    endfunction
    
    //==========================================
    // Imitate randomized storm:
    //   variant - Storm variation           (from 1 to VAR_COUNT)
    //
    public function ImitateRandom takes integer variant returns nothing
        call ImitateRandomLocal(variant, true)
    endfunction

endlibrary
`
ОЖИДАНИЕ РЕКЛАМЫ...
21
Интересная концепция. Пожалуй, поюзаю)
Только у настоящих гроз, как правило, цвет почти белый, и не сильно много углов света и яркостей.
Потому не проще ли сделать 1 модельку на 10 анимаций stand, с разной случайностью, запихнуть туда источник света, прикрутить его к кости и задать кости повороты, а у самого источника заанимировать яркость и видимость, чтоб были разные вспышки?
К самой модели можно также молнию сделать и событийные объекты звуков грома, тоже разные.
А триггером по периоду создавать спецэффект в х у камеры и удалять его. Код всего из нескольких строк получится )
Ответы (13)
16
EugeAl, можно и так, но изначально хотелось больше контроля из кода.
Саму модель молнии делать не считал нужным, т.к. цель в другом состояла. Но если делать какую-нибудь мапу от 1 лица то можно понаделать всяких отдельных эффектов молний чтобы на фоне скайбокса смотрелось.
21
OVOgenez, ну да, круто смотрится. Ок, понял.
А что за карта на скрине? Где скачать?)
21
OVOgenez, шикарный, жуткий синематик. Офигенно)
Но я так понял, его не скачать как карту...
21
OVOgenez, в общем попробовал сделать подобное.
Есть баги событийников звука - если есть директионал свет - звук не работает. Пришлось делать отдельную модельку чисто со звуками, тогда заработало.
Второй баг, самый плохой - если камеру двигаешь постоянно, свет остаётся на несколько секунд. Ужасный баг, всё портит. Это видимо не лечится, из за чего и пришлось отказаться от концепции.
21
OVOgenez, не, мне лень стало качать, я из своих эффектов делал.
Скачал, попробую с твоим.
16
EugeAl, а событийники звука зачем тут вообще? Я сам их не чекал даже будет ли работать, звук то из кода создается.
21
OVOgenez, они нужны, чтоб с кодом звуков не возиться
Только их в бд звуков добавлять придется
16
EugeAl, насколько мне известно slk табличка вот этих звуков подгружается во время загрузки варика, поэтому просто импортнуть ее не получится. А стандартный набор скуден и содержит 1-2 звука грома, такое себе крч.
21
OVOgenez, а, ну тогда не годно. Я то думал все таблицы во время загрузки карты грузятся
25
Не обезательно спавнить даммика, есть функция смены глобального освещения SetDayNightModels(,)
Можно просто заменять ее на время вспышки.
Ответы (1)
16
Jack-of-shadow, это если DNC не используется, может же быть не полный мрак. Плюс ты с этой функцией к моделе не достучишься, а значит и повернуть источник в коде не сможешь. Ну и то что DNC одна а дамиков можно наспамить несколько (типо несколько одновременных вспышек).
0
Одна из немногих работ, которую не стыдно похвалить и оценить в принципе. Очень рад, что такие Авторы еще остаются на плаву и не позволяют упасть нашему обществу Картоделов, только благодаря которому, еще держится в целом Варкрафт как игра спустя столько лет.
Спасибо)
Даже не знаю какие минусы тут особо подобрать, ну разве что, соглашусь с комментарием выше, про цвет, но это не супер критично все же.
Надеюсь, что увидим в будущем какие-нибудь еще работы, подобного плана.🐸
16
Вышла новая версия! Прокрутить к ресурсу
Обновил, добавил возможность работы для локального игрока.
16
Думал на счет TerrainFog, мб при вспышке молнии не только окрашивать туман в цвет света, а еще и умножать его ZSTART и ZEND на (1 + интенсивность света), чтобы увеличивать дальность прорисовки у игрока в этот момент. Крч можно пошаманить с этим.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.