Lewati ke konten
BerfungsiCombat

semi-universal wallbang

FLFluffyBlox766 tayanganUniversal22 Jul 2026
Bagikan
semi-universal wallbang

Kode Script

Lua
local CONFIG = {
	MAX_PHASE_COUNT = 128,
	RAY_DISTANCE = 5000,
	STAND_CHECK_DIST = 4,
	IGNORE_TERRAIN = false,

	-- Only affect anchored/static world parts.
	STATIC_ONLY = true,

	-- Never touch parts with any transparency above this threshold.
	-- Set to 0 so anything even slightly transparent is ignored.
	MAX_ALLOWED_TRANSPARENCY = 0,

	-- Small offset between successive penetrations to reduce repeated hits
	-- on the same surface from floating-point precision jitter.
	RAY_ADVANCE_EPSILON = 0.01,

	ANTI_FLOOR = {
		ENABLED = false,

		-- A part is treated as "floor-like" when one axis is much thinner
		-- than the other two, and that thin axis is close to world-up/down.
		MAX_THIN_TO_WIDE_RATIO = 0.30,
		MIN_WIDE_AXIS = 2.0,
		MIN_MIDDLE_AXIS = 1.0,
		MIN_THIN_AXIS = 0.20,
		MIN_UP_ALIGNMENT = 0.75,
	},

	PHYSICS = {
		-- How long a part must stay out of the active target set before it
		-- becomes eligible to be restored. This smooths out flicker.
		RESTORE_DELAY = 0.08,
	},

	VISUALIZATION = {
		ENABLED = true,
		SHOW_HUD = false,
		SHOW_RAY = true,
		SHOW_HIT_MARKERS = true,
		SHOW_HIGHLIGHTS = true,

		RAY_COLOR = Color3.fromRGB(0, 255, 170),
		HIT_MARKER_COLOR = Color3.fromRGB(255, 170, 0),
		HIGHLIGHT_FILL_COLOR = Color3.fromRGB(255, 255, 0),
		HIGHLIGHT_OUTLINE_COLOR = Color3.fromRGB(255, 255, 255),

		RAY_THICKNESS = 0.08,
		HIT_MARKER_SIZE = 0.22,

		-- Moves the hit marker lower/up/down in world space.
		-- Negative Y lowers it.
		HIT_MARKER_OFFSET = Vector3.new(0, -2.5, 0),

		-- In first person, aim from the center of the screen instead of the
		-- mouse position. This offset is applied in screen-space pixels.
		-- Positive X = right, positive Y = down.
		FIRST_PERSON_SCREEN_OFFSET = Vector2.new(0, 0),

		HIGHLIGHT_FILL_TRANSPARENCY = 0.75,
		HIGHLIGHT_OUTLINE_TRANSPARENCY = 0.1,
	},
}

-- ═══════════════════════════════════════════════════════════════════════════
--  SERVICES / REFERENCES
-- ═══════════════════════════════════════════════════════════════════════════

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local GuiService = game:GetService("GuiService")

local player = Players.LocalPlayer
local camera = workspace.CurrentCamera

--  STATE

local disabledParts: { [BasePart]: boolean } = {}
local restoreQueue: { [BasePart]: number } = {}

type HitInfo = {
	Part: BasePart,
	Position: Vector3,
	StartPosition: Vector3,
}

local currentTargets: { [BasePart]: boolean } = {}

-- Reused raycast parameters and buffers to reduce per-frame allocations.
local mainRayParams = RaycastParams.new()
mainRayParams.FilterType = Enum.RaycastFilterType.Exclude
mainRayParams.IgnoreWater = true

local standRayParams = RaycastParams.new()
standRayParams.FilterType = Enum.RaycastFilterType.Exclude
standRayParams.IgnoreWater = true

local excludedInstances: { Instance } = table.create(16)
local standExcludedInstances: { Instance } = table.create(4)

-- ═══════════════════════════════════════════════════════════════════════════
--  UI
-- ═══════════════════════════════════════════════════════════════════════════

local screenGui = Instance.new("ScreenGui")
screenGui.Name = "RaycastPhaseUI"
screenGui.ResetOnSpawn = false
screenGui.Parent = player:WaitForChild("PlayerGui")

local label = Instance.new("TextLabel")
label.Name = "StatusLabel"
label.Size = UDim2.new(0, 420, 0, 44)
label.Position = UDim2.new(0.5, -210, 0, 16)
label.BackgroundTransparency = 0.35
label.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
label.TextColor3 = Color3.fromRGB(255, 255, 255)
label.Font = Enum.Font.GothamBold
label.TextSize = 15
label.TextXAlignment = Enum.TextXAlignment.Center
label.Text = ""
label.Visible = CONFIG.VISUALIZATION.ENABLED and CONFIG.VISUALIZATION.SHOW_HUD
label.Parent = screenGui

--  DEBUG VISUALS

local debugFolder: Folder? = nil
local rayParts: { Part } = {}
local hitMarkers: { Part } = {}
local debugHighlights: { [BasePart]: Highlight } = {}

local function ensureDebugFolder()
	if not CONFIG.VISUALIZATION.ENABLED then
		return
	end

	if debugFolder and debugFolder.Parent then
		return
	end

	debugFolder = Instance.new("Folder")
	debugFolder.Name = "RaycastPhaseDebug"
	debugFolder.Parent = workspace
end

ensureDebugFolder()

local function setDebugPartVisible(part: Part, visible: boolean)
	part.Transparency = visible and 0.15 or 1
	part.CanCollide = false
	part.CanQuery = false
	part.CanTouch = false
end

local function getRayPart(index: number): Part
	ensureDebugFolder()

	local part = rayParts[index]
	if not part then
		part = Instance.new("Part")
		part.Name = "RaySegment_" .. index
		part.Anchored = true
		part.Locked = true
		part.CanCollide = false
		part.CanQuery = false
		part.CanTouch = false
		part.Material = Enum.Material.Neon
		part.Color = CONFIG.VISUALIZATION.RAY_COLOR
		part.Size = Vector3.new(CONFIG.VISUALIZATION.RAY_THICKNESS, CONFIG.VISUALIZATION.RAY_THICKNESS, 1)
		part.Parent = debugFolder
		rayParts[index] = part
	end
	return part
end

local function getHitMarker(index: number): Part
	ensureDebugFolder()

	local part = hitMarkers[index]
	if not part then
		part = Instance.new("Part")
		part.Name = "HitMarker_" .. index
		part.Anchored = true
		part.Locked = true
		part.Shape = Enum.PartType.Ball
		part.CanCollide = false
		part.CanQuery = false
		part.CanTouch = false
		part.Material = Enum.Material.Neon
		part.Color = CONFIG.VISUALIZATION.HIT_MARKER_COLOR
		part.Size = Vector3.new(
			CONFIG.VISUALIZATION.HIT_MARKER_SIZE,
			CONFIG.VISUALIZATION.HIT_MARKER_SIZE,
			CONFIG.VISUALIZATION.HIT_MARKER_SIZE
		)
		part.Parent = debugFolder
		hitMarkers[index] = part
	end
	return part
end

local function getOrCreateHighlight(part: BasePart): Highlight
	ensureDebugFolder()

	local existing = debugHighlights[part]
	if existing then
		return existing
	end

	local highlight = Instance.new("Highlight")
	highlight.Name = "PhaseHighlight"
	highlight.Adornee = part
	highlight.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
	highlight.FillColor = CONFIG.VISUALIZATION.HIGHLIGHT_FILL_COLOR
	highlight.OutlineColor = CONFIG.VISUALIZATION.HIGHLIGHT_OUTLINE_COLOR
	highlight.FillTransparency = CONFIG.VISUALIZATION.HIGHLIGHT_FILL_TRANSPARENCY
	highlight.OutlineTransparency = CONFIG.VISUALIZATION.HIGHLIGHT_OUTLINE_TRANSPARENCY
	highlight.Enabled = true
	highlight.Parent = debugFolder

	debugHighlights[part] = highlight
	return highlight
end

local function clearUnusedDebugParts(usedRayCount: number, usedMarkerCount: number, usedHighlights: { [BasePart]: boolean })
	for i = usedRayCount + 1, #rayParts do
		setDebugPartVisible(rayParts[i], false)
	end

	for i = usedMarkerCount + 1, #hitMarkers do
		setDebugPartVisible(hitMarkers[i], false)
	end

	for part, highlight in pairs(debugHighlights) do
		if not usedHighlights[part] then
			highlight.Enabled = false
		end
	end
end

local function updateDebugVisuals(hits: { HitInfo })
	if not CONFIG.VISUALIZATION.ENABLED then
		return
	end

	ensureDebugFolder()
	if not debugFolder then
		return
	end

	local usedHighlights: { [BasePart]: boolean } = {}
	local rayIndex = 0
	local markerIndex = 0

	if CONFIG.VISUALIZATION.SHOW_RAY then
		for _, hit in ipairs(hits) do
			rayIndex += 1
			local segment = getRayPart(rayIndex)

			local startPos = hit.StartPosition
			local endPos = hit.Position
			local length = (endPos - startPos).Magnitude

			if length < 0.001 then
				setDebugPartVisible(segment, false)
			else
				local midpoint = (startPos + endPos) * 0.5
				segment.Size = Vector3.new(CONFIG.VISUALIZATION.RAY_THICKNESS, CONFIG.VISUALIZATION.RAY_THICKNESS, length)
				segment.CFrame = CFrame.lookAt(midpoint, endPos)
				setDebugPartVisible(segment, true)
			end
		end
	end

	if CONFIG.VISUALIZATION.SHOW_HIT_MARKERS then
		for _, hit in ipairs(hits) do
			markerIndex += 1
			local marker = getHitMarker(markerIndex)
			marker.CFrame = CFrame.new(hit.Position + CONFIG.VISUALIZATION.HIT_MARKER_OFFSET)
			setDebugPartVisible(marker, true)
		end
	end

	if CONFIG.VISUALIZATION.SHOW_HIGHLIGHTS then
		for _, hit in ipairs(hits) do
			usedHighlights[hit.Part] = true
			getOrCreateHighlight(hit.Part).Enabled = true
		end
	end

	clearUnusedDebugParts(rayIndex, markerIndex, usedHighlights)
end

--  HELPERS

local function getStandingPart(): BasePart?
	local char = player.Character
	if not char then
		return nil
	end

	local root = char:FindFirstChild("HumanoidRootPart") :: BasePart?
	if not root then
		return nil
	end

	standExcludedInstances[1] = char
	standRayParams.FilterDescendantsInstances = standExcludedInstances

	local result = workspace:Raycast(root.Position, Vector3.new(0, -CONFIG.STAND_CHECK_DIST, 0), standRayParams)
	if result and result.Instance and result.Instance:IsA("BasePart") then
		return result.Instance
	end

	return nil
end

local function isInTool(inst: Instance): boolean
	return inst:FindFirstAncestorOfClass("Tool") ~= nil
end

local function isInAccessory(inst: Instance): boolean
	return inst:FindFirstAncestorOfClass("Accessory") ~= nil
end

local function isInCharacterModel(inst: Instance): boolean
	local model = inst:FindFirstAncestorOfClass("Model")
	return model ~= nil and model:FindFirstChildOfClass("Humanoid") ~= nil
end

local function getIgnoreRoot(inst: Instance): Instance
	local tool = inst:FindFirstAncestorOfClass("Tool")
	if tool then
		return tool
	end

	local accessory = inst:FindFirstAncestorOfClass("Accessory")
	if accessory then
		return accessory
	end

	local model = inst:FindFirstAncestorOfClass("Model")
	if model and model:FindFirstChildOfClass("Humanoid") then
		return model
	end

	return inst
end

local function isTransparentPart(part: BasePart): boolean
	return part.Transparency > CONFIG.MAX_ALLOWED_TRANSPARENCY
end

local function isLikelyFloor(part: BasePart): boolean
	if not CONFIG.ANTI_FLOOR.ENABLED then
		return false
	end

	local size = part.Size

	local axes = {
		{ size = size.X, vec = part.CFrame.RightVector },
		{ size = size.Y, vec = part.CFrame.UpVector },
		{ size = size.Z, vec = part.CFrame.LookVector },
	}

	table.sort(axes, function(a, b)
		return a.size < b.size
	end)

	local thin = axes[1].size
	local mid = axes[2].size
	local wide = axes[3].size

	if thin < CONFIG.ANTI_FLOOR.MIN_THIN_AXIS then
		return false
	end

	if mid < CONFIG.ANTI_FLOOR.MIN_MIDDLE_AXIS then
		return false
	end

	if wide < CONFIG.ANTI_FLOOR.MIN_WIDE_AXIS then
		return false
	end

	if (thin / wide) > CONFIG.ANTI_FLOOR.MAX_THIN_TO_WIDE_RATIO then
		return false
	end

	local thinAxisVector = axes[1].vec
	local upAlignment = math.abs(thinAxisVector:Dot(Vector3.yAxis))

	return upAlignment >= CONFIG.ANTI_FLOOR.MIN_UP_ALIGNMENT
end

local function isStaticWorldPart(part: BasePart): boolean
	if CONFIG.STATIC_ONLY and not part.Anchored then
		return false
	end

	return true
end

local function shouldIgnoreHit(inst: Instance): boolean
	if CONFIG.IGNORE_TERRAIN and inst == workspace.Terrain then
		return true
	end

	if not inst:IsA("BasePart") then
		return true
	end

	local part = inst :: BasePart

	if isTransparentPart(part) then
		return true
	end

	if not isStaticWorldPart(part) then
		return true
	end

	if isInTool(inst) or isInAccessory(inst) or isInCharacterModel(inst) then
		return true
	end

	if isLikelyFloor(part) then
		return true
	end

	return false
end

local function disablePart(part: BasePart)
	if disabledParts[part] then
		return
	end

	disabledParts[part] = true
	part.CanCollide = false
	part.CanQuery = false
end

local function tryEnablePart(part: BasePart, standingOn: BasePart?)
	if standingOn == part then
		return false
	end

	if not disabledParts[part] then
		return false
	end

	part.CanCollide = true
	part.CanQuery = true
	disabledParts[part] = nil
	restoreQueue[part] = nil
	return true
end

local function castPenetratingRay(origin: Vector3, direction: Vector3): { HitInfo }
	local hits: { HitInfo } = {}

	local char = player.Character
	table.clear(excludedInstances)
	if char then
		excludedInstances[1] = char
	end
	mainRayParams.FilterDescendantsInstances = excludedInstances

	local remaining = CONFIG.RAY_DISTANCE
	local rayOrigin = origin
	local rayDir = direction.Unit

	for _ = 1, CONFIG.MAX_PHASE_COUNT do
		if remaining <= 0 then
			break
		end

		local startPos = rayOrigin
		local result = workspace:Raycast(rayOrigin, rayDir * remaining, mainRayParams)
		if not result then
			break
		end

		local inst = result.Instance
		local travelled = result.Distance
		rayOrigin = result.Position + rayDir * CONFIG.RAY_ADVANCE_EPSILON
		remaining -= travelled

		if shouldIgnoreHit(inst) then
			excludedInstances[#excludedInstances + 1] = getIgnoreRoot(inst)
			continue
		end

		local part = inst :: BasePart
		hits[#hits + 1] = {
			Part = part,
			Position = result.Position,
			StartPosition = startPos,
		}

		excludedInstances[#excludedInstances + 1] = part
	end

	return hits
end

local function buildTargetNameText(targets: { HitInfo }): string
	if #targets == 0 then
		return ""
	elseif #targets == 1 then
		return "⬡ Phasing: " .. targets[1].Part.Name
	else
		local names = table.create(#targets)
		for i, hit in ipairs(targets) do
			names[i] = hit.Part.Name
		end
		return "⬡ Phasing (" .. #targets .. "): " .. table.concat(names, " → ")
	end
end

local function updateTargetCache(newTargets: { HitInfo })
	table.clear(currentTargets)
	for _, hit in ipairs(newTargets) do
		currentTargets[hit.Part] = true
	end
end

local function updateAimRayAndUi()
	camera = workspace.CurrentCamera
	if not camera then
		return
	end

	local viewportPos: Vector2

	if UserInputService.MouseEnabled then
		local inset = GuiService:GetGuiInset()
		local mousePos = UserInputService:GetMouseLocation()
		viewportPos = mousePos - Vector2.new(inset.X, inset.Y)
	else
		local vp = camera.ViewportSize
		viewportPos = Vector2.new(vp.X * 0.5, vp.Y * 0.5)
	end

	local function isFirstPerson()
		if player.CameraMode == Enum.CameraMode.LockFirstPerson then
			return true
		end

		local camPos = camera.CFrame.Position
		local focusPos = camera.Focus.Position
		return (camPos - focusPos).Magnitude < 1.5
	end

	if isFirstPerson() then
		local vp = camera.ViewportSize
		viewportPos = Vector2.new(vp.X * 0.5, vp.Y * 0.5) + CONFIG.VISUALIZATION.FIRST_PERSON_SCREEN_OFFSET
	end

	local unitRay = camera:ViewportPointToRay(viewportPos.X, viewportPos.Y, 0)
	local origin = unitRay.Origin
	local direction = unitRay.Direction

	local newTargets = castPenetratingRay(origin, direction)
	updateTargetCache(newTargets)

	if CONFIG.VISUALIZATION.ENABLED and CONFIG.VISUALIZATION.SHOW_HUD then
		label.Visible = true
		label.Text = buildTargetNameText(newTargets)
	else
		label.Visible = false
	end

	updateDebugVisuals(newTargets)
end

local function syncPhysicsState()
	local now = os.clock()
	local standingOn = getStandingPart()

	-- Refresh current targets immediately before physics.
	for part in pairs(currentTargets) do
		if part and part.Parent then
			disablePart(part)
		else
			disabledParts[part] = nil
			restoreQueue[part] = nil
		end
	end

	-- Queue stale disabled parts for restoration.
	for part in pairs(disabledParts) do
		if not currentTargets[part] and part.Parent then
			if not restoreQueue[part] then
				restoreQueue[part] = now + CONFIG.PHYSICS.RESTORE_DELAY
			end
		end
	end

	-- Cancel restore timers for parts that became targets again.
	for part in pairs(restoreQueue) do
		if currentTargets[part] then
			restoreQueue[part] = nil
		end
	end

	-- Try restoring anything whose delay has elapsed.
	for part, restoreAt in pairs(restoreQueue) do
		if now >= restoreAt then
			if part and part.Parent then
				if tryEnablePart(part, standingOn) then
					restoreQueue[part] = nil
				else
					-- Still standing on it; keep retrying.
					restoreQueue[part] = now + CONFIG.PHYSICS.RESTORE_DELAY
				end
			else
				disabledParts[part] = nil
				restoreQueue[part] = nil
			end
		end
	end
end

-- ═══════════════════════════════════════════════════════════════════════════
--  MAIN LOOP
-- ═══════════════════════════════════════════════════════════════════════════

local BIND_NAME = "RaycastPhaseScript"

RunService:BindToRenderStep(BIND_NAME, Enum.RenderPriority.Camera.Value + 1, updateAimRayAndUi)
RunService.PreSimulation:Connect(syncPhysicsState)
RunService.Heartbeat:Connect(syncPhysicsState)

-- ═══════════════════════════════════════════════════════════════════════════
--  CLEANUP ON RESPAWN
-- ═══════════════════════════════════════════════════════════════════════════

local function cleanup()
	for part in pairs(disabledParts) do
		if part and part.Parent then
			part.CanCollide = true
			part.CanQuery = true
		end
	end

	table.clear(disabledParts)
	table.clear(restoreQueue)
	table.clear(currentTargets)
	label.Text = ""

	if CONFIG.VISUALIZATION.ENABLED and debugFolder then
		for _, part in ipairs(rayParts) do
			if part then
				part:Destroy()
			end
		end

		for _, part in ipairs(hitMarkers) do
			if part then
				part:Destroy()
			end
		end

		for _, highlight in pairs(debugHighlights) do
			if highlight then
				highlight:Destroy()
			end
		end

		debugFolder:Destroy()
		debugFolder = nil
		rayParts = {}
		hitMarkers = {}
		debugHighlights = {}
	end
end

player.CharacterRemoving:Connect(cleanup)

Deskripsi

uses a raycast to toggle a parts collisions and cantouch, letting most gun games shoot through walls. fully depends on a games security. this can be very buggy and laggy, the endpoint of the raycast is also too low, but paired with a trigger bot it can be pretty fun

Komentar (0)

Masuk untuk ikut berdiskusi

  • Jadilah yang pertama berkomentar.

Pertanyaan yang sering diajukan

Bagaimana cara menggunakan script semi-universal wallbang?
Salin kode script di atas, masuk ke Universal di Roblox, lalu tempel dan jalankan kodenya di executor kamu. Fiturnya langsung aktif begitu script berjalan.
Apakah semi-universal wallbang masih berfungsi?
Ya — semi-universal wallbang saat ini ditandai berfungsi (terakhir diperbarui 17 Sep 2026). Jika rusak setelah update Roblox, cek kembali untuk versi terbaru.
Executor mana yang kompatibel dengan semi-universal wallbang?
Script ini bekerja dengan sebagian besar executor Roblox populer. Lihat halaman executor kami untuk menemukan executor gratis atau berbayar yang tepercaya untuk perangkat Anda.