I already tried looking up multiple solutions in the Roblox developer forums, but I only found some unfinished code or some code that didn't work with mine. The code in this picture makes my rig find the part and chase it until it's there. That works perfectly, but I've been trying to find a way for the rig to chase the nearest player instead. I've heard of magnitude, but I'm not sure how to implement it, I cant even make the rig chase a player in the first place.
First off, .magnitude is the "length of a vector". It is mostly used to find the distance in vector units from pointA to pointB. Hence, the distance from the 2 points would be (pointA.Position-pointB.Position).magnitude.
https://developer.roblox.com/en-us/articles/Magnitude
Now in order to chase the players, you can loop through all of the players and get the one your NPC will chase.
You can use a for loop and loop through game.Players:GetPlayers() then get their character: <v>.Character and then their HumanoidRootPart which has their position. If you wanted to have a range for your NPC or an 'aggro distance', this is where you can implement magnitude. You would first create a variable for your distance. Since we will be dealing with vector units, it should be in length of vectors. For example local aggroDistance = 30. When added to the code, this would mean that it would only track a player if they are within 30 studs. You would then put an if statement saying if (<NPC.HumanoidRootPart.Position-<players hrp position>).magnitude < aggroDistance then. Now you could use Pathfinding Service to move the NPC to the player by using PathfindingService:ComputeAsync(<NPC HumanoidRootPart Position, <player HumanoidRootPart Position>) :ComputeAsync() makes a path from the starting position (the first parameter) to the end position (the second parameter). <NPC Humanoid>:MoveTo(<player HumanoidRootPart Position>) then makes the NPC move to the player. In order to listen out for when the NPC has reached the end of the path it made in :ComputeAsync() you can do <NPC Humanoid>:MoveToFinished:Connect(function()) to run a function after it reached the end, or <NPC Humanoid>:MoveToFinished:Wait() to wait before computing the next path.
Tip: You might also want to check if the player has more than 0 health (if they are alive) so the NPC only moves to players who are alive. You can do this by adding a and <player>.Humanoid.Health > 0 in the if statement where you had your aggroDistance.
Please let me know if you have any questions.
Code Makeup:
aggroDistance variable < optional
while loop
if statement (can contain aggroDistance variable if you have one) and check player health
:ComputeAsync()
:MoveTo()
:MoveToFinished
if statement end
while loop end
Related
Been trying for a while now, not sure how to create a way to block players who don't have enough money to enter a zone and let players through who have enough money if not more.
I have a fully transparent part that i would like to act as the hitbox. I also have leaderstats set up and functioning.
If anyone could help, would be much appreciated :)
This is a great use-case for PhysicsService's CollisionGroups.
You can set up a CollisionGroup where objects in one group do not collide with those in another. It's often used for engine optimizations when a lot of objects simply don't need to check whether they need to collide with others, but you can definitely use them for this as well.
For this case, we'll set the door to be in one collision group, and every player that has unlocked the door will be in another. When they touch the door, it will check how much money they have, and if they have enough it will add each part of their character model into the unlocked group. This will allow their character model to phase right through the door.
So, in order to make this work, I added a Script to the Part that I was using for the door, and I added this code :
local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")
local COST_TO_ENTER = 10 -- update with the actual cost to open the door
local DOOR_GUID = game.HttpService:GenerateGUID()
local LOCKED_DOOR_ID = "LockedDoor" .. DOOR_GUID
local ALLOWED_PLAYERS_ID = "UnlockedPlayers" .. DOOR_GUID
-- find the door that we'll be unlocking
local door = script.Parent
-- create a collision group for the door, and another for players that have unlocked it
PhysicsService:CreateCollisionGroup(LOCKED_DOOR_ID)
PhysicsService:CreateCollisionGroup(ALLOWED_PLAYERS_ID)
-- add the door to the door's collision group
PhysicsService:SetPartCollisionGroup(door, LOCKED_DOOR_ID)
-- make it so that character models in the unlocked group don't collide with the door
PhysicsService:CollisionGroupSetCollidable(LOCKED_DOOR_ID, ALLOWED_PLAYERS_ID, false)
-- listen for when players touch the door to see if we should unlock it
door.Touched:Connect(function(otherPart)
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
if player.leaderstats.Money.Value >= COST_TO_ENTER then
-- if they have enough money, add their character model to the allowed player collision group
for _, part in ipairs(player.Character:GetDescendants()) do
if part:IsA("BasePart") then
PhysicsService:SetPartCollisionGroup(part, ALLOWED_PLAYERS_ID)
end
end
-- TODO : update the visuals of the door client-side so that players know that it is unlocked for them
end
end
end)
-- clean up if the door is getting deleted
door.Destroying:Connect(function()
PhysicsService:RemoveCollisionGroup(LOCKED_DOOR_ID)
PhysicsService:RemoveCollisionGroup(ALLOWED_PLAYERS_ID)
end)
This system doesn't persist whether a player has unlocked the door. So if your character dies, they may need to have enough money to get back in again. But it would be fairly simple to add a receipt system that keeps track which players have unlocked it, and re-add character models to the collision group upon respawn.
Not Enough Money
Enough Money
Every time the money changes, you would also change the CanCollide property of the hitbox. For example:
money.Changed:Connect(function()
hitbox.CanCollide = money.Value < 1024
end)
Here, the < operator will return true if the value of money is smaller than 1024, false otherwise. So if the amount of money is small, the block will collide with the player (not letting him/her in), but otherwise it doesn't.
You would do that in the client so that it only applies to that specific client, not all clients.
Protecting it from cheaters isn't necessary in this case, Roblox characters themselves are exploitable. If you're making an anti-cheat, you can make these zones impossible to enter by teleporting the player to their previous position if they enter when they shouldn't be able to.
I'm trying to implement AlphaZero on a new game using this repository. I'm not sure if they are handling the MCTS search tree correctly.
The logic of their MCTS implementation is as follows:
Get a "canonical form" of the current game state. Basically, switching player colors because the Neural Net always needs the input from the perspective of player with ID = 1. So if the current player is 1, nothing changes. If the current player is -1 the board is inverted.
Call MCTS search. Source code
In the expand-step of the algorithm, a new node is generated like this:
next_s, next_player = self.game.getNextState(canonicalBoard, 1, a)
next_s = self.game.getCanonicalForm(next_s, next_player)
"1" is the current player and "a" is the selected action. Since the input current player is always 1, next_player is always -1 and the board always gets inverted.
The problem occurs once we hit a terminal state:
Assume that action a ends the game
A next state (next_s) is returned by the "getNextState" method, next_player is set to -1. The board gets inverted one last time (1 becomes -1, -1 becomes 1). We now view the board from the perspective of the loser player. That means that a call to getGameEnded(canonicalBoard, 1) will always return -1 (or 0.0001 if it's a draw). Which means we can never observe a win for the player with ID 1.
The getGameEnded function is implemented from the perspective of player with ID = 1. So it returns +1 if player with ID 1 wins, -1 if player with ID 1 loses.
My current understanding about MCTS is that we need to observe all possible game ending states of a two player zero-sum game. I tried to use the framework on my game, and it didn't learn or get better. I changed the game logic to explicitly keep track of the current player id so that I can return all three possible outcomes. Now, at least it seems to learn a bit, but I still think that there is something wrong.
Questions:
Could this implementation theoretically work? Is it a correct implementation of the MCTS algorithm?
Does MCTS need to observe all possible outcomes of a two player zero-sum game?
Are there any obvious quick fixes of the code? Am I missing something about the implementation?
Conceptually the implementation in the linked repo is correct. The evaluation of the state is not checked until we recurse 1 more time to the perspective of the losing player, but as soon as that backs up 1 level the last player to move it is viewed as a win for the last player to perform an action and that will back up the tree all the way swapping back and forth to the current state of the real game which will return the correct value.
This does represent all possible outcomes. The outcomes are player 1 wins, player 2 wins or draw. In the case of a draw, it just returns something close to zero. In the case that player 1 wins, player 1 made the last move and then we recurse to player 2 who is in a losing evaluation. In the case that player 2 wins, player 2 would have made the last move and then we recurse once more to where player 1's evaluation is a loss.
It should be noted that it is possible for there to be a game where you move last and lose and in that case it is still correct!
If you wrote your own game rules and are trying to get this to work for your game, it's best to make sure your implementation adheres to the assumptions made by this implementation, i.e. the evaluation is always from the position of the active player and that your evaluation function is actually zero sum.
I want my player to fly at a certain speed to the specified point after running the code, it should not be teleportation, but exactly smooth movement, as in this video - https://youtu.be/_p7HmviCIF8?t=231
For your case here, if you want an exact time for every teleport, you're gonna need to use TweenService.
So you're first going to reference where you're going. Let's say that our point is a CFrame value of an object.
Remember, whenever we want to tp our character, we use CFrames and not Positions.
So first, you're gonna wanna make a TweenInfo, which is basically the parameters of the tween, e.g Time to get to the point, the movement it should have (Linear, Elastic, etc.), etc.
And then you're gonna need a table containing of the property that needs to be changed. In which case we want the CFrame value of the HumanoidRootPart to be the point we set.
Then we're going to make a new tween and have it tween our HumanoidRootPart CFrame to the point CFrame.
local TweenService = game:GetService("TweenService")
local TweeningInfo = TweenInfo.new(
-- The time to get there here
)
local TargetValue = {
CFrame = -- Point CFrame here.
}
local Tween = TweenService:Create(game.Players.LocalPlayer.Character.HumanoidRootPart, TweeningInfo, TargetValue)
Tween:Play()
For your video its just an script for a exploit like synapse x but there are a lot of pastebin or free scripts in toolbox or simply video on that or use the adonis admin on studio and run this in chat :fly me "speed"
Using the Child-monitoring script #Kylaaa helped me with in another question, I've spent hours on this, altering the core functionality from healing and disappearing bricks to play a parent sound when the player "walks through the leaves". I've been studying various aspects of the problem ('IsA', 'TouchInterest', 'If...then', Classes, Operators, etc.), and done various things, such as altering my script to look at the name of touched objects instead of their classes, but I've had no luck getting the sound to play.
-- create a helper function to access the brick and the thing that touched it
function OnTouched(thing)
local active = false --start with this debounce variable off so that the function will run the first time
return function(target) --provides actual target of the event
if active then return end -- do not do the animation again if it has already started
local player=thing.Parent:findFirstChild("Humanoid") --determine if it's humanoid
if player then --if it is, then
active = true --toggle to prevent function from running again simultaneously
script.Parent:play() --play rustling leaves sound
wait(1)
active = false -- reset so function can be used again
end --end of if statement
end
end
-- loop over the children and connect touch events
local bricks = script:GetChildren()
for i, brick in ipairs(bricks) do
if brick:IsA("Part") then
local onTouchedFunc = OnTouched(brick)
brick.Touched:Connect(onTouchedFunc)
end
end
This is a shot of the leaf litter I want to add the rustling sound to. I also have the same problem with the vines on the left side.
Vines:
All leaves are 'MeshParts' with 'SurfaceAppearance' inside, and are Anchored and CanTouch but not CanCollide. I tried turning on CanCollide but it didn't help.
Dense Leaf patch properties:
Surface Appearance properties:
I had tried "if brick:IsA("Model" or "MeshPart") then"
and
"if brick.Name=="Dense Leaf patch" or "SurfaceAppearance" or "DenseLeafPatch" then"
but neither of those worked.
I then noticed that a TouchInterest wasn't generated by Roblox, and I learned that you can neither copy nor duplicate TouchInterests to use where you need them (they're not there for developers, according to a message in the DevForum).
I originally had 1-3 leaves 'MeshPart's in separate 'Model's, but then made a single, invisible part (name: TouchInterest), CanTouch not CanCollide, that was large enough to cover almost all of the physical area of the instances, and put all of the MeshParts into that part. Then, I altered the script to just look for 'Part's. As a result, a TouchInterest does get generated during run-time.
This is all of the stuff involved in the group "leaves", with the sound, then the script, the containing part, then all the leaves inside as children of the script.
Sound's properties:
No errors for this were in the Output.
I feel like there's something simple I don't understand. Do I need several small parts (instead of the one large one) encompassing groups of leaves? Please help!
I figured out the problems.
On line 6, I used "thing" when I should've used "target".
On line 9, I forgot to capitalize "Play".
On line 10, I needed to make the wait 2 seconds instead of 1.
I am trying to make a script, in Lua code, that detects the level of lighting in my game. I am pretty new to Lua so as far as I know lighting in the game is a number (2, 10, 5).
if game:GetService("Lighting").Brightness < 1 then
game.StarterGui.ScreenGui.output.Text = "You are getting cold";
end
I am not sure if it is just not detecting game:GetService("lighting").Brightness as a number or if the game does not know what game.StarterGui.ScreenGui.output.Text is. I've testing this multiple times, making small alteration every time, but most of the time I got no error. With the code now there is no error message.
Do not use game.StarterGui.
StarterGui is what gui is put inside a player's PlayerGui when they join. Players do NOT see StarterGui.
Instead:
game.Players.PlayerAdded:Connect(function(plr)
if game:GetService("Lighting").Brightness < 1 then
plr.PlayerGui.ScreenGui.output.Text = "You are getting cold";
end
end)
(player).PlayerGui is the gui the player sees. StarterGui will not auto update or modify the game's players' guis when it is changed.
If you have any more questions feel free to ask them with a comment! ^-^
Roblox lua documentation:
https://www.developer.roblox.com/en-us