I’ve made many large projects that each got their own threads. However, I’ve also made smaller things that I just dropped into the What Are You Working On thread. They get lost in the thousands of replies, so I’ll be putting them all here for easier access, and any new ones will go here instead.
Markov Chain
December 2019
Pretty useless besides for having a laugh, but I implemented the markov chain algorithm into Rbx Lua.
API for the module is extremely simple:
MarkovChain.new()
-- Returns a Chain object
Chain:Study(string Text, bool IncludePunctuation)
-- Parses the words in Text and has the chain "learn" it
-- IncludePunctuation is optional and defaults to false
Chain:Generate(number MaxSize)
-- Returns a string generated by the module
-- MaxSize is an optional variable and defaults to 10000
I made it study 160+ Lua Learning tutorials, and this is what it wrote:
A Debounce script prevents a script into ServerScriptService. Name it whatever you’d like.Insert a LocalScript into StarterCharacterScripts.* With a LocalScript, players cannot see other players’ trails.* With a normal script and hit CTRL+C and you will need to be red, dull, and probably crash. That’s what ‘wait’ commands are for. If we wanted to make variables accessible in any script however that will increase the distance. It the delta is lesser that 0, then it will be matched 1+ times.‘-’ - The plus quantifier makes the stringall lower case.>i like chocolate, do you??I don’t really think I need them? Can’t I do not see the game. They can use one of the model and the size of the pattern matching.Looks for the script, we would need. So basically purchasePassID is the scale to offset. This is the service named MarketplaceService for you. You can do this manually, but no one wants to reload. Now for the gun.These variables should be named"killbrick," or something like this:This is especially useful for mobile add this into our ModuleScript:Now we’re going to directly set the CFrame in this instance, a table) Table: A container that stores values In the previous event we created. So we retrieve those numbers and gets the sum out of the code would be:> 5 seconds wouldn’t have passed, then… How are we putting the list ofvowels inside [] characters would be just like the other methods and events when the player We are done! You can also type "Hey want to open notepad on your left and right click and find out?After testing it through, it probably did select random text, and made it variablename to demonstrate that variablescan be named about whatever you want. You can imagine a bowling ball vs. a boulder. Although they are both rocks, the boulder has a HumanoidRootPart, and you should hit “Play” and verify the same mistake, yet being made with starting up your computer. You press the Stop button. It will always be 0.But if you make a variable called "IAMCOOL"Now, I want to dynamically create text on the spawn. Now that our ModuleScript returns, we will change color back to the language. After all, lua is a stringpattern onto itself. well, all three of the part. If you want it. I’m gonna put a string With that said, here are some pages about getting euler angles from a keyboard, we can start off by creating a thread by doingand run it by using the lua users wiki would be outputted. Fixing this is fixed in newer lua versions. Returns a function you need to have the connection to the nearby panels.In this extremely large amounts of applications for this tutorial. As you can use a more complicated rng then you need to check if we can’t get them by their name in ProcessReceipt. Now that we will need either a dot or *colon.*It’s good we have to select a random digit in the string matching %a+ is stored at capture index 1, the part to be first (descending order). So given our easy-to-remember strategy, return a < b mean? I’m not going to be before it can be read back by the Server only. You also need to check if the RemoteEvent and wait for to happen. More specifically, the Sound.Ended event. This event will fire the Event in the Explorer window and click on Move Tool. Now you will first need to escape magic characters. Any non-alphanumeric character (including all punctuation characters%s - represents all letters%c - represents all printable characters except space characters%l - represents all punctuation characters, even the non-magical) can be used to write that line of code should looks something like ‘1’ for 1 script instead of game.Workspace.Part when we are going to check if the ID in the empty space of the characters between (and including) from and to.Output:string.sub() can be fired. Here is the most useful service. We’re gonna start off with some currency, change it to fall off then go to the next section. Global Variables are a beginner at scripting and that no character is 2 and Cross(Up[#Up-1], Up[#Up], Nodes[I]) <= 0 do Low[#Low] = nil Now organization for _, I in next, Nodes do while #Low >= 2 and 3, and only I can act on them."Now, when calling the function didn’t fail, but it’ll return false if it is, more visible it becomes. (Remember that 0 is the equivalent of: We can make your variables. This will decrease the amount of typing nessacary, and if you are take the left number and divide it by the end of the Camera, just the beginning of subject string. Using both will anchor the pattern (a?(%a+).(%s+)), the part it’s parented to.BodyForce has only one property. Force. This is the end.I hope this makes your character will be in a half-second. Why? **Making too many datastore calls can cause an error, then the script is very important!**I’ll be saving the coins in the terrain we generate, wewould use numeric for loops works, you need a function that will never get disconnected:Never use methods like this afterwards.Now, we’re gonna put mine in StarterGui. Get the LocalPlayer in a ModuleScript in ReplicatedStorage, and call the :MoveTo() method and wait for it to workspace, but it’s the shortest axis, which in this example, we use string.sub(msg, 0,1), we only look at the Part we created simple custom player commands using string.sub.First, insert a Remote Event for now.) Why are we getting some strange output? This is a table of nodes: local Nodes = workspace.Nodes:GetChildren() table.sort(Nodes, function(A, B) return A.Position.X < B.Position.X or B.Position.X == B.Position.X and A.Position.Z < B.Position.Z end We need a looping function that checks if the purchase granted. To do this, if the condition is not the plugin).You may be wondering why these two new sub-properties have one number associated with them!Although accessory handles are, by default, but there’s nothing wrong with it. Then you’re completely wrong.Connections take up quite a lot of text it’s going to be first (ascending order). *> means greater than. This would mean if the program failed.
Source Code
--[=[
boatbomber
Really simple Markov Chain module
MarkovChain.new()
Returns a Chain object
Chain:Study(string Text, bool IncludePunctuation)
Parses the words in Text and has the chain "learn" it
IncludePunctuation is optional and defaults to false
Chain:Generate(number MaxSize)
Returns a string generated by the chain
MaxSize is optional and defaults to 10000
--]=]
local NOWORD = "\n"
math.randomseed(tick())
local function GetWords(Text, IncludePunctuation)
local lines = string.split(Text, "\n")
local lineNum = 1
local line = lines[lineNum] -- current line
local pos = 1 -- current position in the line
return function () -- iterator function
while line do -- repeat while there are lines
local s, e = string.find(line, IncludePunctuation and "%S+" or "%w+", pos)
if s then -- found a word?
pos = e + 1 -- update next position
return string.sub(line, s, e) -- return the word
else
lineNum = lineNum +1
line = lines[lineNum] -- word not found; try next line
pos = 1 -- restart from first position
end
end
return nil -- no more lines: end of traversal
end
end
local MarkovChain = {}
function MarkovChain.new()
local Chain = {
StateTable = {};
}
function Chain:Study(Text, IncludePunctuation)
local w1, w2 = NOWORD, NOWORD
for w in GetWords(Text, IncludePunctuation) do
local i,v = w1.." "..w2, w
if not self.StateTable[i] then
self.StateTable[i] = {n=0}
end
self.StateTable[i][#self.StateTable[i]+1] = v
w1 = w2; w2 = w;
end
local i,v = w1.." "..w2, NOWORD
if not self.StateTable[i] then
self.StateTable[i] = {n=0}
end
self.StateTable[i][#self.StateTable[i]+1] = v
end
function Chain:Generate(MaxSize)
MaxSize = type(MaxSize) == "number" and MaxSize or 10000
local TextOutput = ""
local w1,w2 = NOWORD,NOWORD
for i=1,MaxSize do
local list = self.StateTable[(w1.." "..w2)]
-- choose a random item from list
local r = math.random(#list)
local nextword = list[r]
if nextword == NOWORD then break end
TextOutput = TextOutput..nextword.." "
w1 = w2; w2 = nextword
end
return TextOutput
end
return Chain
end
return MarkovChain
ClickDetectors
November 2019
The ClickDetector Instances have very shoddy behavior, and I found them to be unusable.
A MouseHoverEnter event doesn’t always fire a MouseHoverLeave event afterwards. Additionally, sometimes Enter fired on the next detector before the previous one fired Leave.
Differences between my custom Lua ClickDetector vs the Instance version:
-
Mine has stable and reliable behavior. Every Enter is sure to have a Leave fired after (unless you never leave ) and Leave will always fire before the Enter fires on the next one.
-
Mine has a read-only
.Hovering
property. Instead of having to hook Enter and Leave and track it in a variable, you can just check this property when needed. I found this useful, hope you agree. -
Mine has a
.Enabled
property, so you can just set that to false for enter events to stop firing. For some reason, the Instance versions don’t have a way to be disabled. -
Mine does not put Instances inside the part, which I find nice for avoiding clutter.
-
The Instance ClickDetector APIs are named differently than everything else. They’re verbose and old. I hate that. Mine follows the API of a GuiButton. Instead of
MouseHoverEnter
, it’sMouseEnter
. -
Mine doesn’t replicate to the server. It’s entirely clientside. Worth noting, however, that the Instance is super insecure and people have to write modules to be able to use it on the server reasonably.
It’s not entirely complete. Here’s what missing (will be added later):
-
MouseButton1Click
(You can useMouseButton1Down
andMouseButton1Up
for now) -
MouseButton2Click
(You can useMouseButton2Down
andMouseButton2Up
for now)
Source code:
--[=[
Example usage:
local ClickDetector = require(script.ClickDetector)
local Part = ClickDetector.new(workspace:WaitForChild("Part"))
Part.MaxActivationDistance = 15
Part.CursorIcon = "http://www.roblox.com/asset/?id=4317746479"
Part.MouseEnter:Connect(function()
print("Entered part")
end)
Part.MouseLeave:Connect(function()
print("Left part")
end)
Part.MouseButton1Down:Connect(function()
print("Clicked part")
end)
--]=]
local ClickDetector = {}
local UIS = game:GetService("UserInputService")
local BINDABLE = Instance.new("BindableEvent")
local Cam = workspace.CurrentCamera
local Plr = game.Players.LocalPlayer
local Mouse = Plr:GetMouse()
local Char = Plr.Character or Plr.CharacterAdded:Wait()
local HRP = Char:WaitForChild("HumanoidRootPart")
local ActiveDetectors,CurrentHover,last_t,last_i = {},nil,nil,Mouse.Icon
Cam:GetPropertyChangedSignal("CFrame"):Connect(function()
local h = ActiveDetectors[last_t]
if h then
if (HRP.Position - h._Internal.Adornee.Position).Magnitude <=h.MaxActivationDistance and h.Enabled then
--Within distance
if not h.Hovering then
-- not yet set to hover, do it
rawset(h, "Hovering", true)
h._Internal.EnterEvent:Fire()
Mouse.Icon = h.CursorIcon or ""
CurrentHover = h
end
else
-- Far away
if h.Hovering then
-- set to hover, undo
rawset(h, "Hovering", false)
h._Internal.LeaveEvent:Fire()
Mouse.Icon = ""
if CurrentHover == h then
CurrentHover = nil
end
end
end
end
end)
UIS.InputChanged:Connect(function(Input)
if Input.UserInputType == Enum.UserInputType.MouseMovement then
-- Handle hover detection
local t = Mouse.Target
if t ~= last_t then last_t = t
local h = ActiveDetectors[t]
-- Leave old
if CurrentHover and CurrentHover._Internal.Adornee ~= t then
rawset(CurrentHover, "Hovering", false)
CurrentHover._Internal.LeaveEvent:Fire()
Mouse.Icon = ""
end
-- Enter new
if h and (HRP.Position - h._Internal.Adornee.Position).Magnitude <=h.MaxActivationDistance and h.Enabled then
rawset(h, "Hovering", true)
h._Internal.EnterEvent:Fire()
Mouse.Icon = h.CursorIcon or ""
CurrentHover = h
else
CurrentHover = nil
end
end
end
end)
UIS.InputBegan:Connect(function(Input,GP)
if not CurrentHover then return end
if Input.UserInputType == Enum.UserInputType.MouseButton1 then
CurrentHover._Internal.Button1DownEvent:Fire()
elseif Input.UserInputType == Enum.UserInputType.MouseButton2 then
CurrentHover._Internal.Button2DownEvent:Fire()
end
end)
UIS.InputEnded:Connect(function(Input,GP)
if not CurrentHover then return end
if Input.UserInputType == Enum.UserInputType.MouseButton1 then
CurrentHover._Internal.Button1UpEvent:Fire()
elseif Input.UserInputType == Enum.UserInputType.MouseButton2 then
CurrentHover._Internal.Button2UpEvent:Fire()
end
end)
function ClickDetector.new(BasePart)
--Type check
if typeof(BasePart)~="Instance" or not BasePart:IsA("BasePart") then
error("Invalid BasePart for click detection "..BasePart,2)
end
local EnterEvent = BINDABLE:Clone()
local LeaveEvent = BINDABLE:Clone()
local Button1DownEvent = BINDABLE:Clone()
local Button2DownEvent = BINDABLE:Clone()
local Button1UpEvent = BINDABLE:Clone()
local Button2UpEvent = BINDABLE:Clone()
local Detector = {
Enabled = true;
MaxActivationDistance = 32;
CursorIcon = "";
Hovering = false;
MouseEnter = EnterEvent.Event;
MouseLeave = LeaveEvent.Event;
MouseButton1Down = Button1DownEvent.Event;
MouseButton2Down = Button2DownEvent.Event;
MouseButton1Up = Button1UpEvent.Event;
MouseButton2Up = Button2UpEvent.Event;
_Internal = {
EnterEvent = EnterEvent;
LeaveEvent = LeaveEvent;
Button1DownEvent = Button1DownEvent;
Button2DownEvent = Button2DownEvent;
Button1UpEvent = Button1UpEvent;
Button2UpEvent = Button2UpEvent;
Adornee = BasePart;
};
}
function Detector:Destroy()
ActiveDetectors[self._Internal.Adornee] = nil
EnterEvent:Destroy()
LeaveEvent:Destroy()
Button1UpEvent:Destroy()
Button2UpEvent:Destroy()
if self.Hovering then
Mouse.Icon = ""
end
self._Internal.Adornee = nil
end
-- Catch inputs
ActiveDetectors[BasePart] = Detector
return Detector
end
return ClickDetector
Film Grain
October 2019
Wrote a short and simple script to add a film grain effect to your game, with easy customization.
Really doesn’t show up in a compressed video.
Source code
--[=[
:::::::::: ::::::::::: ::: :::: :::: :::::::: ::::::::: ::: ::::::::::: :::: :::
:+: :+: :+: +:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+:+: :+:
+:+ +:+ +:+ +:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ :+:+:+ +:+
:#::+::# +#+ +#+ +#+ +:+ +#+ :#: +#++:++#: +#++:++#++: +#+ +#+ +:+ +#+
+#+ +#+ +#+ +#+ +#+ +#+ +#+# +#+ +#+ +#+ +#+ +#+ +#+ +#+#+#
#+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+#+#
### ########### ########## ### ### ######## ### ### ### ### ########### ### ####
by boatbomber, 2019
--]=]
-- Put this as a LocalScript and tweak the settings to your liking.
-- Settings
local GRAIN_SIZE = 50 -- A number 1 to 100
local GRAIN_SPEED = 50 -- A number 1 to 100
local GRAIN_VISIBILITY = 15 -- A number 1 to 100
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
local udim2 = UDim2.new
local rand = math.random
local plr = game.Players.LocalPlayer
local plrGui= plr:WaitForChild("PlayerGui")
local baseSize = 300*(GRAIN_SIZE*0.02)
local speed = 1/(40*(GRAIN_SPEED*0.02))
local vis = 1.05-(GRAIN_VISIBILITY*0.01)
local GrainGui = Instance.new("ScreenGui")
GrainGui.Name = "FilmGrain"
GrainGui.IgnoreGuiInset = true
GrainGui.DisplayOrder = 99
GrainGui.Parent = plrGui
local GrainImage = Instance.new("ImageLabel")
GrainImage.Size = udim2(1,0,1,0)
GrainImage.BackgroundTransparency = 1
GrainImage.ImageTransparency = vis
GrainImage.ScaleType = Enum.ScaleType.Tile
GrainImage.Image = "http://www.roblox.com/asset/?id=28756351"
GrainImage.Parent = GrainGui
local last = 0
game:GetService("RunService").Heartbeat:Connect(function()
if tick()-last < speed then return end
last = tick()
GrainImage.TileSize = udim2(rand(baseSize*0.89,baseSize*1.11)/1000,0,rand(baseSize*0.89,baseSize*1.11)/1000,0)
end)
Filters
June 2019
It quickly and easily applies filters to your world, on-the-fly.
A while after I made this, someone made a wonderful plugin called LightPlus+ that serves the same purpose but only in studio. Mine is more for a “photo mode” in game that allows filters. It comes with a few filters, and you can easily add your own.
Demo World:
Source code
local LightingService = game:GetService("Lighting")
local Applying = false
local Objects = {}
local module = {
-- To create your own filter, just add another table like these
-- and give it a unique key so it can be called in module.ApplyFilter
Filters = {
['None'] = {
["BloomEffect"] = {Intensity = 0, Size = 0, Threshold = 5};
["BlurEffect"] = {Size = 0};
["ColorCorrectionEffect"] = {Brightness = 0, Contrast = 0, Saturation = 0, TintColor = Color3.fromRGB(255,255,255)};
["SunRaysEffect"] = {Intensity = 0, Spread = 0};
};
['Vintage'] = {
["BloomEffect"] = {Intensity = 2, Size = 50, Threshold = 1};
["BlurEffect"] = {Size = 3};
["ColorCorrectionEffect"] = {Brightness = 0.04, Contrast = -0.1, Saturation = -0.05, TintColor = Color3.fromRGB(252,255,233)};
["SunRaysEffect"] = {Intensity = 0.1, Spread = 0.1};
};
['Warm'] = {
["BloomEffect"] = {Intensity = 2, Size = 50, Threshold = 1};
["BlurEffect"] = {Size = 2};
["ColorCorrectionEffect"] = {Brightness = 0.01, Contrast = 0.01, Saturation = 0.1, TintColor = Color3.fromRGB(255,227,180)};
["SunRaysEffect"] = {Intensity = 0.1, Spread = 0.1};
};
['Cool'] = {
["BloomEffect"] = {Intensity = 5, Size = 40, Threshold = 1};
["BlurEffect"] = {Size = 2};
["ColorCorrectionEffect"] = {Brightness = -0.03, Contrast = -0.1, Saturation = -0.1, TintColor = Color3.fromRGB(212,240,255)};
["SunRaysEffect"] = {Intensity = 0.05, Spread = 0.03};
};
['Negative'] = {
["BloomEffect"] = {Intensity = 10, Size = 50, Threshold = 1};
["BlurEffect"] = {Size = 0};
["ColorCorrectionEffect"] = {Brightness = 0.1, Contrast = -1.8, Saturation = -1, TintColor = Color3.fromRGB(235,246,255)};
["SunRaysEffect"] = {Intensity = 0.2, Spread = 0.1};
};
['Realistic'] = {
["BloomEffect"] = {Intensity = 1, Size = 38, Threshold = 0.8};
["BlurEffect"] = {Size = 2};
["ColorCorrectionEffect"] = {Brightness = -0.01, Contrast = 0.06, Saturation = -0.06, TintColor = Color3.fromRGB(255,253,252)};
["SunRaysEffect"] = {Intensity = 0.2, Spread = 0.1};
};
['Western'] = {
["BloomEffect"] = {Intensity = 2, Size = 40, Threshold = 1};
["BlurEffect"] = {Size = 1};
["ColorCorrectionEffect"] = {Brightness = 0.02, Contrast = -0.03, Saturation = -0.4, TintColor = Color3.fromRGB(255,205,123)};
["SunRaysEffect"] = {Intensity = 0.1, Spread = 0.7};
};
['Old School'] = {
["BloomEffect"] = {Intensity = 3, Size = 50, Threshold = 1};
["BlurEffect"] = {Size = 2};
["ColorCorrectionEffect"] = {Brightness = 0.05, Contrast = 0.06, Saturation = -0.95, TintColor = Color3.fromRGB(249,255,255)};
["SunRaysEffect"] = {Intensity = 0.5, Spread = 0.02};
};
['Meme'] = {
["BloomEffect"] = {Intensity = 10, Size = 80, Threshold = 1};
["BlurEffect"] = {Size = 1};
["ColorCorrectionEffect"] = {Brightness = 0.2, Contrast = 1, Saturation = 30, TintColor = Color3.fromRGB(255,255,255)};
["SunRaysEffect"] = {Intensity = 0.01, Spread = 0.12};
};
};
}
function module:ApplyFilter(FilterType)
--Avoid doing two applications at once and making a mess
if Applying then repeat wait(0.1) until not Applying end Applying = true
--Remove old filter
for i=1,#Objects do
Objects[i]:Destroy()
end
--Find chosen filter
local Filter = self.Filters[FilterType] or self.Filters.Realistic
--Apply filter
for obj, props in pairs(Filter) do
local effect = Instance.new(obj)
for p,v in pairs(props) do
effect[p] = v
end
Objects[#Objects+1] = effect
effect.Parent = LightingService
end
--Allow new application
Applying = false
end
return module