Create Generator Script

A client script will be created that will generate the axes. It will select a random blade and handle from the data tables, and also randomize the color of the parts.

Storing all the colors for each part as an attribute for the NFT can be a little too much, especially if you are manually creating the attributes on OpenSea. A better approach to this that we will be using, is storing the seed used.

Create NFTAxeGeneratorClient Script

Create a new script called NFTAxeGeneratorClient and place it into a Client Context folder. This script will need references to the container so it can spawn the objects, the blades, and the handles.

  1. Add the Container group inside the Dummy Object as a custom property called Container.
  2. Add the Blades data table as a custom property called Blades.
  3. Add the Handles data table as a custom property called Handles.

Add Variables

Add the variables below to the script.

  • The currentItem variable will hold information about the current Axe that was generated.
  • The list variable will hold all the axes generated so the data can be printed that can be used for helping create the NFTs.
  • RNG and ColorRNG are instances of RandomStream. This allows us to use a seeded random number, in this case, the seed is the year 2022.
local CONTAINER = script:GetCustomProperty("Container"):WaitForObject()
local BLADES = require(script:GetCustomProperty("Blades"))
local HANDLES = require(script:GetCustomProperty("Handles"))

local currentItem = nil
local list = {}
local RNG = RandomStream.New(2022)
local ColorRNG = RandomStream.New(2022)
Code language: Lua (lua)

Enable Cursor

Enable the cursor so it is visible when clicking on the screen.

UI.SetCursorVisible(true)
Code language: JavaScript (javascript)

Create ClearPrevious Function

Create a function called ClearPrevious. This function will clear the previous objects that were spawned. This will prevent objects from overlapping when creating a random Axe.

local function ClearPrevious()
	if currentItem ~= nil then
		if Object.IsValid(currentItem.blade) then
			currentItem.blade:Destroy()
		end

		if Object.IsValid(currentItem.handle) then
			currentItem.handle:Destroy()
		end
	end

	currentItem = nil
end
Code language: Lua (lua)

Create InList Function

Create a function called InList. This function will check to see if an item already exists in the list. Because we want unique axes for NFTs, we can prevent duplicates by checking the current mutated seed against the seeds in the list table.

local function InList(seed)
	for i, item in ipairs(list) do
		if item.seed == seed then
			return true
		end
	end

	return false
end
Code language: Lua (lua)

Create ColorMeshes Function

Create a function called ColorMeshes. This function will find all static meshes and randomly set the color of each material slot. If a mesh has a custom property of Ignore, then the loop will ignore that static mesh.

local function ColorMeshes(item)
	local meshes = item:FindDescendantsByType("StaticMesh")

	for m, mesh in ipairs(meshes) do
		if mesh:GetCustomProperty("Ignore") == nil or not mesh:GetCustomProperty("Ignore") then
			local material_slots = mesh:GetMaterialSlots()

			for s, slot in ipairs(material_slots) do
				slot:SetColor(Color.New(ColorRNG:GetNumber(), ColorRNG:GetNumber(), ColorRNG:GetNumber()))
			end
		end
	end
end
Code language: Lua (lua)

Create Generate Function

Create a function called Generate. This function will clear the previously generated Axe, mutate RNG, and try to spawn a random blade and handle. If it is a unique Axe, then it is randomly colored. Each blade and handle is spawned into the CONTAINER.

local function Generate()
	ClearPrevious()

	RNG:Mutate()

	currentItem = {

		seed = ColorRNG.seed,
		handleIndex = RNG:GetInteger(1, #HANDLES),
		bladeIndex = RNG:GetInteger(1, #BLADES)

	}

	local handleRow = HANDLES[currentItem.handleIndex]

	currentItem.handle = World.SpawnAsset(handleRow.Template, { parent = CONTAINER })

	local bladeRow = BLADES[currentItem.bladeIndex]
	
	currentItem.blade = World.SpawnAsset(bladeRow.Template, { parent = CONTAINER })

	if InList(currentItem.seed) then
		print("Item exists already")
		ClearPrevious()
	else
		ColorMeshes(currentItem.blade)
		ColorMeshes(currentItem.handle)
	end
end
Code language: Lua (lua)

Create AddToList Function

Create a function called AddToList. This function will add the current item that was generated to the list table.

local function AddToList()
	if currentItem ~= nil then
		list[#list + 1] = currentItem
	end
end
Code language: Lua (lua)

Create Output Function

Create a function called Output. This function is responsible for outputting all the information about each Axe into the Event Log. This information can then be used to create the NFTs.

local function Output()
	local output = {}

	for index, item in ipairs(list) do
		local entry = {

			blade = item.bladeIndex,
			handle = item.handleIndex

		}

		output[#output + 1] = entry

		print("Blade:", item.bladeIndex)
		print("Handle:", item.handleIndex)
		print("Seed:", item.seed)

		print("------------------------------")
	end
end
Code language: Lua (lua)

Check Input Action Pressed

To generate an Axe, we need to check what action is being pressed. We can check a few different actions which will call different functions.

  • If the action is Shoot, which is the left mouse button by default. It will call the Generate function and generate an Axe.
  • If the action is Jump, which is space bar by default. It will call the Output function and generate the information about all the generated axes in the Event Log.
  • If the action is Aim, which is the right mouse button by default. It will add the current Axe generated to the list. You may not want all axes to be added to the list.
Input.actionPressedEvent:Connect(function(player, action)
	if action == "Shoot" then
		Generate()
	elseif action == "Jump" then
		Output()
	elseif action == "Aim" then
		AddToList()
	end
end)
Code language: Lua (lua)

The NFTAxeGeneratorClient Script

local CONTAINER = script:GetCustomProperty("Container"):WaitForObject()
local BLADES = require(script:GetCustomProperty("Blades"))
local HANDLES = require(script:GetCustomProperty("Handles"))

local currentItem = nil
local list = {}
local RNG = RandomStream.New(2022)
local ColorRNG = RandomStream.New(2022)

UI.SetCursorVisible(true)

local function ClearPrevious()
	if currentItem ~= nil then
		if Object.IsValid(currentItem.blade) then
			currentItem.blade:Destroy()
		end

		if Object.IsValid(currentItem.handle) then
			currentItem.handle:Destroy()
		end
	end

	currentItem = nil
end

local function InList(seed)
	for i, item in ipairs(list) do
		if item.seed == seed then
			return true
		end
	end

	return false
end

local function ColorMeshes(item)
	local meshes = item:FindDescendantsByType("StaticMesh")

	for m, mesh in ipairs(meshes) do
		if mesh:GetCustomProperty("Ignore") == nil or not mesh:GetCustomProperty("Ignore") then
			local material_slots = mesh:GetMaterialSlots()

			for s, slot in ipairs(material_slots) do
				slot:SetColor(Color.New(ColorRNG:GetNumber(), ColorRNG:GetNumber(), ColorRNG:GetNumber()))
			end
		end
	end
end

local function Generate()
	ClearPrevious()

	RNG:Mutate()

	currentItem = {

		seed = ColorRNG.seed,
		handleIndex = RNG:GetInteger(1, #HANDLES),
		bladeIndex = RNG:GetInteger(1, #BLADES)

	}

	local handleRow = HANDLES[currentItem.handleIndex]

	currentItem.handle = World.SpawnAsset(handleRow.Template, { parent = CONTAINER })

	local bladeRow = BLADES[currentItem.bladeIndex]

	currentItem.blade = World.SpawnAsset(bladeRow.Template, { parent = CONTAINER })

	if InList(currentItem.seed) then
		print("Item exists already")
		ClearPrevious()
	else
		ColorMeshes(currentItem.blade)
		ColorMeshes(currentItem.handle)
	end
end

local function AddToList()
	if currentItem ~= nil then
		list[#list + 1] = currentItem
	end
end

local function Output()
	local output = {}

	for index, item in ipairs(list) do
		local entry = {

			blade = item.bladeIndex,
			handle = item.handleIndex

		}

		output[#output + 1] = entry

		print("Blade:", item.bladeIndex)
		print("Handle:", item.handleIndex)
		print("Seed:", item.seed)

		print("------------------------------")
	end
end

Input.actionPressedEvent:Connect(function(player, action)
	if action == "Shoot" then
		Generate()
	elseif action == "Jump" then
		Output()
	elseif action == "Aim" then
		AddToList()
	end
end)
Code language: Lua (lua)

Test the Game

Test the game to make sure the following work:

  1. Left clicking generates a random Axe with random colors.
  2. Right click adds the Axe to the list.
  3. Pressing space prints out the list to the event log.
Scroll to Top