I would like to share this library of books I assembled to procedurally fill a book shelf area with books, for my furniture library.
![image](http://devforum-uploads.s3.dualstack.us-east-2.amazonaws.com/uploads/original/5X/c/8/d/8/c8d812f751f207bd698a3d3aa3a2ad8cabb2a15b.jpeg)
To do this the books are organized into 3 categories, groups of books, stacks of books and individual books…
Individual books are labeled with a title and an attribute string called Author. and book synopsis called “examine”.
![image](http://devforum-uploads.s3.dualstack.us-east-2.amazonaws.com/uploads/original/5X/8/2/1/9/821901a7e93d7f142166f3948983575a4aadffd5.jpeg)
![image](http://devforum-uploads.s3.dualstack.us-east-2.amazonaws.com/uploads/original/5X/0/b/8/f/0b8f73aec1b69b0c0a33f5d325931492b5c3997c.png)
![image](http://devforum-uploads.s3.dualstack.us-east-2.amazonaws.com/uploads/original/5X/2/1/3/8/2138c090e63db6ea1964288fd0198d90553003f8.jpeg)
Included in this example is my implementation of a wikipedia lookup system to interact with the books this is the complete source code that formats the books and organizes the book shelves.
local book = {}
local BookLibrary=script.BookLibrary.Value
local BookDirectory=workspace
local BookTypes=BookLibrary:GetChildren()
local BooksLib={}
for i,Bookdir in BookTypes do
BooksLib[i]=Bookdir:GetChildren()
end
BookTypes=BooksLib
local Bookarray = {}
for i, Bookdir in pairs(BookTypes) do
for t, Book in pairs(Bookdir) do
table.insert(Bookarray, Book) -- book is guaranteed to be a MeshPart instance
end
end
--local Bookarray=BookLibrary.Books:GetChildren()
local BookGuide={["BlankShelf"]={math.rad(-180),"X","Z"},["Books"]={math.rad(-90),"Z","X"},["BlankStack"]={math.rad(-180),"X","Z"}}
function book.GetBook(size)
-- Create a table to hold books of equal or lesser size
local suitableBooks = {}
-- Iterate through the Bookarray to find suitable books
for _, book in ipairs(Bookarray) do
if BookGuide[book.Parent.Name] and book.Size[BookGuide[book.Parent.Name][2]]<= size.X and book.Size.Y <= size.Y then
table.insert(suitableBooks, book)
end
end
-- If there are no suitable books, return nil
if #suitableBooks == 0 then
return nil
end
-- Return a random book from the suitableBooks table
return suitableBooks[math.random(#suitableBooks)]
end
function book.shelf(platform)
local limit = platform.Size.X
local start = platform.CFrame:ToWorldSpace( CFrame.new(-limit / 2, -platform.Size.Y / 2, platform.Size.Z / 2) )-- back top of platform
local currentX = 0
while currentX < limit do
local v = book.GetBook(Vector3.new(limit - currentX,platform.Size.Y,0))
local slot
if not v then
break -- No suitable book found, exit the loop
else
slot=BookGuide[v.Parent.Name]
v=v:Clone()
end
-- Position the book on the shelf
currentX = currentX + v.Size[slot[2]]/2
v.CFrame = start :ToWorldSpace(CFrame.new(currentX, v.Size.Y / 2, -v.Size[slot[3]] / 2)) * CFrame.Angles(0, slot[1], 0) -- align books with back top of platform
currentX = currentX + v.Size[slot[2]]/2
-- Update the current position on the shelf
-- Parent the book to the platform
v.Parent = BookDirectory
end
end
function book.VerticalText(frame, referenceLabel, text)
-- Clear any existing children in the frame
frame:ClearAllChildren()
-- Calculate the spacing between each character
local spacing = 1 / #text
local labelYscale=spacing
-- Loop through each character in the text
for i = 1, #text do
-- Clone the reference text label
local newLabel = referenceLabel:Clone()
-- Set the text of the new label to the current character
newLabel.Text = text:sub(i, i)
newLabel.Size = UDim2.new(1, 0, spacing, 0)
-- Position the new label vertically within the frame
newLabel.Position = UDim2.new(0, 0, (i - 1) * spacing, 0)
-- Parent the new label to the frame
newLabel.Parent = frame
end
end
function book.Render(object)
local cover=object:FindFirstChild("Cover") or script.Cover:Clone()
local spine=object:FindFirstChild("Spine") or script.Spine:Clone()
local back=object:FindFirstChild("Back") or script.Back:Clone()
cover.Author.Text=object:GetAttribute("Author") or ""
cover.Title.Text=object.Name
--spine.Title.Text=object.Name
book.VerticalText(spine.Frame, cover.Title, object.Name)
back.Description.Text=object:GetAttribute("examine") or ""
back.Author.Text=cover.Author.Text
back.Parent=object
back.Adornee=object
cover.Parent=object
cover.Adornee=object
spine.Parent=object
spine.Adornee=object
end
function book.Reset(object)
local cover=object:FindFirstChild("Cover")-- or script.Cover:Clone()
local spine=object:FindFirstChild("Spine")-- or script.Spine:Clone()
local back=object:FindFirstChild("Back")
if cover and spine and back then
cover:Destroy() spine:Destroy() back:Destroy()
end
end
function book.Format(Library)
for i,object in Library:GetChildren() do
book.Render(object)
end
end
return book
This is a model that features the module and the book library as well as an example book shelf, the instructions are to put the Module in ReplicatedStorage to run the example. configure to your liking. Let me know what you think of this and leave a like if you enjoy this resource.
Book Library - Creator Store (roblox.com)
Some of the features are:
- You can create your own book model with a cover, spine and back. By using the book.Render function you can render your preconfigured book model with a generated template.
- Using the book.shelf function you can fill a bookshelf with books. This does this by taking a part and occupying the space of the shelf then the algorithm generates a random book shelf every time! This is demonstrated in the Furniture model featuring the bookshelf. Notice how the book shelf front orientation is the same as a standard part instance so respect orientation when placing book shelves!
An idea is that perhaps you want to add more things to shelves? Why does it have to be books? It can be anything!
If you like this you can check out my other open source projects at these links!
Day Night Weather Cycle - Lighting & Terrain Shader Algorithm + Artificial Sun - Clean Efficient [Open-Source] - Resources / Community Resources - Developer Forum | Roblox