Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Hello!
- This will show you how to implement an improved mobile aiming system in your PA game.
- In this system, the move is instead cast on-release.
- Camera rotations of more than 10 degrees will not trigger a move (unless it was a brief tap).
- Very quick presses will always trigger a move.
- In all, this makes for a less annoying aiming system.
- Thank you for using this!
- To edit:
- All edits to the game are made through scripts, so just follow the text guides.
- We will be editing StarterGui > SkillsGui > WeaponsController, and performing edits to all ClientModules.
- I will show you an easy way to do the second one.
- A demonstration of where to paste everything will be present at the bottom of the guide.
- 1. In StarterGui > SkillsGui > WeaponsController, find the function labelled Use.
- Change the header from this:
- function Use()
- to this:
- function Use(aimedDirection)
- 2. In the same function, find where it declares a variable as "local returned".
- Then, you change that line from this:
- local returned = func(game.Players.LocalPlayer, DeviceType, CallServer, CallWeaponServer)
- to this:
- local returned = func(game.Players.LocalPlayer, DeviceType, CallServer, CallWeaponServer, (aimedDirection and aimedDirection or game.Players.LocalPlayer:GetMouse().Hit.LookVector))
- Basically all this does is it takes the aimDirection parameter that we put in in Step 1, and passes it to a ClientModule whenever a move is used.
- 3. We are still in the same script. Scroll down to where it connects an event to UserInputService.InputBegan.
- Then, scroll down to the bottom of that function, where it says "elseif".
- Replace this (sorry about the indents):
- elseif input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
- if not gp then
- if selectedweapon ~= nil then
- Use()
- end
- end
- end
- with this:
- elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
- if not gp then
- if selectedweapon ~= nil then
- Use()
- end
- end
- elseif input.UserInputType == Enum.UserInputType.Touch then
- if not gp then
- if selectedweapon ~= nil then
- local startedAtTime = tick()
- local startedAtRotation = workspace.CurrentCamera.CFrame.LookVector
- local endedAtDirection
- local gotVerdict = false
- local OnRelease = UserInputService.InputEnded:Connect(function(endedInput)
- if endedInput.UserInputType == Enum.UserInputType.Touch then
- -- If the player has released their finger within 0.15 seconds of pressing, then count it as a click.
- -- Otherwise, see how far they've rotated their camera. If it's a small rotation, then count it as a click.
- -- (A small rotation is a change within 10 degrees.)
- local playerClicked = false
- if tick()-startedAtTime<0.15 then
- playerClicked = true
- else
- local endedAtRotation = workspace.CurrentCamera.CFrame.LookVector
- -- :Dot checks how much two Vectors match in direction.
- -- If they face the same way, it returns 1. If they're perpendicular, then 0. Opposite directions is -1.
- if startedAtRotation:Dot(endedAtRotation) >= 80/90 then
- playerClicked = true
- end
- end
- if playerClicked then
- local screenCoord = endedInput.Position
- endedAtDirection = workspace.CurrentCamera:ViewportPointToRay(screenCoord.X, screenCoord.Y).Direction
- -- This is basically the same as plr:GetMouse().Hit.LookVector
- end
- gotVerdict = true
- end
- end)
- repeat task.wait() until gotVerdict == true
- OnRelease:Disconnect()
- if endedAtDirection then Use(endedAtDirection) end
- end
- end
- end
- end
- debounce = true
- end)
- Congratulations! That's the important part of the code that makes the aiming actually good on mobile.
- However, the game currently doesn't recognize the direction we released at as our desired aim angle.
- Basically, if we were walking and using HydroPump (meaning we have one finger on the joystick)...
- then half the time, the game would aim it at the ground, because that's where it detects our "mouse."
- This is why we need to edit every ClientModule to use the passed aimDirection.
- 4. So, how are we going to edit all 167+ attack scripts in your game?
- Well, we will take advantage of the fact that it's all copypasted in order to edit all of them simultaneously.
- First, create a new Baseplate and paste your ClientModules Folder there.
- This is just a precaution to make sure we don't change anything erroneously with our "global edit".
- Then, in that Baseplate, press Ctrl+Shift+F.
- Open the drop-down menu on the new window so that you have the option to search and replace.
- Type this in "find" field:
- function Use(plr, device, CS, CWS)
- And then this in the "replace" field:
- function Use(plr, device, CS, CWS, aimDirection)
- Then, click Replace All. We have to do this one more time. Delete both text fields.
- Type this in the "find" field:
- plr:GetMouse().hit.lookVector
- And then this in the "replace" field:
- aimDirection
- Now, Replace All yet again.
- 5. Lastly, paste your newly edited ClientModules folder back into your game.
- (The edits may not have saved depending on your settings. I suggest publishing the Baseplate to prevent this.)
- Now, you've implemented the system completely! Good job!
- Paste Demonstration for WeaponsController:
- (note that this has remnants of the no-attack-latency system, so it's not completely vanilla)
- game.ReplicatedStorage:WaitForChild("WEAPONFUNCTION")
- local k = 0
- function CallWeaponServer(...)
- return game.ReplicatedStorage.WEAPONFUNCTION:InvokeServer(...)
- end
- game.ReplicatedStorage:WaitForChild("FUNCTION")
- function CallServer(...)
- return game.ReplicatedStorage.FUNCTION:InvokeServer(...)
- end
- local DeviceType = nil
- local selectedweapon = nil
- local weapons = {}
- k = CallServer("GetK", "sanspopsicles")
- local gui = script.Parent
- local weaponsEvent = game:GetService("ReplicatedStorage"):WaitForChild("WeaponStatsEvent")
- function Weap(t, id)
- if t == "E" then
- gui.Holder["Skill"..tostring(id)].ReloadBar.Visible = true
- gui.Holder["Skill"..tostring(id)].ReloadFullBar.Visible = true
- gui.Holder["Skill"..tostring(id)].ReloadText.Visible = true
- elseif t == "UE" then
- gui.Holder["Skill"..tostring(id)].ReloadBar.Visible = false
- gui.Holder["Skill"..tostring(id)].ReloadFullBar.Visible = false
- gui.Holder["Skill"..tostring(id)].ReloadText.Visible = false
- end
- end
- function UpdateGui()
- for _, i in pairs(script.CurrentClientModules:GetChildren()) do i:Destroy() end
- for i = 1, 4 do
- if weapons[i] then
- if script.ClientModules:FindFirstChild(weapons[i]) then
- script.ClientModules[weapons[i]]:Clone().Parent = script.CurrentClientModules
- end
- end
- local frame = gui.Holder:FindFirstChild("Skill"..tostring(i))
- frame.SkillName.Text = weapons[i] or " "
- end
- end
- function UpdateGuiDevice()
- local function Check(loc)
- for _, i in pairs(loc:GetChildren()) do
- if i:IsA'Frame' then
- Check(i)
- else
- if i.Name == DeviceType.."HotKeys" then
- i.Visible = true
- elseif string.find(i.Name, "HotKeys") then
- i.Visible = false
- end
- end
- end
- end
- Check(gui.Holder)
- end
- function SkillCUC(t, i)
- if t == "C" then
- local frame = gui.Holder:FindFirstChild("Skill"..tostring(i))
- frame.SkillName.TextColor3 = Color3.new(47/255, 187/255, 200/255)
- elseif t == "UC" then
- local frame = gui.Holder:FindFirstChild("Skill"..tostring(i))
- frame.SkillName.TextColor3 = Color3.new(1,1,1)
- end
- end
- function SetupGui()
- script.Parent.Holder.Visible = true
- for i = 1, 4 do
- local frame = gui.Holder:FindFirstChild("Skill"..tostring(i))
- frame.SkillName.Text = weapons[i] or " "
- frame.SkillName.MouseButton1Click:connect(function()
- if weapons[i] ~= nil then
- SelectWeapon(i)
- end
- end)
- end
- end
- local debounce = {[1] = true, [2] = true, [3] = true, [4] = true}
- local debounceuse = true
- local LastUse = tick()
- local SLPvalue = 0
- local PvPvalue = 0
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF. Please paste the below line over its original version.
- function Use(aimedDirection)
- -- This is what the original line said:
- -- function Use()
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- local curweaponf = selectedweapon
- if debounceuse then
- debounceuse = false
- if debounce[curweaponf] then
- if PvPvalue == 1 then
- if SLPvalue == 0 and game.Players.LocalPlayer.Character and game.Players.LocalPlayer.Character.Humanoid.Health > 0 then
- if script.CurrentClientModules:FindFirstChild(weapons[curweaponf]) then
- game.Players.LocalPlayer.PlayerGui.GameGui.LocalScript.WeaponUsed.Value = true
- debounce[curweaponf] = false
- local tab = require(script.CurrentClientModules[weapons[curweaponf]])
- local func = tab[1]
- local reload = tab[2]
- coroutine.wrap(function()
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF. Please paste the below line over its original version.
- local returned = func(game.Players.LocalPlayer, DeviceType, CallServer, CallWeaponServer,
- (aimedDirection and aimedDirection or game.Players.LocalPlayer:GetMouse().Hit.LookVector))
- -- This is what the original line said:
- -- local returned = func(game.Players.LocalPlayer, DeviceType, CallServer, CallWeaponServer)
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- if returned ~= nil then
- reload = returned
- end
- LastUse = tick()
- --print(reload)
- end)()
- coroutine.wrap(function()
- local i = 0
- while i < reload do
- if 0.8 * (i / (reload)) < 0.1 then
- gui.Holder["Skill"..tostring(curweaponf)].ReloadBar:TweenSize(UDim2.new(0.1, 0, -0.15, 0), "Out", "Quad", 1, true)
- else
- gui.Holder["Skill"..tostring(curweaponf)].ReloadBar:TweenSize(UDim2.new(0.8 * (i / (reload)), 0, -0.15, 0), "Out", "Quad", 1, true)
- end
- gui.Holder["Skill"..tostring(curweaponf)].ReloadText.Text = "Reloading!"
- i = i + wait(1/60)
- end
- gui.Holder["Skill"..tostring(curweaponf)].ReloadBar:TweenSize(UDim2.new(0.8, 0, -0.15, 0), "Out", "Quad", 1, true)
- gui.Holder["Skill"..tostring(curweaponf)].ReloadText.Text = "Ready!"
- debounce[curweaponf] = true
- end)()
- SkillCUC("UC", curweaponf)
- selectedweapon = nil
- end
- end
- else
- game.StarterGui:SetCore("SendNotification", {
- Title = "Skills";
- Text = "Turned the PvP on!";
- Duration = 2;
- })
- CallServer("ChangeStat", k, "PvP", 1)
- end
- end
- wait(2)
- debounceuse = true
- end
- end
- function SelectWeapon(num)
- if weapons[num] ~= nil then
- if selectedweapon == num then
- selectedweapon = nil
- SkillCUC("UC", num)
- else
- selectedweapon = num
- SkillCUC("C", num)
- if num ~= 1 then SkillCUC("UC", 1) end
- if num ~= 2 then SkillCUC("UC", 2) end
- if num ~= 3 then SkillCUC("UC", 3) end
- if num ~= 4 then SkillCUC("UC", 4) end
- end
- end
- end
- game.Players.LocalPlayer.Backpack.ChildAdded:connect(function(i)
- if script.ClientModules:FindFirstChild(i.Name) then
- script.ClientModules[i.Name]:Clone().Parent = script.CurrentClientModules
- end
- if weapons[1] == nil then table.insert(weapons, 1, i.Name) Weap("E", 1)
- elseif weapons[2] == nil then table.insert(weapons, 2, i.Name) Weap("E", 2)
- elseif weapons[3] == nil then table.insert(weapons, 3, i.Name) Weap("E", 3)
- elseif weapons[4] == nil then table.insert(weapons, 4, i.Name) Weap("E", 4)
- end
- UpdateGui()
- end)
- game.Players.LocalPlayer.Backpack.ChildRemoved:connect(function(i)
- if script.CurrentClientModules:FindFirstChild(i.Name) then
- script.CurrentClientModules[i.Name]:Destroy()
- end
- if weapons[1] == i.Name then weapons[1] = nil Weap("UE", 1) if selectedweapon == 1 then selectedweapon = nil SkillCUC("UC", 1) end
- elseif weapons[2] == i.Name then weapons[2] = nil Weap("UE", 2) if selectedweapon == 2 then selectedweapon = nil SkillCUC("UC", 2) end
- elseif weapons[3] == i.Name then weapons[3] = nil Weap("UE", 3) if selectedweapon == 3 then selectedweapon = nil SkillCUC("UC", 3) end
- elseif weapons[4] == i.Name then weapons[4] = nil Weap("UE", 4) if selectedweapon == 4 then selectedweapon = nil SkillCUC("UC", 4) end
- end
- UpdateGui()
- end)
- repeat wait() until weapons[1] ~= nil
- SetupGui()
- local debounce = true
- local UserInputService = game:GetService("UserInputService")
- UserInputService.InputBegan:connect(function(input, gp)
- if debounce then
- debounce = false
- if input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Keyboard then
- -- EXECUTING
- if input.KeyCode == Enum.KeyCode.Q or input.KeyCode == Enum.KeyCode.ButtonL1 then
- if weapons[1] ~= nil then
- SelectWeapon(1)
- end
- elseif input.KeyCode == Enum.KeyCode.E or input.KeyCode == Enum.KeyCode.ButtonL2 then
- if weapons[2] ~= nil then
- SelectWeapon(2)
- end
- elseif input.KeyCode == Enum.KeyCode.R or input.KeyCode == Enum.KeyCode.ButtonR2 then
- if weapons[3] ~= nil then
- SelectWeapon(3)
- end
- elseif input.KeyCode == Enum.KeyCode.T or input.KeyCode == Enum.KeyCode.ButtonR1 then
- if weapons[4] ~= nil then
- SelectWeapon(4)
- end
- elseif input.KeyCode == Enum.KeyCode.ButtonX then
- if selectedweapon ~= nil then
- Use()
- end
- end
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
- if not gp then
- if selectedweapon ~= nil then
- Use()
- end
- end
- elseif input.UserInputType == Enum.UserInputType.Touch then
- if not gp then
- if selectedweapon ~= nil then
- local startedAtTime = tick()
- local startedAtRotation = workspace.CurrentCamera.CFrame.LookVector
- local endedAtDirection
- local gotVerdict = false
- local OnRelease = UserInputService.InputEnded:Connect(function(endedInput)
- if endedInput.UserInputType == Enum.UserInputType.Touch then
- -- If the player has released their finger within 0.15 seconds of pressing, then count it as a click.
- -- Otherwise, see how far they've rotated their camera. If it's a small rotation, then count it as a click.
- -- (A small rotation is a change within 10 degrees.)
- local playerClicked = false
- if tick()-startedAtTime<0.15 then
- playerClicked = true
- else
- local endedAtRotation = workspace.CurrentCamera.CFrame.LookVector
- -- :Dot checks how much two Vectors match in direction.
- -- If they face the same way, it returns 1. If they're perpendicular, then 0. Opposite directions is -1.
- if startedAtRotation:Dot(endedAtRotation) >= 80/90 then
- playerClicked = true
- end
- end
- if playerClicked then
- local screenCoord = endedInput.Position
- endedAtDirection = workspace.CurrentCamera:ViewportPointToRay(screenCoord.X, screenCoord.Y).Direction
- -- This is basically the same as plr:GetMouse().Hit.LookVector
- end
- gotVerdict = true
- end
- end)
- repeat task.wait() until gotVerdict == true
- OnRelease:Disconnect()
- if endedAtDirection then Use(endedAtDirection) end
- end
- end
- end
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- debounce = true
- end
- end)
- local UIS = game:GetService("UserInputService")
- if UIS.GamepadEnabled then
- DeviceType = "Gamepad"
- UpdateGuiDevice()
- elseif UIS.MouseEnabled then
- DeviceType = "Pc"
- UpdateGuiDevice()
- elseif UIS.TouchEnabled then
- DeviceType = "Mobile"
- UpdateGuiDevice()
- end
- UIS.GamepadConnected:connect(function(GPN)
- if GPN == Enum.UserInputType.Gamepad1 then
- DeviceType = "Gamepad"
- UpdateGuiDevice()
- end
- end)
- UIS.GamepadDisconnected:connect(function(GPN)
- if GPN == Enum.UserInputType.Gamepad1 then
- if UIS.MouseEnabled then
- DeviceType = "Pc"
- UpdateGuiDevice()
- elseif UIS.TouchEnabled then
- DeviceType = "Mobile"
- UpdateGuiDevice()
- end
- end
- end)
- spawn(function()
- local CurHP = CallServer("GetHP")
- local LastHPChange = tick()
- while wait(1) do
- local HP = CallServer("GetHP")
- if HP < CurHP then LastHPChange = tick() end
- CurHP = HP
- if tick() - LastUse > 6 and tick() - LastHPChange > 6 then
- CallServer("HealPlayer", 10)
- LastUse = tick()
- end
- end
- end)
- weaponsEvent.OnClientEvent:Connect(function(...)
- local args = {...}
- --[1]: the name of a stat
- --[2]: the stat's new value
- if args[1]=="SLP" then
- SLPvalue = args[2]
- elseif args[1]=="PvP" then
- PvPvalue = args[2]
- end
- end)
- Paste Demonstration for a ClientModule script:
- (note that this is just an example for you to see if you did it right)
- -- SETTINGS
- local reload = 4
- local name = "Absorb"
- -- SCRIPT
- local debounce = true
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- function Use(plr, device, CS, CWS, aimDirection)
- -- Original line:
- -- function Use(plr, device, CS, CWS)
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- if debounce then
- debounce = false
- local target = nil
- if CS("GetStat", "NewAim") == 1 then
- -- NEW STUFF
- -- NEW STUFF
- -- NEW STUFF
- target = aimDirection * 120
- -- Original line: target = plr:GetMouse().hit.lookVector * 120
- -- Note that the 120 varies from move to move.
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- -- END OF NEW STUFF
- else
- target = plr.Character.Torso.CFrame.lookVector * 120
- end
- CWS("RunWeapon", name, target)
- wait(0.5)
- debounce = true
- end
- end
- return {Use, reload}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement