Vlod поделился системой для работы со звуками, я немножко доработал, а если конкретнее - добавил периодическую проверку на расстояние между камерой и звуком
вариковские функции
вариковские функции
native SetSoundDistanceCutoff takes sound soundHandle, real cutoff returns nothing
native SetSoundDistances takes sound soundHandle, real minDist, real maxDist returns nothing
при выходе и входе либо проигрывают заново звук либо прерывают его (в зависимости что вы указали в четвёртом аргументе функции CreateSound)
оригинал
код
library LibSound
struct Sound
sound sound
timer timer
real time
unit u
real x
real y
integer volume
integer tick
boolean is_playing = false
private static hashtable H = InitHashtable() // таблица для звуков, StringHash(string)
private static hashtable H_T = InitHashtable() // таблица для таймеров, GetHandleId(timer)
private static real MIN_DIST = 600 // дистанция где звук 100%
private static real MAX_DIST = 990000 // растягивает звук. чем больше число, тем меньше будет слышно звук на другом конце карты
private static real All_X = 0 // НАСТРОИТЬ All_X All_Y!!!
private static real All_Y = 0 // X, Y, Z координаты точки, которая всегда видна (если нет, то создать)
private static real All_Z = 600+50
private static real All_DIST = 99000 // максимальное расстояние на карте
private static real All_CUTOFF = 0
private static real PTIME = 0.1
// создает и прелоадит новый звук, не использовать!
// для получения свободного звука из буфера используйте Sound.path2sound(string)
static method create takes string path, real time returns thistype
local thistype n = thistype.allocate()
local integer hid = StringHash(path)
local integer count = LoadInteger(H, hid, 0)
set n.sound = CreateSound(path, false, true, false, 10, 10, "")
set n.time = time
set n.timer = CreateTimer()
call SaveInteger(H_T, 0, GetHandleId(n.timer), n)
set count = count + 1
call SaveInteger(H, hid, 0, count)
call SaveInteger(H, hid, count, n)
call SetSoundPitch(n.sound, 1)
call SetSoundDistances(n.sound, MIN_DIST, MAX_DIST)
call SetSoundConeAngles(n.sound, 0.0, 0.0, 127)
call SetSoundConeOrientation(n.sound, 0.0, 0.0, 0.0)
call SetSoundChannel(n.sound, 40)
return n
endmethod
// остановить звук
method stop takes nothing returns integer
if this > 0 and .is_playing then
call PauseTimer(.timer)
set .u = null
set .is_playing = false
call StopSound(.sound, false, false)
endif
return 0
endmethod
private static method sound_off takes nothing returns nothing
local thistype snd = LoadInteger(H_T, 0, GetHandleId(GetExpiredTimer()))
call snd.stop()
endmethod
private static method track takes nothing returns nothing
local thistype snd = LoadInteger(H_T, 0, GetHandleId(GetExpiredTimer()))
//call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "track snd"+I2S(snd))
//call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "track snd.tick"+I2S(snd.tick))
call SetSoundPosition(snd.sound, GetUnitX(snd.u), GetUnitY(snd.u), All_Z)
set snd.tick = snd.tick - 1
if snd.tick <= 0 then
call snd.stop()
endif
endmethod
// получить звук по пути (если нет свободного звука создется новый)
static method path2sound takes string path returns thistype
local integer hid = StringHash(path)
local integer count = LoadInteger(H, hid, 0)
local integer i = 1
local Sound snd
//call DisplayTextToPlayer(Player(0),0,0, "path2sound "+path)
if count <= 0 then
return 0
endif
loop
exitwhen i > count
set snd = LoadInteger(H, hid, i)
if not snd.is_playing then
return snd
endif
set i = i + 1
endloop
set snd = Sound.create(path, thistype(LoadInteger(H, hid, 1)).time)
//call DisplayTextToPlayer(Player(0),0,0, "new snd "+I2S(snd))
return snd
endmethod
private method prepare_for_all takes nothing returns nothing
call SetSoundPosition(.sound, All_X, All_Y, All_Z)
call SetSoundDistanceCutoff(.sound, All_DIST)
//call SetSoundVolume(.sound, 0)
//call SetSoundPitch(.sound, 1)
//call SetSoundDistances(.sound, MinDist, MaxDist)
//call SetSoundConeAngles(.sound, 0.0, 0.0, 127)
//call SetSoundConeOrientation(.sound, 0.0, 0.0, 0.0)
//call SetSoundChannel(.sound,40)
endmethod
// проиграть звук в точке
method xy takes integer volume, real x, real y returns nothing
if this <= 0 then
return
endif
set .volume = volume
set .x = x
set .y = y
call .prepare_for_all()
call StopSound(.sound, false, false)
call StartSound(.sound)
call SetSoundPosition(.sound, x, y, All_Z)
call SetSoundDistanceCutoff(.sound, All_CUTOFF)
call SetSoundVolume(.sound, volume)
set .is_playing = true
if .u == null then
call TimerStart(.timer, .time+PTIME, false, function thistype.sound_off)
else
set .tick = R2I(.time/PTIME) + 1
call TimerStart(.timer, PTIME, true, function thistype.track)
endif
//call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "method xy .time "+R2S(.time))
endmethod
// проиграть звук на юните
method on_unit takes integer volume, unit u returns nothing
local real x = GetUnitX(u)
local real y = GetUnitY(u)
set .u = u
call .xy(volume, x, y)
endmethod
method destroy takes nothing returns nothing
// заглушка, удалять Sound не надо, они кешируются вместе с sound в hashtable
endmethod
// проиграть звук в точке
static method play_xy takes string path, integer volume, real x, real y returns thistype
local thistype snd = path2sound(path)
call snd.xy(volume, x, y)
return snd
endmethod
// проиграть звук на юните
static method play_on_unit takes string path, integer volume, unit u returns thistype
local thistype snd = path2sound(path)
local real x = GetUnitX(u)
local real y = GetUnitY(u)
set snd.u = u
call snd.xy(volume, x, y)
return snd
endmethod
// прелоадит звук в библиотеку. все звуки нужно прелоадить 1 раз.
static method preload takes string path, real time returns nothing
call thistype.create(path, time)
endmethod
endstruct
endlibrary
доработка
код
library SoundLib
globals
private constant hashtable H = InitHashtable( )
private constant real MaxDistance = 9999999.00 // макс дистанція звуку
private constant real VisibleXForAll = 0.00 // видимі координати кожному гравцю у будь-який час гри
private constant real VisibleYForAll = 0.00
private constant location LFZ = Location( 0.00, 0.00 )
endglobals
function GetLocZ takes real x, real y returns real
call MoveLocation( LFZ, x, y )
return GetLocationZ( LFZ )
endfunction
struct Sound
private static hashtable HS = InitHashtable( ) // таблица для звуков, StringHash(string)
private static real PTIME = 0.05
boolean is_playing = false
integer volume
integer tick
sound sound
timer timer
unit u
real x
real y
real z
real time
real minDist
real maxDist
// создает и прелоадит новый звук, не использовать!
// для получения свободного звука из буфера используйте Sound.path2sound(string)
static method create takes string path, real time returns thistype
local thistype n = thistype.allocate( )
local integer hid = StringHash( path )
local integer count = LoadInteger( HS, hid, 0 ) + 1
set n.sound = CreateSound( path, false, true, false, 10, 10, "" )
set n.time = time
set n.timer = CreateTimer( )
call SaveInteger( H, 0, GetHandleId( n.timer ), n )
call SaveInteger( HS, hid, 0, count )
call SaveInteger( HS, hid, count, n )
call SetSoundDistanceCutoff( n.sound, MaxDistance )
call SetSoundDistances( n.sound, MaxDistance, MaxDistance )
call SetSoundConeAngles( n.sound, MaxDistance, MaxDistance, 127 )
return n
endmethod
method destroy takes nothing returns nothing
// заглушка, удалять Sound не надо, они кешируются вместе с sound в hashtable
endmethod
// остановить звук
method stop takes nothing returns integer
if this > 0 and .is_playing then
call PauseTimer( .timer )
call StopSound( .sound, false, false )
set .u = null
set .is_playing = false
endif
return 0
endmethod
static method track takes nothing returns nothing
local thistype snd = LoadInteger( H, 0, GetHandleId( GetExpiredTimer( ) ) )
local real x
local real y
local real z
local real d
if snd.u != null then
if GetUnitTypeId( snd.u ) > 0 then
set x = snd.x
set y = snd.y
set z = snd.z
set snd.x = GetUnitX( snd.u )
set snd.y = GetUnitY( snd.u )
set snd.z = GetLocZ( snd.x, snd.y ) + GetUnitFlyHeight( snd.u )
if x != snd.x or y != snd.y or z != snd.z then
call SetSoundPosition( snd.sound, snd.x, snd.y, snd.z )
endif
else
set snd.u = null
endif
endif
set x = GetCameraTargetPositionX( )
set y = GetCameraTargetPositionY( )
set z = GetCameraTargetPositionZ( )
set d = SquareRoot( ( x - snd.x ) * ( x - snd.x ) + ( y - snd.y ) * ( y - snd.y ) + ( z - snd.z ) * ( z - snd.z ) )
if d > snd.minDist then
if d > snd.maxDist then
call SetSoundVolume( snd.sound, 0 )
else
call SetSoundVolume( snd.sound, R2I( snd.volume * ( 1.00 - ( ( d - snd.minDist ) / ( snd.maxDist - snd.minDist ) ) ) ) )
endif
else
call SetSoundVolume( snd.sound, snd.volume )
endif
set snd.tick = snd.tick - 1
if snd.tick <= 0 then
call snd.stop( )
else
call TimerStart( snd.timer, PTIME, false, function thistype.track )
endif
endmethod
// проиграть звук в точке
method play takes nothing returns nothing
if this <= 0 then
return
endif
call SetSoundPosition( .sound, VisibleXForAll, VisibleYForAll, 0.00 )
call StartSound( .sound )
call SetSoundPosition( .sound, .x, .y, z )
call SetSoundVolume( .sound, .volume )
call SetSoundPitch( .sound, GetRandomReal( 0.98, 1.02 ) )
call SetSoundConeOrientation( .sound, .x, .y, z )
set .is_playing = true
set .tick = R2I( .time / PTIME ) + 1
call TimerStart( .timer, 0.00, false, function thistype.track )
endmethod
// получить звук по пути (если нет свободного звука создется новый)
static method path2sound takes string path returns thistype
local integer hid = StringHash( path )
local integer count = LoadInteger( HS, hid, 0 )
local integer i = 1
local Sound snd
if count <= 0 then
return 0
endif
loop
exitwhen i > count
set snd = LoadInteger( HS, hid, i )
if not snd.is_playing then
return snd
endif
set i = i + 1
endloop
return Sound.create( path, thistype( LoadInteger( HS, hid, 1 ) ).time )
endmethod
// проиграть звук в точке
static method playPoint takes string path, real x, real y, real mind, real maxd, integer vol returns thistype
local thistype snd = path2sound( path )
set snd.x = x
set snd.y = y
set snd.z = GetLocZ( snd.x, snd.y )
set snd.minDist = mind
set snd.maxDist = maxd
set snd.volume = vol
call snd.play( )
return snd
endmethod
// проиграть звук на юните
static method playUnit takes string path, unit u, real mind, real maxd, integer vol returns thistype
local thistype snd = path2sound( path )
set snd.u = u
set snd.x = GetUnitX( u )
set snd.y = GetUnitY( u )
set snd.z = GetLocZ( snd.x, snd.y ) + GetUnitFlyHeight( u )
set snd.minDist = mind
set snd.maxDist = maxd
set snd.volume = vol
call snd.play( )
return snd
endmethod
// прелоадит звук в библиотеку. все звуки нужно прелоадить 1 раз.
static method preload takes string path, real time returns nothing
call thistype.create( path, time )
endmethod
endstruct
endlibrary
rsfghd, Причем тут это? Путь к звуку уникальный да, но может же быть несколько звуков с одним путем?
SetSoundParamsFromLabel(Sound, "ChatroomTimerTick");
SetSoundDuration(Sound, 476);
SetSoundChannel(Sound, 11);
SetSoundVolume(Sound, 150);
SetSoundPitch(Sound, 1.0);
SetSoundDistances(Sound, 750.0, 100000.0);
SetSoundDistanceCutoff(Sound, 2000.0);