Making target always appear on the ground (boss fight)

I’m doing a boss fight in my game and have a boss attack where the boss comes from under the ground( like spikes) I also have a target( the thing that indicates where the boss is gonna show up)

That’s the script : wait(5)
local function enemyChallenge()
local bool = true
local No = 0
while task.wait(0.9) do
if bool == true and No <=9 then
for i,player in pairs(game.Players:GetPlayers()) do
if player.Character then
local enemy = game.ReplicatedStorage.Enemy:Clone()
local target = game.ReplicatedStorage.Target:Clone()
local dirt = game.ReplicatedStorage.Dirt:Clone()
target.Parent = game.Workspace
target.CFrame = (player.Character.HumanoidRootPart.CFrame - Vector3.new(0, 2.7, 0)) * CFrame.Angles(0, 0,math.rad(90))
dirt.Parent = game.Workspace
dirt.CFrame = (player.Character.HumanoidRootPart.CFrame - Vector3.new(0, 2.8, 0))
wait(0.7)
enemy.Parent = game.Workspace
enemy:MoveTo(target.Position - Vector3.new(0, 3, 0))
wait(0.9)
target:Destroy()
enemy:Destroy()
dirt:Destroy()
end
end
No += 1
end
end
end
enemyChallenge()

the problem is that the script checks the players hrp to spawn the target under the player ( I use Vector3 to move target under so that it will appear on the ground. But when you jump, the players hrp moves up. So in this situation the target appears above the ground. I’d to always appear on the ground, even if they jump.

I dont even know where I start to fix this problem. The only thing I could think of is attaching, rigging or welding the target, which obviously didnt work…
Screenshot_20230118_222342

the brown thing is the target, as you can see it looks weird

if its a flat ground, you can approximate the y value of the hrp when the player is on the ground, and you can spawn the boss on the hrp’s x and z coordinates and use that approximated y value

example

local player = game.Players:LocalPlayer()
local character = player.Character

local hrp = character.HumanoidRootPart
local loc = hrp.Position

local Y = 4 -- lets just say this is the y value of the player's hrp when they are standing

local spawnloc = Vector3.new(loc.X, Y, loc.Z)

I’m a beginner so sorry for this question but, do I place this example of the script in my code or do I need to change it. If yes where?

i’ll try moderating the script so it works in yours but can you post your script like this:

image

its just easier to read it like that

wait(5)
local function enemyChallenge()
	local bool = true
	local No = 0
	while task.wait(0.9) do
		if bool == true and No <=9 then
			for i,player in pairs(game.Players:GetPlayers()) do
				if player.Character then
					local enemy = game.ReplicatedStorage.Enemy:Clone()
					local target = game.ReplicatedStorage.Target:Clone()
					local dirt = game.ReplicatedStorage.Dirt:Clone()
					target.Parent = game.Workspace
					target.CFrame = (player.Character.HumanoidRootPart.CFrame - Vector3.new(0, 2.7, 0)) * CFrame.Angles(0, 0,math.rad(90))
					dirt.Parent = game.Workspace
					dirt.CFrame = (player.Character.HumanoidRootPart.CFrame - Vector3.new(0, 2.8, 0))
					wait(0.7)
					enemy.Parent = game.Workspace
					enemy:MoveTo(target.Position - Vector3.new(0, 3, 0)) 
					wait(0.9)
					target:Destroy()
					enemy:Destroy()
					dirt:Destroy()
				end
			end
			No += 1
		end
	end
end
enemyChallenge()
1 Like

also, 1 dude told me I should get rid of the for loops cuz my game is single player? I dunno why but just thought it’s worth mentioning it

i dont think it really affects anything

yea. He made me rlly anxious pointing out everything he didnt like, without explaining why. The only thing I understood is that I need to make a WaitForChild when getting the enemy clone, but that oddly made the boss appear only 1 time instead of 9?

wait(5)
local function enemyChallenge()
	local bool = true
	local No = 0
	while task.wait(0.9) do
		if bool == true and No <=9 then
			for i,player in pairs(game.Players:GetPlayers()) do
				if player.Character then
					local enemy = game.ReplicatedStorage.Enemy:Clone()
					local target = game.ReplicatedStorage.Target:Clone()
					local dirt = game.ReplicatedStorage.Dirt:Clone()
					target.Parent = game.Workspace
					target.CFrame = (player.Character.HumanoidRootPart.CFrame - Vector3.new(0, 2.7, 0)) * CFrame.Angles(0, 0,math.rad(90))
					dirt.Parent = game.Workspace
					dirt.CFrame = (player.Character.HumanoidRootPart.CFrame - Vector3.new(0, 2.8, 0))
					wait(0.7)
					enemy.Parent = game.Workspace
					enemy:MoveTo(Vector3.new(target.Position.X, 1, target.Position.Z)) 
					wait(0.9)
					target:Destroy()
					enemy:Destroy()
					dirt:Destroy()
				end
			end
			No += 1
		end
	end
end
enemyChallenge()

enemy:MoveTo(Vector3.new(target.Position.X, 1, target.Position.Z))
this line above me, change that 1 to any number to change the height when it spawns

ty, lemme just try it out in studio. hmm idk why but nothing changed :frowning: could we figure this out tomorrow though pls? I have to sleep, have a good night

oh wait ur making the enemy spawn diffrently, not the target, can I apply the changed line to target.CFrame…?

yeah (devforum makes me send long posts)

So I changed this line target.CFrame = (player.Character.HumanoidRootPart.CFrame - Vector3.new(0, 2.7, 0)) to this line target.CFrame = (player.Character.HumanoidRootPart.CFrame - Vector3.new(target.Position.X, 2.7, target.Position.Z)) and did the same with the dirt( its the 2nd target, for aestethic reasons) but I must have done something wrong since now my target + dirt spawn like in the middle of the map no matter where I move. So, any suggestions?

sorry i forgot about this cause im not active here, but did you get any errors on output

no, however a kind person suggested I try ray casting

so can you still help unicorn?

oh yeah sorry im just not active here

im not the best with raycasting, but i know how to use it, you want to send a ray straight down from the humanoidrootpart, and then that ray hits something, that will be, or should be, the ground, and thats where you will place the dirt

so I already solved my issue, however I have problem which Idk if it is Robloxes fault. Basically like every 2 seconds the boss spawn to attack you. I have this problem not only in this but also in other scripts, that when there is a wait time in a for loop or repeat, the waiting time isnt consistent, which means sometimes it’ll wait 1 second, sometimes 3. That’s really annoying

This is because you’re using ROBLOX’s old wait() function inside your loop, where you should be using the new & improved task.wait() instead

There are a couple things that I personally think you can improve on with the code, one thing in particular that’s bothering me is you’re setting the Parent property of your variables early, which can actually result in a bit more performance usage than what you’d expect

Just make sure to set your properties first, and then the .Parent last

You also have a while task.wait(0.9) loop in there as well, which will run indefinitely so I wouldn’t recommend this, you can go ahead & remove it

Since you said this,

Although that would be the better alternative, calling GetPlayers() I think, is the easier way of obtaining Players rather than having go through the process of re-working your entire code:

  • Referencing the only Player on a Server Script
  • Creating a variable for that one instead & making sure it’s a valid Player Object

One thing to keep note of, is that looping through GetPlayers() will actually cause a delay if there are more than 2 players within the server, as it’ll go through each individual player run each individual code of code X times

The easiest way to get around this is by coroutining it, where it can create a separate function (But it’ll run the same time the moment you first call it) whilst your original code is running as well, but just make sure to space out a decent amount of time for every coroutine created here

local bool = true
local No = 0

task.wait(5)

local function enemyChallenge()
	if bool == true and No <=9 then
		for i,player in pairs(game.Players:GetPlayers()) do
			local Char = player.Character
			
			if Char then
			    coroutine.resume(coroutine.create(function()) -- Think of this as another separate script that's running if it helps
					local HRP = Char:WaitForChild("HumanoidRootPart")
					
					local target = game.ReplicatedStorage.Target:Clone()
					target.CFrame = (HRP.CFrame - Vector3.new(0, 2.7, 0)) * CFrame.Angles(0, 0,math.rad(90))
					target.Parent = game.Workspace

					local dirt = game.ReplicatedStorage.Dirt:Clone()
					dirt.CFrame = (HRP.CFrame - Vector3.new(0, 2.8, 0))
					dirt.Parent = game.Workspace
					
					task.wait(0.7)
					
					local enemy = game.ReplicatedStorage.Enemy:Clone()
					enemy:MoveTo(Vector3.new(target.Position.X, 1, target.Position.Z)) 
					enemy.Parent = game.Workspace
					
					task.wait(0.9)
					
					target:Destroy()
					enemy:Destroy()
					dirt:Destroy()
				end))
			end
		end
		No += 1
		
		task.wait(2) -- We want to include a task.wait() here, cause there's no yielding within our loop as the corountine is its own separate function
	end
end

enemyChallenge()
1 Like