Best way to do bullet holes? (Placing imagelabels in surfacegui depending on where the bullet hits)

How do games handle bullet holes like this?

https://i.gyazo.com/05d6552c245ed5bce9191af9430715e3.gif

I’ve looked through free models and they all just spawn an invisible part and put a decal in the direction of the shooter.

I found this topic that says to use a surfacegui

but it’s from 2 years ago and it doesn’t explain how they position the imagelabel based on where you shoot.

My gripe with the first method mentioned is that it might lag the game with so many instances being created and deleted every time a bullet hole is created and deleted.

4 Likes

You should look into raycasting as it’s how they get the position and stuff. Also you should use a part pooling system for the bullet holes

If I’m not mistaken, its possible to set the material of parts to air to get a similar effect to image labels with decals?

I know how to use raycasts. However, to my understanding, it’s better to use surfaceGUIs instead of cloning and parenting to workspace from the replicated storage. The problem is how you would position the imagelabel inside the surfaceGUI based on where you shot.

Do games with bullet holes just create transparent parts and stick a decal on it or do they use the method I mentioned before?

From what I know, yes, they create decals on invisible part.

Hey there, I made this simple script a few years ago:

I use it for bullet holes in my gun system. Here’s a video showing it from a few years ago

24 Likes

Hello, could you explain how to use it?
I have tried to use it, but the times I have used it I have missed a mistake
The error practically reads like this: “getSurfaceClosestToPoint is not valid member of baseplate” As well as the baseplate, with all the blocks I shoot that error appears to me.
Like this

module.WorldPositionToGuiPosition(hitpart,hitpos)

I’ve done everything right, the position gives you a vector 3 and the hitpart gives you the part you’ve shot.

local SurfaceFace, Width, Height, RelativeX, RelativeY = WorldToGuiModule.WorldPositionToGuiPosition( PartHit, Position )

local SCALE = 128
	
local SurfaceGui = Instance.new("SurfaceGui")
SurfaceGui.CanvasSize = Vector2.new( SCALE*Width, SCALE*Height )
SurfaceGui.LightInfluence = 1
SurfaceGui.Face = SurfaceFace

local SurfaceFrame = Instance.new("Frame")
SurfaceFrame.Size = UDim2.new(1, 0, 1, 0)
SurfaceFrame.BackgroundTransparency = 1
SurfaceFrame.ClipsDescendants = true
SurfaceFrame.BorderSizePixel = 0
SurfaceFrame.Parent = SurfaceGui

local BulletDecal = Instance.new("ImageLabel")
BulletDecal.BorderSizePixel = 0
BulletDecal.BackgroundTransparency = 1
BulletDecal.Size = UDim2.new( 0, SCALE*DecalSize, 0, SCALE*DecalSize )
BulletDecal.AnchorPoint = Vector2.new(0.5, 0.5)
BulletDecal.Position = UDim2.new(RelativeX, 0, RelativeY, 0)
BulletDecal.Parent = SurfaceFrame

SurfaceGui.Parent = PartHit

I don’t suggestion using instance.new for every new bullet hole, look into how to make a part pool

Yes, I did the same thing in my script.
When sending the block and the pocision to the modulescript this gives error in line 121, the same one that I just taught you
“GetSurfaceClosestToPoint is not a valid member of baseplate”.

This is an example. If you want to use a pool, go for it.

It’s working for me. The line you’re referring to:
local Surface = self:GetSurfaceClosestToPoint( Part, WorldPosition );

Which indicates your error thinks “self” is baseplate. No idea how that could be the case. In any means, I just updated the script on the toolbox to be the latest one I have. Though I am quite sure I haven’t touched it since I wrote it in 2017.

I will try it, by the way, very well programmed the bots of your last video, I am currently trying to make an fps with game modes similar to those of the video game “halo” and I am inspired by your creations.

1 Like

I just reviewed it and it has no difference with the old one

I did everything correctly and got this, do you know the solution?


Yeah I’m having the same issue as @ZDevZ12 is, I’ve been staring at my screen for the past 15 minutes and I’m not sure how to solve this.


Trying to fix one thing leads to another error.

It’s working totally fine for me. I copied the example above and put it in a test place (uncopylocked):
https://www.roblox.com/games/7719736091/Bullet-Hole-Test

1 Like

Works well, thank you for helping us with this! :blue_heart:

I had to do another module from 0, the current module has given me error by mistake but already
https://ro.blox.com/Ebh5?pid=share&is_retargeting=true&af_dp=roblox%3A%2F%2Fnavigation%2Fgame_details%3FgameId%3D2843015560&af_web_dp=https%3A%2F%2Fwww.roblox.com%2Fgames%2F7283636956
This is my testing game, I’ve been creating this game and use the module that I made, you can enter and check if you want :’)

128 was the size of the imagelabel in the example. Change it to the size of yours. (It could be because for the size of the decal your doing x2)

I’m a little late… But how do I set this up? I’m bad with modulescripts, and I am not sure how to use it and modify it to actually create bullet holes from my raycast…