Hasli4

Untitled

Aug 3rd, 2026
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.39 KB | None | 0 0
  1. local Players = game:GetService("Players")
  2. local ReplicatedStorage = game:GetService("ReplicatedStorage")
  3.  
  4. local knight = script.Parent
  5. local knightRoot = knight:WaitForChild("Torso")
  6.  
  7. local startPoint = workspace:WaitForChild("StartPoint")
  8. local caughtEvent = ReplicatedStorage:WaitForChild("CaughtEvent")
  9.  
  10.  
  11. -- =====================================================
  12. -- НАСТРОЙКИ ПОЛЯ ЗРЕНИЯ
  13. -- =====================================================
  14.  
  15. -- На какое расстояние видит рыцарь
  16. local VIEW_DISTANCE = 30
  17.  
  18. -- Полный угол обзора
  19. -- Например, 70 означает 35 градусов влево
  20. -- и 35 градусов вправо
  21. local VIEW_ANGLE = 70
  22.  
  23. -- Как часто проверять игроков
  24. local CHECK_DELAY = 0.1
  25.  
  26. -- Высота жёлтого поля зрения относительно HumanoidRootPart
  27. local VISION_HEIGHT_OFFSET = -2.7
  28.  
  29. -- Количество полос, из которых строится жёлтый веер
  30. local STRIP_COUNT = 21
  31.  
  32. -- Прозрачность жёлтого поля
  33. -- 0 = непрозрачное
  34. -- 1 = полностью невидимое
  35. local VISION_TRANSPARENCY = 0.84
  36.  
  37. -- Направление поля зрения
  38. -- Если поле смотрит назад, поставьте 180
  39. local DIRECTION_OFFSET = 0
  40.  
  41. -- Сколько секунд игрок не может быть пойман повторно
  42. local CATCH_COOLDOWN = 2
  43.  
  44.  
  45. -- =====================================================
  46. -- СОЗДАНИЕ ВИДИМОГО ЖЁЛТОГО ПОЛЯ ЗРЕНИЯ
  47. -- =====================================================
  48.  
  49. local oldVisionCone = knight:FindFirstChild("VisionCone")
  50.  
  51. if oldVisionCone then
  52. oldVisionCone:Destroy()
  53. end
  54.  
  55. local visionFolder = Instance.new("Folder")
  56. visionFolder.Name = "VisionCone"
  57. visionFolder.Parent = knight
  58.  
  59. -- Расстояние между соседними полосами по углу
  60. local angleStep = VIEW_ANGLE / (STRIP_COUNT - 1)
  61.  
  62. -- Ширина каждой полосы
  63. local stripWidth =
  64. 2
  65. * VIEW_DISTANCE
  66. * math.tan(math.rad(angleStep / 2))
  67. * 1.15
  68.  
  69. for number = 0, STRIP_COUNT - 1 do
  70. local angle = -VIEW_ANGLE / 2 + angleStep * number
  71.  
  72. local strip = Instance.new("Part")
  73. strip.Name = "VisionStrip"
  74.  
  75. strip.Size = Vector3.new(
  76. stripWidth,
  77. 0.08,
  78. VIEW_DISTANCE
  79. )
  80.  
  81. strip.Color = Color3.fromRGB(255, 220, 40)
  82. strip.Material = Enum.Material.Neon
  83. strip.Transparency = VISION_TRANSPARENCY
  84.  
  85. strip.Anchored = false
  86. strip.Massless = true
  87.  
  88. strip.CanCollide = false
  89. strip.CanTouch = false
  90. strip.CanQuery = false
  91. strip.CastShadow = false
  92.  
  93. -- Размещаем полосу перед рыцарем
  94. strip.CFrame =
  95. knightRoot.CFrame
  96. * CFrame.Angles(
  97. 0,
  98. math.rad(DIRECTION_OFFSET + angle),
  99. 0
  100. )
  101. * CFrame.new(
  102. 0,
  103. VISION_HEIGHT_OFFSET,
  104. -VIEW_DISTANCE / 2
  105. )
  106.  
  107. strip.Parent = visionFolder
  108.  
  109. -- Прикрепляем полосу к рыцарю
  110. local weld = Instance.new("WeldConstraint")
  111. weld.Part0 = knightRoot
  112. weld.Part1 = strip
  113. weld.Parent = strip
  114. end
  115.  
  116.  
  117. -- =====================================================
  118. -- НАПРАВЛЕНИЕ, КУДА СМОТРИТ РЫЦАРЬ
  119. -- =====================================================
  120.  
  121. local function getKnightForwardVector()
  122. local directionCFrame =
  123. knightRoot.CFrame
  124. * CFrame.Angles(
  125. 0,
  126. math.rad(DIRECTION_OFFSET),
  127. 0
  128. )
  129.  
  130. return directionCFrame.LookVector
  131. end
  132.  
  133.  
  134. -- =====================================================
  135. -- НАСТРОЙКА ЛУЧА
  136. -- =====================================================
  137.  
  138. local raycastParameters = RaycastParams.new()
  139.  
  140. raycastParameters.FilterType = Enum.RaycastFilterType.Exclude
  141.  
  142. -- Луч не должен сталкиваться с частями самого рыцаря
  143. raycastParameters.FilterDescendantsInstances = {
  144. knight
  145. }
  146.  
  147. raycastParameters.IgnoreWater = true
  148.  
  149.  
  150. -- =====================================================
  151. -- ПРОВЕРКА: ВИДИТ ЛИ РЫЦАРЬ ПЕРСОНАЖА
  152. -- =====================================================
  153.  
  154. local function canSeeCharacter(character)
  155. if not character then
  156. return false
  157. end
  158.  
  159. local characterRoot =
  160. character:FindFirstChild("Torso")
  161.  
  162. local humanoid =
  163. character:FindFirstChildOfClass("Humanoid")
  164.  
  165. if not characterRoot or not humanoid then
  166. return false
  167. end
  168.  
  169. if humanoid.Health <= 0 then
  170. return false
  171. end
  172.  
  173.  
  174. -- Точка, из которой смотрит рыцарь
  175. local eyePosition =
  176. knightRoot.Position
  177. + Vector3.new(0, 1.5, 0)
  178.  
  179. -- Точка на теле игрока
  180. local targetPosition =
  181. characterRoot.Position
  182. + Vector3.new(0, 1, 0)
  183.  
  184. local directionToPlayer =
  185. targetPosition - eyePosition
  186.  
  187. local distanceToPlayer =
  188. directionToPlayer.Magnitude
  189.  
  190.  
  191. -- Проверяем расстояние
  192. if distanceToPlayer > VIEW_DISTANCE then
  193. return false
  194. end
  195.  
  196. if distanceToPlayer < 0.1 then
  197. return false
  198. end
  199.  
  200.  
  201. -- Убираем высоту, чтобы проверять угол только по горизонтали
  202. local horizontalDirectionToPlayer = Vector3.new(
  203. directionToPlayer.X,
  204. 0,
  205. directionToPlayer.Z
  206. )
  207.  
  208. local knightForward = getKnightForwardVector()
  209.  
  210. local horizontalKnightForward = Vector3.new(
  211. knightForward.X,
  212. 0,
  213. knightForward.Z
  214. )
  215.  
  216. if horizontalDirectionToPlayer.Magnitude < 0.01 then
  217. return false
  218. end
  219.  
  220. if horizontalKnightForward.Magnitude < 0.01 then
  221. return false
  222. end
  223.  
  224.  
  225. -- Вычисляем угол между взглядом рыцаря и игроком
  226. local dotProduct = math.clamp(
  227. horizontalKnightForward.Unit:Dot(
  228. horizontalDirectionToPlayer.Unit
  229. ),
  230. -1,
  231. 1
  232. )
  233.  
  234. local angleToPlayer =
  235. math.deg(math.acos(dotProduct))
  236.  
  237.  
  238. -- Игрок находится слишком далеко в стороне
  239. if angleToPlayer > VIEW_ANGLE / 2 then
  240. return false
  241. end
  242.  
  243.  
  244. -- Пускаем луч от рыцаря до игрока
  245. local raycastResult = workspace:Raycast(
  246. eyePosition,
  247. directionToPlayer,
  248. raycastParameters
  249. )
  250.  
  251.  
  252. -- Если луч ни во что не попал,
  253. -- значит между рыцарем и игроком нет препятствия
  254. if not raycastResult then
  255. return true
  256. end
  257.  
  258.  
  259. -- Если луч попал в часть персонажа,
  260. -- значит рыцарь действительно видит игрока
  261. if raycastResult.Instance:IsDescendantOf(character) then
  262. return true
  263. end
  264.  
  265.  
  266. -- Луч попал в стену или другой объект
  267. return false
  268. end
  269.  
  270.  
  271. -- =====================================================
  272. -- ВОЗВРАЩЕНИЕ ИГРОКА НА СТАРТ
  273. -- =====================================================
  274.  
  275. local caughtPlayers = {}
  276.  
  277. local function catchPlayer(player)
  278. -- Защита от многократного срабатывания
  279. if caughtPlayers[player] then
  280. return
  281. end
  282.  
  283. caughtPlayers[player] = true
  284.  
  285. -- Показываем сообщение только пойманному игроку
  286. caughtEvent:FireClient(
  287. player,
  288. "Вы попались, попробуйте ещё раз"
  289. )
  290.  
  291. local character = player.Character
  292.  
  293. if character then
  294. local characterRoot =
  295. character:FindFirstChild("Torso")
  296.  
  297. if characterRoot then
  298. -- Перемещаем весь персонаж на старт
  299. character:PivotTo(
  300. startPoint.CFrame
  301. * CFrame.new(0, 3, 0)
  302. )
  303.  
  304. -- Останавливаем движение после телепортации
  305. characterRoot.AssemblyLinearVelocity =
  306. Vector3.zero
  307.  
  308. characterRoot.AssemblyAngularVelocity =
  309. Vector3.zero
  310. end
  311. end
  312.  
  313. -- Через несколько секунд игрок снова может быть замечен
  314. task.delay(CATCH_COOLDOWN, function()
  315. caughtPlayers[player] = nil
  316. end)
  317. end
  318.  
  319.  
  320. -- =====================================================
  321. -- ПОСТОЯННАЯ ПРОВЕРКА ВСЕХ ИГРОКОВ
  322. -- =====================================================
  323.  
  324. while knight.Parent do
  325. for _, player in ipairs(Players:GetPlayers()) do
  326. if not caughtPlayers[player] then
  327. local character = player.Character
  328.  
  329. if canSeeCharacter(character) then
  330. catchPlayer(player)
  331. end
  332. end
  333. end
  334.  
  335. task.wait(CHECK_DELAY)
  336. end
Advertisement
Add Comment
Please, Sign In to add comment