Jump to content

Recommended Posts

hello, I need help I'm really new to this thing I'm trying out and have no idea how to achieve it lol

 

so, i'm trying to spawn in some new stuff into the world and one of the thing i want to spawn is pretty big and needs a good amount of space away from the ocean/water like 15 or 20 radius and i was wondering how would i find such a position?

Is there some function or code i can use to find an x,y,z position with a certain distance away from the water/ocean and preferably a way to find random positions in specific biomes?

 

Edited by . . .
local offsets = {
    {6,0},
    {6,6},
    {-6,6},
    {6,-6},
    {-6,0},
    {0,6},
    {0,-6},
    {-6,-6},
}

local function CheckForWater(pt)
    for k, v in ipairs(offsets) do
        local water = TheWorld.Map:IsOceanTileAtPoint(pt.x + v[1],pt.y + v[2],pt.z)
        if water == true then
            return false
        end
    end
    local structures = TheSim:FindEntities(pt.x, pt.y, pt.z, 6, {"structure","birdblocker"})
    if #structures > 0 then
        return false
    end
    return true
end 

local offset = FindWalkableOffset(pos, math.random() * 360 * math.pi, math.random(400, 800), 500,nil,nil,CheckForWater)

This is some code that I used to spawn a chest somewhere but not too close to the ocean and without spawning on top of boulder or something else :D

You use FindWalkableOffset to find an offset from your position that has all the things you need.

FindWalkableOffset(position, start_angle, radius, attempts, check_los, ignore_walls, customcheckfn, allow_water, allow_boats)

This is the definition of FindWalkableOffset. The important bit for you is the customcheckfn.

I think you can use the same as I did with just the offsets made to a higher number.

As for the biomes, I think you can add a check like this:

local tile = TheWorld.Map:GetTileAtPoint(pt)
if tile ~= "whatever_tile_of_the_biome_you_want" then
	return false
end

The tiles can be found in constants.lua

Edited by Monti18
  • Thanks 1

@Monti18 Thanks a lot! It seems to work most of the time which's great!

The only thing is rarely my thing still spawns too close to the water even with all the offsets being at 30 instead of 6? Do I have to make it a huge number like 100 for that not to happen? And thanks a lot :D!

ps: it was in a world without caves if that matters

Edited by . . .

You're welcome!

I think the problem is that there is too much distance between your starting point and the spawn point, I only added a few offsets so it's won't be as accurate if you get farther. If that's the case, something like this is probably better:

local function CheckForWater(pt)
	local ocean = FindNearbyOcean(pt,30)
	if ocean then 
		return false
	end
	local structures = TheSim:FindEntities(pt.x, pt.y, pt.z, 6, {"structure","birdblocker"})
	if #structures > 0 then
		return false
	end
	return true
end 

This is not tested, but I think it should work. If it doesn't, copy the function FindNearbyOcean, change the attempts of the FindValidPositionByFan function to a higher number, somethin like 60 or 180. More attempts means it will check more positions in the radius around the starting point.

You can also try to add another check of the ocean at lower distances if there are some problems that still persist.

Hope that will make it work now! :)

Edited by Monti18
  • Thanks 1

@Monti18

Hey again! I'm so sorry to bother you again but I must be dumb or something no matter how much I look at your post of increasing the FindValidPositionByFan

function FindNearbyOcean(position, range)
    local finaloffset = FindValidPositionByFan(math.random() * 2 * PI, range or 8, 8, function(offset)
        local x, z = position.x + offset.x, position.z + offset.z
        return TheWorld.Map:IsOceanAtPoint(x, 0, z)
            and not TheWorld.Map:IsPointNearHole(Vector3(x, 0, z))
    end)
    if finaloffset ~= nil then
        finaloffset.x = finaloffset.x + position.x
        finaloffset.z = finaloffset.z + position.z
        return finaloffset
    end
end

and think what I have to do I can't figure it out how I would increase it looks so complicated it makes my brain just stop thinking

there's a problem that sometimes the thing i want to spawn doesn't even spawn in the world which i guess needs to change the FindValidPositionByFan to make it check more do you know what I would change? sorry to bother

 

This is the current code for finding a place to spawn the thing too

local function CheckForThing(pt)
	local ocean = GLOBAL.FindNearbyOcean(pt, 20)
	if ocean then return false end
	local structures = TheSim:FindEntities(pt.x, pt.y, pt.z, 15, {"structure", "birdblocker", "antlion_sinkhole_blocker"})
    if #structures > 0 then return false end
	
	local ents = TheSim:FindEntities(pt.x, pt.y, pt.z, 15, nil, nil, {"tree", "plant", "renewable", "tentacle"})
    for k, v in pairs(ents) do if v ~= nil then v:Remove() end end
	
    return true
end

local function SpawnThing(inst)
	local pos = inst:GetPosition()
	local offset = GLOBAL.FindWalkableOffset(pos, math.random() * 360 * math.pi, math.random(400, 800), 500, nil, nil, CheckForThing)
	if offset then
		local spawn_pos = pos + offset
		local a = SpawnPrefab("giantmeteor")
		a.Transform:SetPosition(spawn_pos:Get())		
	end
end

 

local function IsOceanHere(position, range)
    local finaloffset = FindValidPositionByFan(math.random() * 2 * PI, range or 8, 60, function(offset)
        local x, z = position.x + offset.x, position.z + offset.z
        return TheWorld.Map:IsOceanAtPoint(x, 0, z)
            and not TheWorld.Map:IsPointNearHole(Vector3(x, 0, z))
    end)
    if finaloffset ~= nil then
        finaloffset.x = finaloffset.x + position.x
        finaloffset.z = finaloffset.z + position.z
        return finaloffset
    end
end

The argument behind the range is the attempts argument, this is the one you need to increase. I increased it here to 60. 

You need to have a very open position for this to work, and if you try it, you will always have the same distance from your starting point. To get more different postitions, I would try this:

local function CheckForThing(pt)
	local ocean = IsOceanHere(pt, 20)
	if ocean then return false end
	local structures = TheSim:FindEntities(pt.x, pt.y, pt.z, 15, {"structure", "birdblocker", "antlion_sinkhole_blocker"})
    if #structures > 0 then return false end
	
	local ents = TheSim:FindEntities(pt.x, pt.y, pt.z, 15, nil, nil, {"tree", "plant", "renewable", "tentacle"})
    for k, v in pairs(ents) do if v ~= nil then v:Remove() end end
	
    return true
end

local tries = 0
local MAX_TRIES = 10

local function SpawnThing(inst)
	local pos = inst:GetPosition()
	local offset = GLOBAL.FindWalkableOffset(pos, math.random() * 360 * math.pi, math.random(400, 800), 500, nil, nil, CheckForThing)
	if offset then
		tries = 0
		local spawn_pos = pos + offset
		local a = SpawnPrefab("giantmeteor")
		a.Transform:SetPosition(spawn_pos:Get())		
	else
		tries = tries + 1
		if tries < MAX_TRIES then
			SpawnThing(inst)
		end
	end
end

This will make it try to spawn your thing 10 times, which will be at different radius as you run math.random each time. You can increase the MAX_TRIES if you need it to run more often.

I hope that it will work now :D

Edited by Monti18
  • Thanks 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...