RTS game movement system

How could I create a select and movement system for an RTS game?

1 Like

Please provide more information in your topic. What is an ‘RTS game’? What look are you trying to accomplish? What have you tried so far?

1 Like

This is a pretty complex question but I will try to answer as best I can.

To create a select and movement system for an RTS game, first you need a script that will spawn in the units.

When you have the units spawn, these units should be referenceable by a table. With this created, you could set a unique id Attribute onto the unit model which we can use to identify when we select it.

Now we need a script that uses mouse/touch input to cast a ray which will search for unit models. Once hit, find the unique ID attribute of the model and store that in a current selected value.

This script should know that if we have a current selected value and we click somewhere that doesn’t have any units in the way, we send the server the location of the hit and tween the position of the unit to the location of the hit.

This is a naïve implementation as we are not considering how units will collide with each other or selecting multiple units or considering the network cost of replication but this could help you get you started.

1 Like

Not sure how that can be done, I was thinking of a selection box type of thing that most RTS games use and somehow check if the units are in the selected area, I’m not sure how I could do this though.

I actually tried something like this a while ago. I first connected to the player’s mouse Button2Down event and used it to get the mouse’s starting position. Next, I connected to the RunService heartbeat event within the same block, which updates the mouse’s ending position every frame along with the corresponding GUI (which I didn’t include here). To retrieve the parts between the two mouse positions, I created a region and used GetPartBoundsInBox (you might use something else if it’s a model). Below is an example of this.

local players = game:GetService("Players")
local run = game:GetService("RunService")

local mouse = players.LocalPlayer:GetMouse()

local currentSelection = {}
local endingPosition = Vector3.zero
local holding = nil
local parameters = OverlapParams.new()
local selectedParts = {}
local startingPosition = Vector3.zero
-- Modify the overlap parameters.
parameters.FilterDescendantsInstances = {workspace.Selectable} -- The model/folder that contains only selectable parts.
parameters.CollisionGroup = "Default"
parameters.FilterType = Enum.RaycastFilterType.Include
parameters.MaxParts = 6 -- Max number of parts allowed to be selected.
-- Connect to the Button2Down event.
mouse.Button2Down:Connect(function()
	local newRegion = nil
	startingPosition = mouse.Hit.Position
	
	table.clear(selectedParts)
	-- Connect to the Heartbeat event.
	holding = run.Heartbeat:Connect(function()
		endingPosition = mouse.Hit.Position
		-- Create the region.
		if startingPosition.X < endingPosition.X then
			newRegion = Region3.new(endingPosition, startingPosition)
		else
			newRegion = Region3.new(startingPosition, endingPosition)
		end
		-- If the region actually exists.
		if newRegion then
			local regionSize = newRegion.Size
			currentSelection = workspace:GetPartBoundsInBox(newRegion.CFrame * CFrame.new(1, 0, 1), Vector3.new(math.abs(regionSize.X), 10, math.abs(regionSize.Z)), parameters)
			-- This is where you would update the GUI's and part's selection box.
			-- If you aren't going to do this, the code above can be moved to the event below.
		end
	end)
end)
-- Connect to the Button2Up event.
mouse.Button2Up:Connect(function()
	if holding then
		holding:Disconnect()
		-- Add the selected parts to the array.
		for _, obj in pairs(currentSelection) do
			table.insert(selectedParts, obj)
		end
		print(selectedParts)
	end
end)