Добавлен , опубликован
Способ реализации:
Версия Warcraft:

Система стрельбы

Демонстрация

С помощью WASD передвигайте персонажа. С помощью ЛКМ производите срельбу. С помощью ПКМ прицеливаетесь. С помощью ножа режете

Мультиплеер

+ Мультиплеерное
+ Количество урона, скорости передвижения, скорости полёта снаряда, дистанция полёта снаряда и скорострельность настраиваются в редакторе объектов
+ Динамическая камера
+ Учитывается высота противников для стрельбы, на которых направлена мышка
+ Отсутствие движения мышки учитывается при ходьбе
+ Прицеливание уменьшает разброс пуль
- Не изменяется положение туловища и ног по Pitch'y

Предыстория

Я редко встречаю карты с системами стрельбы через мышку и на WASD'e, тем более мультиплеерные и тем более на ванилле (я и не ищу их, я ищу счастье, гармонию от слияния с бесконечно вечным)
Референс для этой наработки взят из Морозко против Зла, где подобное было выполнено горекриво на мемхаке и с отсутствием мультиплеера. Систему можно самостоятельно очень сильно развить, добавив на тот же пробел кувырок/рывок/телепорт/прыжок/джетпак персонажа, на ПКМ атаку ближнего боя, на Q/E смену оружия, которое можно самостоятельно сделать абсолютно различными вариациями, ну и так далее. Я не делал ориентацию туловища/ног для этой наработки, поскольку есть 2 варианта это сделать:
  1. SetUnitLookAt - старый, рабочий костыль, требующий даммика в позиции курсора.
  2. UnitEnableAutoOrientation + SetUnitOrientation - нативки UjAPI, требует сглаживания. Варкрафтовское изменение ориентации работать больше не будет, GetUnitFacing нужно заменять на GetUnitYaw.

Инструкция по импорту

  • Работает исключительно на UjAPI, поэтому вам необходимо установить лаунчер

Скопировать папку Initialization и закинуть в свою карту вместе со всем импортом
Триггер Sound нужен для позиционированных звуков стрельбы и взят с уже существующей наработки 3д звук
В триггере ShooterSystem указать на 324/325 строках равкод туловища/ног персонажа, на строке 258 указать радиус пули, на строках 247-253 указать разброс пуль при свободной стрельбе и прицеливании, на строках 178, 179 и 214 указать во втором аргументе функции индекс анимации ходьбы. Всё остальное требует минимальных знаний джасса
если что-то не понятно - комменты

Код

У меня нет настроения расписывать какое это говно, так что просто представьте, что не представьте, первый раз космос погибнет в уме - второй раз в сердце, мир это лишь твой проектор вне, спасибо за непонимание
AllGlobals
library AllGlobalsLib initializer OnInit
globals
    constant hashtable H = InitHashtable( )
    
    unit array PlayerUnitUnderCursor
    real array PlayerMouseWorldX
    real array PlayerMouseWorldY
    real array PlayerMouseWorldZ
    real array PlayerMouseWorldXLast
    real array PlayerMouseWorldYLast
    
    real MaxX
    real MinX
    real MaxY
    real MinY
endglobals

function AngleDifference takes real a, real a1 returns real
	set a = RAbsBJ( a - a1 )
	
	if a > 180.00 then
		set a = 360.00 - a
	endif

	return a
endfunction

function SetUnitPositionSmooth takes unit source, real x, real y returns nothing
    local real last_x = GetUnitX(source)
    local real last_y = GetUnitY(source)
    local boolean bx
    local boolean by

    call SetUnitPosition(source, x, y)

    if (RAbsBJ(GetUnitX(source) - x) > 0.5) or (RAbsBJ(GetUnitY(source) - y) > 0.5) then
        
        call SetUnitPosition(source, x, last_y)
        set bx = RAbsBJ(GetUnitX(source) - x) <= 0.5
        call SetUnitPosition(source, last_x, y)
        set by = RAbsBJ(GetUnitY(source) - y) <= 0.5
        
        if bx then
            call SetUnitPosition(source, x, last_y)
        elseif by then
            call SetUnitPosition(source, last_x, y)
        else
            call SetUnitPosition(source, last_x, last_y)
        endif

    endif
endfunction

function SetUnitPositionEX takes unit u, real x, real y returns nothing
    if x > MaxX then
        set x = MaxX
    elseif x < MinX then
        set x = MinX
    endif
    
    if y > MaxY then
        set y = MaxY
    elseif y < MinY then
        set y = MinY
    endif
    
    call SetUnitX( u, x )
    call SetUnitY( u, y )
endfunction

function CreateUnitEx takes player id, integer unitid, real x, real y, real face returns unit
    set bj_lastCreatedUnit = CreateUnit( id, unitid, x, y, face )
    
    call SetUnitPositionEX( bj_lastCreatedUnit, x, y )
    
    return bj_lastCreatedUnit
endfunction

function TrackUnitUnderCursor takes nothing returns nothing
    set PlayerUnitUnderCursor[ GetPlayerId( GetTriggerPlayer( ) ) ] = GetTriggerUnit( )
endfunction

function TrackMouseWorldXYZ takes nothing returns nothing
    local integer i = GetPlayerId( GetTriggerPlayer( ) )
    
    set PlayerMouseWorldX[i] = GetTriggerPlayerMouseWorldX( )
    set PlayerMouseWorldY[i] = GetTriggerPlayerMouseWorldY( )
    set PlayerMouseWorldZ[i] = GetTriggerPlayerMouseWorldZ( )
endfunction

private function OnInit takes nothing returns nothing
    local trigger trg = CreateTrigger( )
    local trigger ttg = CreateTrigger( )
    local integer i = 0
    local rect r = GetWorldBounds( )
    
    call SetMouseMoveEventWorldAxisEnabled( true )
    call SetMouseMoveEventScreenAxisEnabled( false )
    
    loop
        call TriggerRegisterPlayerEvent( trg, Player( i ), EVENT_PLAYER_MOUSE_MOVE )
        call TriggerRegisterPlayerEvent( ttg, Player( i ), EVENT_PLAYER_WIDGET_TRACK )
        
        set i = i + 1
        exitwhen i >= bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddAction( trg, function TrackMouseWorldXYZ )
    call TriggerAddAction( ttg, function TrackUnitUnderCursor )
    
    set MaxX = GetRectMaxX( r )
    set MinX = GetRectMinX( r )
    set MaxY = GetRectMaxY( r )
    set MinY = GetRectMinY( r )
    
    call RemoveRect( r )
    
    set r = null
    set trg = null
    set ttg = null
endfunction
endlibrary

//===========================================================================
//function InitTrig_AllGlobals takes nothing returns nothing
    //set gg_trg_AllGlobals = CreateTrigger(  )
//endfunction

ShooterSystem
library ShooterSystem initializer OnInit requires SoundLib
globals
    private constant timer CameraMotionTimer = CreateTimer( )
    private constant real TimerPeriodic = 0.02125
    private constant group TempGroup = CreateGroup( )
    
    private timer array TempTimer
    
    private boolean array BUTTON_PRESSED[195][12]
    private boolean array IsMoved
    
    private string array BulletModel
    
    private real array ReloadTime
    
    unit array CharacterBody
    unit array CharacterLegs
endglobals

private struct vector
    real x
    real y
    real z
    
    method length takes nothing returns real
        return SquareRoot( x * x + y * y + z * z )
    endmethod
    
    method normalize takes nothing returns nothing
        local real l = length( )
        
        if l == 0.00 then
            set l = 1.00
        endif
        
        set x = x / l
        set y = y / l
        set z = z / l
    endmethod
    
    static method create takes real x, real y, real z returns thistype
        local thistype this = thistype.allocate( )
        
        set this.x = x
        set this.y = y
        set this.z = z
        
        return this
    endmethod
endstruct

private struct bulletS
    vector v
    vector p
    
    real speed
    real damage
    real radius
    real distance
    effect bullet
    player pl
    timer t
    
    method Destroy takes nothing returns nothing
        call PauseTimer( t )
        call FlushChildHashtable( H, GetHandleId( t ) )
        call DestroyTimer( t )
            
        call DestroyEffect( bullet )
        
        set t = null
        set bullet = null
        
        call p.destroy( )
        call v.destroy( )
        call destroy( )
    endmethod
    
    static method move takes nothing returns nothing
        local thistype this = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
        local unit u
        
        if this.distance < this.speed then
            set this.speed = this.distance
        endif
        
        set this.p.x = this.p.x + this.speed * this.v.x
        set this.p.y = this.p.y + this.speed * this.v.y
        set this.p.z = this.p.z + this.speed * this.v.z
        set this.distance = this.distance - this.speed
        
        call SetSpecialEffectPositionWithZ( this.bullet, this.p.x, this.p.y, this.p.z )
        
        call GroupEnumUnitsInRange( TempGroup, this.p.x, this.p.y, this.radius + 200.00, null )
        
        loop
            set u = FirstOfGroup( TempGroup )
            exitwhen u == null
            call GroupRemoveUnit( TempGroup, u )
            
            if IsUnitInRangeXY( u, this.p.x, this.p.y, this.radius ) then
                if IsUnitAlive( u ) and IsUnitEnemy( u, this.pl ) then
                    if RAbsBJ( GetUnitZ( u ) - this.p.z ) <= this.radius + GetUnitRealField( u, UNIT_RF_COLLISION_SIZE ) * 2.00 then
                        call UnitDamageTarget( CharacterBody[ GetPlayerId( this.pl ) ], u, this.damage, false, false, null, null, null )
                        
                        call GroupClear( TempGroup )
                        set this.distance = 0.00
                    endif
                endif
            endif
        endloop
        
        if this.distance <= 0.00 or this.p.z <= GetAxisZ( this.p.x, this.p.y ) then
            call this.Destroy( )
        endif
    endmethod
    
    method launch takes nothing returns nothing
        set t = CreateTimer( )
        
        call SaveInteger( H, GetHandleId( t ), 0, this )
        call TimerStart( t, TimerPeriodic, true, function thistype.move )
    endmethod
endstruct

private function CheckMoves takes nothing returns nothing
    local integer i = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local integer j = 0
    local real a = 0.00
    local real s = 0.00
    local real k
    local real d
    local bulletS A
    
    if BUTTON_PRESSED[ GetHandleId( OSKEY_W ) ][i] then
        set a = a + 90.00
        set j = j + 1
    elseif BUTTON_PRESSED[ GetHandleId( OSKEY_S ) ][i] then
        set a = a + 270.00
        set j = j + 1
    endif
    
    if BUTTON_PRESSED[ GetHandleId( OSKEY_A ) ][i] then
        set a = a + 180.00
        set j = j + 1
    elseif BUTTON_PRESSED[ GetHandleId( OSKEY_D ) ][i] then
        set a = a + 360.00
        if a == 450.00 then
            set a = a - 360.00
        endif
        set j = j + 1
    endif
    
    if j != 0 then
        set a = a / j
        set s = GetUnitMoveSpeed( CharacterBody[i] ) * 0.01
        set d = GetUnitFacing( CharacterBody[i] )
        set k = AngleDifference( a, d )
        
        if k >= 95.00 then
            if k >= 135.00 then
                set s = s * 0.85
            else
                set s = s * 0.75
            endif
            
            call SetUnitTimeScale( CharacterBody[i], -1.00 )
            call SetUnitTimeScale( CharacterLegs[i], -1.00 )
            call SetUnitFacingInstant( CharacterLegs[i], d )
        else
            call SetUnitTimeScale( CharacterBody[i], 1.00 )
            call SetUnitTimeScale( CharacterLegs[i], 1.00 )
            call SetUnitFacing( CharacterLegs[i], a )
        endif 
        
        call SetUnitPositionSmooth( CharacterBody[i], GetUnitX( CharacterBody[i] ) + s * MathCosDeg( a ), GetUnitY( CharacterBody[i] ) + s * MathSinDeg( a ) )
        call SetUnitX( CharacterLegs[i], GetUnitX( CharacterBody[i] ) )
        call SetUnitY( CharacterLegs[i], GetUnitY( CharacterBody[i] ) )
        
        if not IsMoved[i] then
            set IsMoved[i] = true
            call SetUnitAnimationByIndex( CharacterBody[i], 7 )
            call SetUnitAnimationByIndex( CharacterLegs[i], 7 )
        endif
    else
        call SetUnitFacing( CharacterLegs[i], GetUnitFacing( CharacterBody[i] ) )
        
        if IsMoved[i] then
            set IsMoved[i] = false
            
            call SetUnitTimeScale( CharacterBody[i], 1.00 )
            call SetUnitTimeScale( CharacterLegs[i], 1.00 )
            call SetUnitAnimation( CharacterBody[i], "stand" )
            call SetUnitAnimation( CharacterLegs[i], "stand" )
        endif
    endif
    
    if PlayerMouseWorldXLast[i] == PlayerMouseWorldX[i] then
        set PlayerMouseWorldX[i] = PlayerMouseWorldX[i] + s * MathCosDeg( a )
    endif
    
    if PlayerMouseWorldYLast[i] == PlayerMouseWorldY[i] then
        set PlayerMouseWorldY[i] = PlayerMouseWorldY[i] + s * MathSinDeg( a )
    endif
    
    set PlayerMouseWorldXLast[i] = PlayerMouseWorldX[i]
    set PlayerMouseWorldYLast[i] = PlayerMouseWorldY[i]
    
    if ReloadTime[i] > 0.00 then
        set ReloadTime[i] = ReloadTime[i] - 0.01
    elseif BUTTON_PRESSED[ GetHandleId( OSKEY_LBUTTON ) ][i] then
        set ReloadTime[i] = GetUnitWeaponRealField( CharacterBody[i], UNIT_WEAPON_RF_ATTACK_BASE_COOLDOWN, 0 )
        
        call SetUnitAnimation( CharacterBody[i], "attack" )
        call QueueUnitAnimation( CharacterBody[i], "ready" )
        
        if IsMoved[i] then
            call QueueWidgetAnimationByIndex( CharacterBody[i], 7 )
        else
            call QueueUnitAnimation( CharacterBody[i], "stand" )
        endif
        
        set A = bulletS.create( )
        
        set A.p = vector.create( GetUnitX( CharacterBody[i] ), GetUnitY( CharacterBody[i] ), GetUnitZ( CharacterBody[i] ) + 60.00 )
        
        if PlayerUnitUnderCursor[i] != null and PlayerUnitUnderCursor[i] != CharacterBody[i] then
            if GetUnitZ( PlayerUnitUnderCursor[i] ) - 60.00 > GetUnitZ( CharacterBody[i] ) then
                set A.v = vector.create( GetUnitX( PlayerUnitUnderCursor[i] ) - A.p.x, GetUnitY( PlayerUnitUnderCursor[i] ) - A.p.y, GetUnitZ( PlayerUnitUnderCursor[i] ) - A.p.z )
            else
                set A.v = vector.create( GetUnitX( PlayerUnitUnderCursor[i] ) - A.p.x, GetUnitY( PlayerUnitUnderCursor[i] ) - A.p.y, GetUnitZ( PlayerUnitUnderCursor[i] ) + 60.00 - A.p.z )
            endif
        else
            set A.v = vector.create( PlayerMouseWorldX[i] - A.p.x, PlayerMouseWorldY[i] - A.p.y, PlayerMouseWorldZ[i] + 60.00 - A.p.z )
        endif
        
        set A.pl = Player( i )
        set A.bullet = AddSpecialEffect( BulletModel[ GetRandomInt( 0, 5 ) ], A.p.x, A.p.y )
        
        call SetSpecialEffectZ( A.bullet, A.p.z )
        call SetSpecialEffectOrientation( A.bullet, Atan2( A.v.y, A.v.x ) * bj_RADTODEG, Atan2( A.v.z, A.v.length( ) ) * bj_RADTODEG, 0.00 )
        
        set bj_lastCreatedEffect = AddSpecialEffect( "confetti_up_small.mdx", A.p.x, A.p.y )
        call SetSpecialEffectZ( bj_lastCreatedEffect, A.p.z )
        call SetSpecialEffectOrientation( bj_lastCreatedEffect, GetSpecialEffectYaw( A.bullet ), GetSpecialEffectPitch( A.bullet ) - 80.00, 0.00 )
        call DestroyEffect( bj_lastCreatedEffect )
        
        call A.v.normalize( )
        
        if BUTTON_PRESSED[ GetHandleId( OSKEY_RBUTTON ) ][i] then
            set A.v.x = A.v.x + GetRandomReal( -0.04, 0.04 )
            set A.v.y = A.v.y + GetRandomReal( -0.04, 0.04 )
            set A.v.z = A.v.z + GetRandomReal( -0.01, 0.01 )
        else
            set A.v.x = A.v.x + GetRandomReal( -0.08, 0.08 )
            set A.v.y = A.v.y + GetRandomReal( -0.08, 0.08 )
            set A.v.z = A.v.z + GetRandomReal( -0.03, 0.03 )
        endif
        
        set A.speed = GetUnitWeaponRealField( CharacterBody[i], UNIT_WEAPON_RF_ATTACK_PROJECTILE_SPEED, 0 ) * TimerPeriodic
        set A.damage = GetRandomInt( GetUnitWeaponIntegerField( CharacterBody[i], UNIT_WEAPON_IF_ATTACK_DAMAGE_BASE_MINIMUM, 0 ), GetUnitWeaponIntegerField( CharacterBody[i], UNIT_WEAPON_IF_ATTACK_DAMAGE_BASE_MAXIMUM, 0 ) ) + GetUnitWeaponIntegerField( CharacterBody[i], UNIT_WEAPON_IF_ATTACK_DAMAGE_BONUS, 0 )
        set A.radius = 32.00
        set A.distance = GetUnitWeaponRealField( CharacterBody[i], UNIT_WEAPON_RF_ATTACK_RANGE, 0 )
        
        call Sound.playPoint( "groza_shoot" + I2S( GetRandomInt( 0, 1 ) ) + ".wav", A.p.x, A.p.y, 600.00, 3000.00, GetRandomInt( 60, 80 ) )
        call Sound.playPoint( "sleigh bells" + I2S( GetRandomInt( 0, 3 ) ) + ".wav", A.p.x, A.p.y, 600.00, 3000.00, GetRandomInt( 60, 80 ) )
        
        call A.launch( )
    endif
    
    call SetUnitFacing( CharacterBody[i], MathAngleBetweenPoints( GetUnitX( CharacterBody[i] ), GetUnitY( CharacterBody[i] ), PlayerMouseWorldX[i], PlayerMouseWorldY[i] ) )
endfunction

private function CharacterMove takes nothing returns nothing
    set BUTTON_PRESSED[ GetHandleId( GetTriggerPlayerKey( ) ) ][ GetPlayerId( GetTriggerPlayer( ) ) ] = GetTriggerPlayerIsKeyDown( )
endfunction

private function SetCameraMotion takes nothing returns nothing
    local integer i = GetPlayerId( GetLocalPlayer( ) )
    local real wh = GetWindowHeight( )
    local real ww = GetWindowWidth( )
    local real x  = ww * ( GetMouseScreenX( ) / 0.80 )
    local real y  = wh * ( GetMouseScreenY( ) / 0.60 )
    local real a  = Atan2( y - wh / 2.00, x - ww / 2.00 )
    local real d 
    
    if BUTTON_PRESSED[ GetHandleId( OSKEY_RBUTTON ) ][i] then
        set d = SquareRoot( ( x - ww / 2.00 ) * ( x - ww / 2.00 ) + ( y - wh / 2.00 ) * ( y - wh / 2.00 ) ) * 1.50
        
        call SetCameraField( CAMERA_FIELD_TARGET_DISTANCE, 1850.00 + ( GetAxisZ( x, y ) + GetUnitFlyHeight( CharacterBody[i] ) ) * 0.50, 0.10 )
    else
        set d = RMinBJ( SquareRoot( ( x - ww / 2.00 ) * ( x - ww / 2.00 ) + ( y - wh / 2.00 ) * ( y - wh / 2.00 ) ) * 0.75, 100.00 + 300.00 * ww / 1920.00 )
        
        call SetCameraField( CAMERA_FIELD_TARGET_DISTANCE, 2000.00 + ( GetAxisZ( x, y ) + GetUnitFlyHeight( CharacterBody[i] ) ) * 0.50, 0.10 )
    endif
    
    set x = GetUnitX( CharacterBody[i] )
    set y = GetUnitY( CharacterBody[i] )
    call PanCameraToTimed( x + d * Cos( a ), y + d * Sin( a ), 0.01 )
endfunction

private function OnInit takes nothing returns nothing
    local trigger trgWASD = CreateTrigger( )
    local integer i = 0
    local player p
    
    loop
        set p = Player( i )
        
        if GetPlayerController( p ) == MAP_CONTROL_USER and GetPlayerSlotState( p ) == PLAYER_SLOT_STATE_PLAYING then
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_W, META_KEY_NONE, true )
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_A, META_KEY_NONE, true )
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_S, META_KEY_NONE, true )
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_D, META_KEY_NONE, true )
            
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_W, META_KEY_NONE, false )
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_A, META_KEY_NONE, false )
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_S, META_KEY_NONE, false )
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_D, META_KEY_NONE, false )
            
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_LBUTTON, META_KEY_NONE, true )
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_RBUTTON, META_KEY_NONE, true )
            
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_LBUTTON, META_KEY_NONE, false )
            call TriggerRegisterPlayerKeyEvent( trgWASD, p, OSKEY_RBUTTON, META_KEY_NONE, false )
            
            // створення персонажу
            set CharacterBody[i] = CreateUnitEx( p, 'h000', 0.00, 0.00, 0.00 )
            set CharacterLegs[i] = CreateUnitEx( p, 'h001', 0.00, 0.00, 0.00 )
            
            call AddSpecialEffectTarget( "autogun.mdx", CharacterBody[i], "hand right ref" )
            call SetUnitPathing( CharacterLegs[i], false )
            
            set TempTimer[i] = CreateTimer( )
            
            call SaveInteger( H, GetHandleId( TempTimer[i] ), 0, i )
            call TimerStart( TempTimer[i], 0.01, true, function CheckMoves )
            
            set IsMoved[i] = false
        endif
        
        set i = i + 1
        exitwhen i >= bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddAction( trgWASD, function CharacterMove )
    call TimerStart( CameraMotionTimer, 0.01, true, function SetCameraMotion )
    
    call EnableSelect( false, false )
    call EnablePreSelect( false, false )
    call EnableDragSelect( false, false )
    
    set BulletModel[0] = "Shot Blue.mdx"
    set BulletModel[1] = "Shot Green.mdx"
    set BulletModel[2] = "Shot Orange.mdx"
    set BulletModel[3] = "Shot Purple.mdx"
    set BulletModel[4] = "Shot Red.mdx"
    set BulletModel[5] = "Shot Yellow.mdx"
    
    set trgWASD = null
endfunction
endlibrary

//===========================================================================
//function InitTrig_ShooterSystem takes nothing returns nothing
    //set gg_trg_ShooterSystem = CreateTrigger(  )
//endfunction



`
ОЖИДАНИЕ РЕКЛАМЫ...
28
А слабо было курсор изменить на нормальный прицел? Ты так и будешь бездарно выкладывать свои никому ненужные поделки на хгм? Зачем ты позоришься, боже
Ответы (2)
28
извините господин, я совсем забыл про это, а ещё я забыл про звуки шагов и выстрелить себе в голо
я обязательно не исправлюсь
9
У меня есть своя системка на Рефе полностю все работатет но такую штуку с камерой запилить не знаю как, точнее знаю но получается дергано.
Ответы (4)
28
jasonrus96, кстати, код на камеру мне ещё когда-то давно скинул KaneThaumaturge для Морозко, я просто подкорректировал под нативки южапи
28
jasonrus96, SetCameraSmoothFactor и указать время перемещения камеры не 0.00, а 0.10 к примеру..
Чтобы оставить комментарий, пожалуйста, войдите на сайт.