how do I check if a vector3 value is in a region3 value in Roblox Studio? - roblox

I am making a game with a building system. I am trying to add land ownership to my game by creating a region around a person's tent. The issue is that I have no idea how to check if another player is placing something in another player's land. Does anyone have an answer?

A Vector3 is essentially just a coordinate with an X, Y, and Z component. The assumption here is that its origin is at (0, 0, 0).
A Region3 is an axis-aligned bounding box that is constructed based on a minimum Vector3 coordinate and a maximum Vector3 coordinate.
A Vector3 can be considered inside the Region3 if its magnitude is greater than the minimum coordinate and less than the maximum coordinate.
Since the Region3 gives you the center of the region as its CFrame property, you can calculate the extents of the Region3 using its Size divided in half, and then check if the Vector3 falls inside that region.
local function isVect3InRegion3(vector, region)
-- validate input
assert(typeof(vector) == "Vector3")
assert(typeof(region) == "Region3")
-- get the dimensions of the region
local regionCenter = region.CFrame.Position
local regionHalfSize = region.Size * 0.5
-- calculate the extents of the region
local lowerLeftCorner = regionCenter - regionHalfSize
local upperRightCorner = regionCenter + regionHalfSize
-- check if the vector is inside the extents
local isBeyondLeftCorner = (vector.X >= lowerLeftCorner.X) and
(vector.Y >= lowerLeftCorner.Y) and
(vector.Z >= lowerLeftCorner.Z)
local isBeforeRightCorner = (vector.X <= upperRightCorner.X) and
(vector.Y <= upperRightCorner.Y) and
(vector.Z <= upperRightCorner.Z)
return isBeyondLeftCorner and isBeforeRightCorner
-- NOTE : comparing individual values above is less expensive than
-- return vector.Magnitude >= lowerLeftCorner.Magnitude and
-- vector.Magnitude <= upperRightCorner.Magnitude
end

Related

How to check if the X or Y component of a Vector3 has increased or decreased

I have a Vector3 that contains information about a gameOjects position in worldspace, I’m wondering if it’s possible to query the x and y component to see if it’s changed?
Cheers in advance for your help
You can query an object's position at any time using gameObject.transform.position, which will give you the position in world space. If you save that position to a variable, you can check if and how it changed in the next frame:
Vector3 oldPosition; // the Vector you want to compare to
Vector3 delta = transform.position - oldPosition;
// delta now contains how much the position has changed since oldPosition

How to place part on top of the terrain in Roblox?

I have a terrain generated in my ROBLOX game (hills, flats, rivers) and I have a model of a tree. Tree is just a group of "bricks" so it looks like kind-of a Minecraft tree.
Now I want to clone that tree programatically at run-time and I need to place that copy (clone) somewhere else on the map.
All of this is easy. But after I give my clone new coordinates (I keep coordinate for Y axis the same like my original tree), it's placed or in the air, or it is under the surface of my terrain.
How do I place it directly ON the terrain?
Or how do I get the Y-axis coordinate of that particular place on map?
Thanks!
EDIT
While answer from #Kylaaa is perfectly complete, here I include my solution, while I needed also an information about the material of the terrain in that place (rocks / grass / etc.)
function FindTerrainHeight(pos)
local VOXEL_SIZE = 4
local voxelPos = workspace.Terrain:WorldToCell(pos)
// my region will start at -100 under the desired position and end in +100 above desired position
local voxelRegion = Region3.new((voxelPos - Vector3.new(0,100,0)) * VOXEL_SIZE, (voxelPos + Vector3.new(1,100,1)) * VOXEL_SIZE)
local materialMap, occupancyMap = workspace.Terrain:ReadVoxels(voxelRegion, VOXEL_SIZE)
local steps = materialMap.Size.Y // this is actually 200 = height of the region
// now going from the very top of the region downwards and checking the terrain material
// (while it's AIR = no terrain found yet)
for i = steps, 1, -1 do
if (materialMap[1][i][1] ~= Enum.Material.Air) then
materialMap[1][i][1] ---> this is the material found on surface
((i-100) * VOXEL_SIZE) ---> this is the Y coordinate of the surface in world coordinates
end
end
return false
end
EDIT 2
So it turns out that #Kylaaa's answer solves everything. It includes also terrain material! As 4th item in the tuple. It means my solution is too complicated with no reason. Use his solution.
Try raycasting downward from your starting point until you find the terrain. game.Workspace:FindPartOnRayWithWhitelist() is great for this!
-- choose some starting point in world space
local xPos = 15
local yPos = 20
local zPos = 30
-- make a ray and point it downward.
-- NOTE - It's unusual, but you must specify a magnitude for the ray
local origin = Vector3.new(xPos, yPos, zPos)
local direction = Vector3.new(0, -100000, 0)
local ray = Ray.new(origin, direction)
-- search for the collision point with the terrain
local whitelist = { game.Workspace.Terrain }
local ignoreWater = true
local _, intersection, surfaceNormal, surfaceMaterial = game.Workspace:FindPartOnRayWithWhitelist(ray, whitelist, ignoreWater)
-- spawn a part at the intersection.
local p = Instance.new("Part")
p.Anchored = true
p.Size = Vector3.new(1, 1, 1)
p.Position = intersection -- <---- this Vector3 is the intersection point with the terrain
p.Parent = game.Workspace
If your model is moving around in unusual ways when you call SetPrimaryPartCFrame(), be aware that Roblox physics does not like interpenetrating objects. So models will often get pushed upwards until they are no longer interpenetrating. Objects that are CanCollide = false will not have this issue, but they will also fall through of the world if they are not Anchored or welded to a part is set to CanCollide = true.

Find collision time given distance and speed

Suppose I have an object A at position x = 0 and object B at position x = 16.
Suppose A have this code:
public class Move : MonoBehaviour
{
float speed = 0.04f;
Update()
{
transform.Translate(speed, 0, 0);
}
}
My question is: how to evaluate how many seconds (precisely) will it take for A to collide with B?
If I apply the formula S = S0 + vt, it won't work correctly, because I don't know how to measure how many frames it will pass in a second to exactly measure what speed is.
First of all you shouldn't do that. Your code is currently framerate-dependent so the object moves faster if you have a higher framerate!
Rather use Time.deltaTime
This property provides the time between the current and previous frame.
to convert your speed from Unity Units / frame into Unity Units / second
transform.Translate(speed * Time.deltaTime, 0, 0);
this means the object now moves with 0.04 Unity Units / second (framerate-independent).
Then I would say the required time in seconds is simply
var distance = Mathf.Abs(transform.position.x - objectB.transform.position.x);
var timeInSeconds = distance / speed;
Though .. this obviously still assumes by "collide" you mean at the same position (at least on the X axis) .. you could also take their widths into account since their surfaces will collide earlier than this ;)
var distance = Mathf.Abs(transform.position.x - objectB.transform.position.x) - (objectAWidth + objectBWidth);
var timeInSeconds = distance / speed;

Unity3D - Calculating t-value position on orbit

I'm using a script that i found online that uses a kdTree to calculate the nearest point to an object on the surface of a mesh.
I have the following code in the OnDrawGizmos method that allows me to draw a circle that will orbit the surface of the object.
x = target.transform.position.x + ((Mathf.Cos(tValue)) * (radius));
z = target.transform.position.z + ((Mathf.Sin(tValue)) * (radius));
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(new Vector3(x, y, z), 0.06f);
On the the object i am orbiting the "tValue" ranges from 0 to 6.3 to do a full orbit. My problem is that i am trying to calculate the tValue in the range 0-6.3 of an object that is near the central object. I have used my kdTree system to calculate the vector3 position on the surface of the object and it lines up perfectly.
I calculate the radius used in both the above and below equation with:
Vector3 RadiusDirection = (Vector3.ProjectOnPlane(orbitingSurfaceMeshPos, planet.transform.up) - Vector3.ProjectOnPlane(planet.transform.position, planet.transform.up));
float radius = RadiusDirection.magnitude;
However, when i try to calculate the t-value, i get a completely different value. I figured i could just "reverse" the "equation" and so i've been doing:
float temp = orbiting.z - planet.transform.position.z;
temp = temp / radius;
calculatedTvalue = (Mathf.Asin(temp));
What could i be doing wrong? I have tested my "reversing equation" in an empty scene and new script and it worked fine, if i just took the result of the orbit position calculation and directly reversed it. However, it doesn't work in my game.

Instantiate gameobject between 2 objects in unity 3d

I have 2 objects. It will be in various direction and distance.
How can i instantiate objects between them with a specific distance.
var centerLocation : Vector3 = Vector3.Lerp(object2.transform.position - object1.transform.position, 0.5);
Vector3.Lerp will determine the Vector3 location between 2 Vector3s at a specified percentage. 0.5 = 50%.
My suggestion would be to calculate the vector between the two objects, like this
Vector3 objectLine = (object2.transform.position - object1.transform.position);
Store the magnitude of that vector
float distance = objectLine.magnitude;
Then, normalise the vector;
objectLine = objectLine.normalized;
Iterate through the line, instanciating the object you want to create a specific distances
Vector3 creationPoint = object1.transform.position;
float creationPointDistance = (object1.transform.position -
object1.transform.position);
while(creationPointDistance < distance)
{
creationPoint += objectLine * NEW_OBJECT_DISTANCE;
creationPointDistance = (object1.transform.position -
object1.transform.position);
if(creationPointDistance < distance)
{
objects.Add((GameObject)Instanciate(newObject, creationPoint,
new Vector3(0.0f,0.0f,0.0f)));
}
}
What that will do is set the initial point to be object1's position. It will then move a set distance along the vector between object 1 and object 2, check it's within the two objects, and if it is, instanciate the object, storing it in a list of gameobjects.
That hopefully should do it. I don't have Unity (or any IDE) in front of me to check the syntax.