I’m trying to make water currents for my boat game. Right now, these are represented with a part that adds a VectorForce to any part of a boat that touches it, and removes it again once the part stops touching.
This works, except that sometimes nothing happens? I’ve confirmed that the VectorForces really do get added and configured correctly, it’s just that the boat doesn’t seem to be affected. Pushing the boat by walking into it with my character seems to “activate” the VectorForces, but only until the boat touches the next “current part”.
I’m looking into this issue, it seems to be a bug by no fault of your own.
Will update with more information in a little while and we can look into making a bug report.
In the meantime, can you share a repro of your issue? I think I’ve found a way to reproduce something that sounds like what you’re seeing but I’d like to make sure.
Edit: was a fluke, I need to see what you’re doing so we can see if this is a bug or not.
Are you ensuring the magnitude of force is appropriate? Are you sure the drag created by water (assuming you are using terrain water) is being adequately compensated for?
Yes, I’m certain of this. I tweaked the water friction and Force magnitude to be sufficient to move the boat at what I feel is a fun/realistic pace while inside the current. It works correctly, except when it doesn’t
--Disabled while waiting for SetupCollisionGroups
local TagHelper = require( game.ReplicatedStorage.TagHelper )
local RunService = game:GetService("RunService")
local TagService = game:GetService("CollectionService")
local Util = require( game.ReplicatedStorage.Util )
local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")
local Debris = game:GetService("Debris")
local touchingDict = {}
local forcesDict = {}
function boatPartStartedTouching(wavePart, touchingPart)
table.insert(touchingDict[wavePart], touchingPart)
touchingPart.Velocity = touchingPart.Velocity + Util.v3OnSphere(1)
local force = Instance.new("VectorForce")
force.Attachment0 = touchingPart.WaveForceAttachment
force.Attachment1 = wavePart.Attachment
force.RelativeTo = Enum.ActuatorRelativeTo.Attachment1
force.Force = Vector3.new(0, 0, -1) * 8 * 40
force.Name = "WaveForce"
force.Parent = touchingPart
forcesDict[wavePart][touchingPart] = force
end
function boatPartStoppedTouching(wavePart, touchingPart)
table.remove( touchingDict[wavePart], Util.indexOf(touchingDict[wavePart], touchingPart) )
local force = forcesDict[wavePart][touchingPart]
Debris:AddItem(force, 0)
forcesDict[wavePart][touchingPart] = nil
end
function createWave(wavePart)
touchingDict[wavePart] = {}
forcesDict[wavePart] = {}
wavePart.Touched:Connect(function(touchingPart)
if TagService:HasTag(touchingPart, "BoatPart") and not Util.indexOf(touchingDict[wavePart], touchingPart) then
boatPartStartedTouching(wavePart, touchingPart)
end
end)
wavePart.TouchEnded:Connect(function(touchingPart)
if TagService:HasTag(touchingPart, "BoatPart") and Util.indexOf(touchingDict[wavePart], touchingPart) then
boatPartStoppedTouching(wavePart, touchingPart)
end
end)
end
TagHelper:ApplyToAllTagged("Wave", createWave)
It’s obviously got a couple of dependencies, but you shouldn’t worry about those. The script itself works correctly, I’ve verified that the VectorForce objects really do get created, with the correct Attachment and Force properties.
manually put touch events on my waves and used presence of the force attachment to identify boats (remove tags)
explicit values for forces
Combined your dictionaries to keep track of name and value of forces generated by waves
unique key used by combining boat part name and wave name
all would need a unique name, which could be affected with a script
since all touching event have both objects and therefore their name it works
Simplified Repro
if(workspace:FindFirstChild("Baseplate")) then workspace.Baseplate:Destroy() end
local forces = {}
local function createWaves()
local waveparts = {}
local wave = Instance.new("Part",workspace)
wave.Size = Vector3.new(10,2,10)
wave.Position = Vector3.new(0,0,0)
wave.Anchored = true
wave.Name = "wave1"
wave.BrickColor = BrickColor.Black()
local wave2 = wave:Clone()
wave2.Parent = workspace
wave2.Position = Vector3.new(0,0,10)
wave.Name = "wave2"
wave2.BrickColor = BrickColor.Blue()
local wave3 = wave:Clone()
wave3.Parent = workspace
wave3.BrickColor = BrickColor.Red()
wave.Name = "wave3"
wave3.Position = Vector3.new(10,0,5)
local dir = Instance.new("Vector3Value", wave)
dir.Value = Vector3.new(0,0,1)
dir.Name = "Force"
dir = Instance.new("Vector3Value",wave2)
dir.Value = Vector3.new(1,0,0)
dir.Name = "Force"
dir = Instance.new("Vector3Value",wave3)
dir.Value = Vector3.new(1,0,0)
dir.Name = "Force"
table.insert(waveparts, wave)
table.insert(waveparts, wave2)
table.insert(waveparts, wave3)
for i, w in pairs(waveparts) do
createWave(w)
end
end
local function createBoat()
local boatFront = Instance.new("Part")
boatFront.Position= Vector3.new(0,2,0)
boatFront.Size = Vector3.new(1,1,1)
boatFront.Parent = workspace
boatFront.Name = "BoatFront"
local boatBack = Instance.new("Part")
boatBack.Position = Vector3.new(0,2,-1)
boatBack.Parent = workspace
boatBack.BrickColor = BrickColor.Green()
boatBack.Size = Vector3.new(1,1,1)
boatBack.Name = "BoatBack"
local weld = Instance.new("WeldConstraint",boatFront)
weld.Part0 = boatFront
weld.Part1 = boatBack
local attach1 = Instance.new("Attachment",boatFront)
attach1.Name = "WaveForceAttachment"
local attach2 = attach1:Clone()
attach2.Parent = boatBack
end
function boatPartStartedTouching(wavePart, touchingPart)
local force = Instance.new("VectorForce")
force.Attachment0 = touchingPart.WaveForceAttachment
force.Force = wavePart.Force.Value*45
force.RelativeTo = "World"
force.Name = touchingPart.Name..'+'..wavePart.Name
force.Parent = touchingPart
forces[touchingPart.Name..'+'..wavePart.Name] = force
print(force)
end
function boatPartStoppedTouching(wavePart, touchingPart)
-- table.remove(touchingDict[wavePart], touchingPart)
local force = forces[touchingPart.Name..'+'..wavePart.Name]
force:Destroy()
forces[touchingPart.Name..'+'..wavePart.Name] = nil
end
function createWave(wavePart)
wavePart.Touched:Connect(function(touchingPart)
if(touchingPart.WaveForceAttachment) then
boatPartStartedTouching(wavePart, touchingPart)
end
end)
wavePart.TouchEnded:Connect(function(touchingPart)
if(touchingPart.WaveForceAttachment) then
boatPartStoppedTouching(wavePart, touchingPart)
end
end)
end
createWaves()
createBoat()
Is this the general functionality you were wanting?
are your waves larger than boat parts or smaller? is the boat single block or multiple?
whats the max number of forces you will have on a single part?
Experimenting further with what you sent me, it appears the friction property of the boat parts is what’s causing it to be unaffected by VectorForces.
Try changing friction for boat parts and see if that solves the issue.
Changing friction for the water will create a nice momentum preserving effect, but it will diminish the water’s ability to move parts via the anchored + velocity trick.
I noticed that a flat boat consisting of an array of parts would only begin to be affected by the VectorForces when all / most of the parts contained a force, which for some reason tipped me off to try playing with friction.
It seems like the actual force applied to an assembly of multiple parts welded together is not equal to the actual force applied to a single part with the same size and physical properties as the assembly.
Either friction or force applied to parts in a rigid assembly seems incorrect.