mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-24 06:34:09 +00:00
update rules
This commit is contained in:
parent
4c390fdd37
commit
d5522b2fef
8549 changed files with 11783 additions and 1888 deletions
569
.cursor/rules/roblox/en-us/resources/modules/emote-bar.md
Normal file
569
.cursor/rules/roblox/en-us/resources/modules/emote-bar.md
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
---
|
||||
title: Emote Bar
|
||||
description: The Emote Bar module aims to provide players an accessible, customizable way to socially interact.
|
||||
---
|
||||
|
||||
Emotes are a core component of any social experience. The **EmoteBar** [developer module](../../resources/modules/index.md) aims to provide players an accessible, customizable way to facilitate meaningful social interaction.
|
||||
|
||||
<video src="../../assets/developer-modules/emote-bar/Showcase.mp4" controls width="100%"></video>
|
||||
|
||||
## Module usage
|
||||
|
||||
### Installation
|
||||
|
||||
To use the **EmoteBar** module in an experience:
|
||||
|
||||
1. From Studio's **Window** menu or **Home** tab toolbar, open the [Toolbox](../../projects/assets/toolbox.md) and select the **Creator Store** tab.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" />
|
||||
|
||||
1. Make sure the **Models** sorting is selected, then click the **See All** button for **Categories**.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Categories-See-All.png" width="360" />
|
||||
|
||||
1. Locate and click the **Packages** tile.
|
||||
|
||||
1. Locate the **Emote Bar** module and click it, or drag-and-drop it into the 3D view.
|
||||
|
||||
<img src="../../assets/developer-modules/emote-bar/Toolbox-Icon.png" width="143" />
|
||||
|
||||
1. In the [Explorer](../../studio/explorer.md) window, move the entire **EmoteBar** model into `Class.ReplicatedStorage`. Upon running the experience the module will begin running.
|
||||
|
||||
### Configuration
|
||||
|
||||
The module is preconfigured with 7 emotes and it can be easily customized with your own emotes and display options. Additionally, if the player owns any emotes from previous Roblox events such as Lil Nas X, Royal Blood, or Twenty One Pilots, those emotes will be automatically added to the list of available emotes.
|
||||
|
||||
1. In **ServerScriptService**, create a new `Class.Script` and rename it **ConfigureEmotes**.
|
||||
|
||||
<img src="../../assets/developer-modules/emote-bar/Script-ConfigureEmotes.png" width="320" />
|
||||
|
||||
2. Paste the following code into the new **ConfigureEmotes** script. The `useDefaultEmotes` setting of `false` overrides the default emotes and lets you define custom emotes via the [setEmotes](#setemotes) function.
|
||||
|
||||
```lua title="Script - ConfigureEmotes" highlight="6,9"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.configureServer({
|
||||
useDefaultEmotes = false,
|
||||
})
|
||||
|
||||
EmoteBar.setEmotes({
|
||||
{
|
||||
name = "Hello",
|
||||
animation = "rbxassetid://3344650532",
|
||||
image = "rbxassetid://7719817462",
|
||||
defaultTempo = 1,
|
||||
},
|
||||
{
|
||||
name = "Applaud",
|
||||
animation = "rbxassetid://5915693819",
|
||||
image = "rbxassetid://7720292217",
|
||||
defaultTempo = 2,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
<p>If you want to disable loading of user-owned emotes into the emote bar or wheel, make sure the **UserEmotesEnabled** property is disabled for the **StarterPlayer** object. Note that this property can only be set in Studio and cannot be set by scripts at runtime.</p>
|
||||
<p>Also note that this developer module will modify the local user's emotes via `Class.HumanoidDescription:SetEmotes()`, meaning that calls to `Class.HumanoidDescription:GetEmotes()` will return values modified by this module.</p>
|
||||
</Alert>
|
||||
|
||||
### Mega emotes
|
||||
|
||||
A **mega emote** is formed when multiple players in the same area perform the same emote at the same time. As more and more players join in, the mega emote grows larger. As players stop performing the emote, the mega emote grows smaller until eventually it disappears.
|
||||
|
||||
<img src="../../assets/developer-modules/emote-bar/Mega-Emote.jpg" width="80%" />
|
||||
|
||||
### Tempo
|
||||
|
||||
An emote's **tempo** is the speed at which it plays when its button is tapped once. The default speed of an emote is determined by its `defaultTempo`. An emote's speed can be increased or decreased by tapping its button faster or slower.
|
||||
|
||||
## API reference
|
||||
|
||||
### Types
|
||||
|
||||
#### Emote
|
||||
|
||||
Each emote is represented by a dictionary with the following key-value pairs:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`name`</td>
|
||||
<td>string</td>
|
||||
<td>Emote name, for example `"Shrug"`.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`animation`</td>
|
||||
<td>string</td>
|
||||
<td>Asset ID for the emote's animation.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`image`</td>
|
||||
<td>string</td>
|
||||
<td>Asset ID for the emote's image in the GUI.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`defaultTempo`</td>
|
||||
<td>number</td>
|
||||
<td>Default speed factor at which to play the emote animation. For example, a tempo of 2 will play the animation at twice its normal speed. Must be greater than 0.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`isLocked`</td>
|
||||
<td>bool</td>
|
||||
<td>Whether the emote is "locked" from being activated.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Enums
|
||||
|
||||
#### EmoteBar.GuiType
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`EmoteBar`</td>
|
||||
<td>Default form where emotes are displayed in a bar along the bottom of the screen, separated into individual "pages."</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`EmoteWheel`</td>
|
||||
<td>Variant where emotes are displayed in a ring when a player clicks or taps on their player character.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.configureClient({
|
||||
guiType = EmoteBar.GuiType.EmoteWheel,
|
||||
})
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
#### configureServer
|
||||
|
||||
<figcaption>
|
||||
configureServer(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default server-side configuration options through the following keys/values in the `config` table. This function can only be called from a `Class.Script` and changes will automatically replicate to all clients.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`useDefaultEmotes`</td>
|
||||
<td>Whether the provided default emotes are included or not.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`useMegaEmotes`</td>
|
||||
<td>Enables or disables the [mega emotes](#mega-emotes) feature.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`emoteMinPlayers`</td>
|
||||
<td>Minimum number of players performing the same emote to contribute to a mega emote.</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`emoteMaxPlayers`</td>
|
||||
<td>Maximum number of players performing the same emote to contribute to a mega emote.</td>
|
||||
<td>50</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`playParticles`</td>
|
||||
<td>Enables or disables the emotes players are playing as floating particles above their heads.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`sendContributingEmotes`</td>
|
||||
<td>Enables or disables sending a small emote icon to contribute to the mega emote.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="Script" highlight="5-8"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.configureServer({
|
||||
emoteMinPlayers = 2,
|
||||
playParticles = false,
|
||||
})
|
||||
```
|
||||
|
||||
#### configureClient
|
||||
|
||||
<figcaption>
|
||||
configureClient(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default client-side configuration options through the following keys/values in the `config` table. This function can only be called from a `Class.LocalScript`. Depending on the value of `guiType`, options in the noted tabs also apply.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="General">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`guiType`</td>
|
||||
<td>Controls which form the GUI will take for displaying emotes ([EmoteBar.GuiType](#emotebarguitype)).</td>
|
||||
<td>[EmoteBar](#emotebarguitype)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`useTempo`</td>
|
||||
<td>Enables or disables the [tempo](#tempo) feature where users are able to control how fast or slow their emotes are played by repeatedly activating the same emote rhythmically.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`tempoActivationWindow`</td>
|
||||
<td>Amount of time, in seconds, the user has between sequential activations of an emote for it to count as part of the tempo.</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`lockedImage`</td>
|
||||
<td>Image to display overtop locked emotes.</td>
|
||||
<td>"rbxassetid://6905802778"</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Bar">
|
||||
If the value of `guiType` is [EmoteBar](#emotebarguitype) (default), the following options apply:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`maxEmotesPerPage`</td>
|
||||
<td>Maximum number of emotes that are displayed at a time. Smaller screens will automatically show fewer emotes.</td>
|
||||
<td>4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`emoteBarPosLandscape`</td>
|
||||
<td>Position of the emote bar in landscape mode (`Datatype.UDim2`).</td>
|
||||
<td>(0.5, 0, 1, -16)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`emoteBarPosPortrait`</td>
|
||||
<td>Position of the emote bar in portrait mode (`Datatype.UDim2`).</td>
|
||||
<td>(0.5, 0, 1, -100)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`useEmoteHotkeys`</td>
|
||||
<td>Whether emote hotkeys are used. If `true`, this binds 1, 2, 3, 4, etc. as hotkeys for the emote bar. Only numeric keys 1–9 are supported.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`usePageHotkeys`</td>
|
||||
<td>Whether page hotkeys are used. If `true`, `nextPageKey` and `prevPageKey` are used to cycle between pages.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`prevPageKey`</td>
|
||||
<td>Key used to cycle to the previous page of emotes (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|Q`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`nextPageKey`</td>
|
||||
<td>Key used to cycle to the next page of emotes (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|E`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`leftArrowImage`</td>
|
||||
<td>Image for the left arrow (previous page).</td>
|
||||
<td>"rbxassetid://6998633654"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`rightArrowImage`</td>
|
||||
<td>Image for the right arrow (next page).</td>
|
||||
<td>"rbxassetid://6998635824"</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Wheel">
|
||||
If the value of `guiType` is [EmoteWheel](#emotebarguitype), the following options apply:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`closeImage`</td>
|
||||
<td>Image for the close button on the emote wheel, placed overtop the `closeBackgroundImage` image.</td>
|
||||
<td>"rbxassetid://7027440823"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`closeBackgroundImage`</td>
|
||||
<td>Background image for the close button on the emote wheel.</td>
|
||||
<td>"rbxassetid://7027440823"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`emoteHoverImage`</td>
|
||||
<td>Image for hover-over indication of the selected emote in the wheel.</td>
|
||||
<td>"rbxassetid://7344843157"</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
```lua title="LocalScript - Emote Bar" highlight="5-10"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.configureClient({
|
||||
guiType = EmoteBar.GuiType.EmoteBar,
|
||||
maxEmotesPerPage = 6,
|
||||
nextPageKey = Enum.KeyCode.Z,
|
||||
prevPageKey = Enum.KeyCode.C,
|
||||
})
|
||||
```
|
||||
|
||||
```lua title="LocalScript - Emote Wheel" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.configureClient({
|
||||
guiType = EmoteBar.GuiType.EmoteWheel,
|
||||
})
|
||||
```
|
||||
|
||||
#### setEmotes
|
||||
|
||||
<figcaption>
|
||||
setEmotes(emotes: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Sets the custom emotes to use. These will be added to the defaults if `useDefaultEmotes` is `true`, or replace the defaults if `useDefaultEmotes` is `false`. This function can only be called from a `Class.Script` and changes will automatically replicate to all clients.
|
||||
|
||||
See [Emote](#emote) for the structure of each emote passed to this function.
|
||||
|
||||
<Alert severity="info">
|
||||
The order of custom emotes in the array determines how each emote is ordered in the UI.
|
||||
</Alert>
|
||||
|
||||
```lua title="Script - ConfigureEmotes" highlight="5,9"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.configureServer({
|
||||
useDefaultEmotes = false,
|
||||
})
|
||||
|
||||
EmoteBar.setEmotes({
|
||||
{
|
||||
name = "Hello",
|
||||
animation = "rbxassetid://3344650532",
|
||||
image = "rbxassetid://7719817462",
|
||||
defaultTempo = 1,
|
||||
},
|
||||
{
|
||||
name = "Applaud",
|
||||
animation = "rbxassetid://5915693819",
|
||||
image = "rbxassetid://7720292217",
|
||||
defaultTempo = 2,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
#### setGuiVisibility
|
||||
|
||||
<figcaption>
|
||||
setGuiVisibility(visible: `boolean`)
|
||||
</figcaption>
|
||||
|
||||
Shows or hides the emotes GUI. This function can only be called from a `Class.LocalScript` on a specific client.
|
||||
|
||||
```lua title="LocalScript" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.setGuiVisibility(false)
|
||||
```
|
||||
|
||||
#### getEmote
|
||||
|
||||
<figcaption>
|
||||
getEmote(emoteName: `Library.string`): `Library.table`
|
||||
</figcaption>
|
||||
|
||||
Gets an [Emote](#emote) by name. Returns `nil` if the emote cannot be found. This function can only be called from a `Class.LocalScript` on a specific client.
|
||||
|
||||
<Alert severity="info">
|
||||
Emotes registered on the server with [setEmotes](#setemotes) can be retrieved client-side using this function. This can also be used to retrieve any of the default emotes by name: `"Hello"`, `"Applaud"`, `"Point"`, `"Stadium"`, `"Tilt"`, `"Shrug"`, or `"Salute"`.
|
||||
</Alert>
|
||||
|
||||
```lua title="LocalScript" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
local shrug = EmoteBar.getEmote("Shrug")
|
||||
```
|
||||
|
||||
#### playEmote
|
||||
|
||||
<figcaption>
|
||||
playEmote(emote: [Emote](#emote))
|
||||
</figcaption>
|
||||
|
||||
Plays the given [Emote](#emote) and fires the [emotePlayed](#emoteplayed) event on the server, if connected. This function can only be called from a `Class.LocalScript` on a specific client.
|
||||
|
||||
```lua title="LocalScript" highlight="5-6"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
local shrug = EmoteBar.getEmote("Shrug")
|
||||
EmoteBar.playEmote(shrug)
|
||||
```
|
||||
|
||||
#### lockEmote
|
||||
|
||||
<figcaption>
|
||||
lockEmote(emoteName: `Library.string`)
|
||||
</figcaption>
|
||||
|
||||
Locks the [Emote](#emote) with the given name. This function can only be called from a `Class.LocalScript` on the client.
|
||||
|
||||
```lua title="LocalScript" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.lockEmote("Applaud")
|
||||
```
|
||||
|
||||
#### unlockEmote
|
||||
|
||||
<figcaption>
|
||||
unlockEmote(emoteName: `Library.string`)
|
||||
</figcaption>
|
||||
|
||||
Unlocks the [Emote](#emote) with the given name. This function can only be called from a `Class.LocalScript` on the client.
|
||||
|
||||
```lua title="LocalScript" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.unlockEmote("Applaud")
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
#### emotePlayed
|
||||
|
||||
Fires when any client plays an emote. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>player: `Class.Player`</td>
|
||||
<td>Player who acted out the emote.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>emote: [Emote](#emote)</td>
|
||||
<td>Emote which was played.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.emotePlayed:Connect(function(player, emote)
|
||||
print(player.Name, "played", emote.name)
|
||||
end)
|
||||
```
|
||||
|
||||
#### lockedEmoteActivated
|
||||
|
||||
Fires when a client clicks a locked emote. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>emote: [Emote](#emote)</td>
|
||||
<td>Locked emote which was activated.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="6-8"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local EmoteBar = require(ReplicatedStorage.EmoteBar)
|
||||
|
||||
EmoteBar.lockedEmoteActivated:Connect(function(emote)
|
||||
print(Players.LocalPlayer, "clicked", emote.name)
|
||||
end)
|
||||
```
|
||||
1146
.cursor/rules/roblox/en-us/resources/modules/event-sequencer.md
Normal file
1146
.cursor/rules/roblox/en-us/resources/modules/event-sequencer.md
Normal file
File diff suppressed because it is too large
Load diff
268
.cursor/rules/roblox/en-us/resources/modules/friends-locator.md
Normal file
268
.cursor/rules/roblox/en-us/resources/modules/friends-locator.md
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
---
|
||||
title: Friends Locator
|
||||
description: The Friends Locator module lets players easily find and teleport to their friends inside a place.
|
||||
---
|
||||
|
||||
It can be challenging to locate friends in-experience. The **FriendsLocator** [developer module](../../resources/modules/index.md) lets players easily find and teleport to their friends inside a place.
|
||||
|
||||
<video src="../../assets/developer-modules/friends-locator/Showcase.mp4" controls width="100%"></video>
|
||||
|
||||
## Module usage
|
||||
|
||||
### Installation
|
||||
|
||||
To use the **FriendsLocator** module in an experience:
|
||||
|
||||
1. From Studio's **Window** menu or **Home** tab toolbar, open the [Toolbox](../../projects/assets/toolbox.md) and select the **Creator Store** tab.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" />
|
||||
|
||||
1. Make sure the **Models** sorting is selected, then click the **See All** button for **Categories**.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Categories-See-All.png" width="360" />
|
||||
|
||||
1. Locate and click the **Packages** tile.
|
||||
|
||||
1. Locate the **Friends Locator** module and click it, or drag-and-drop it into the 3D view.
|
||||
|
||||
<img src="../../assets/developer-modules/friends-locator/Toolbox-Icon.png" width="143" />
|
||||
|
||||
1. In the [Explorer](../../studio/explorer.md) window, move the entire **FriendsLocator** model into `Class.ReplicatedStorage`. Upon running the experience the module will begin running.
|
||||
|
||||
### Test in Studio
|
||||
|
||||
To test the module in Studio, the **FriendsLocator** module must be run in a multi-client simulation, since no friends will be present in a solo playtest.
|
||||
|
||||
1. In **StarterPlayerScripts**, create a new `Class.LocalScript` and rename it **ConfigureFriendsLocator**.
|
||||
|
||||
<img src="../../assets/developer-modules/friends-locator/LocalScript-ConfigureFriendsLocator.png" width="320" />
|
||||
|
||||
1. Paste the following code into the new **ConfigureFriendsLocator** script. The `showAllPlayers` setting within the [configure](#configure) function ensures that locators are shown for all users while testing in Studio, but not in a published place.
|
||||
|
||||
```lua title="LocalScript - ConfigureFriendsLocator"
|
||||
local RunService = game:GetService("RunService")
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local FriendsLocator = require(ReplicatedStorage.FriendsLocator)
|
||||
|
||||
FriendsLocator.configure({
|
||||
showAllPlayers = RunService:IsStudio(), -- Allows for debugging in Studio
|
||||
})
|
||||
```
|
||||
|
||||
1. From Studio's mezzanine, start a [multi-client simulation](../../studio/testing-modes.md#multi-client-simulation) with 2 clients. Three new instances of Studio will open; one simulated server and two simulated clients.
|
||||
|
||||
<img src="../../assets/studio/general/Mezzanine-Testing-Mode-Server-Clients.png" width="800" alt="Server & Clients option in the testing modes dropdown of Studio's mezzanine." />
|
||||
|
||||
1. Go into either of the **client** Studio instances, move a distance of 100 studs away from the other character, and you should see a **locator icon** appear over its head.
|
||||
|
||||
<img src="../../assets/developer-modules/friends-locator/Testing-On-Client.jpg" width="800" />
|
||||
|
||||
<Alert severity="info">
|
||||
Due to the way user IDs are handled in Studio, avatar images will not appear on the locator icons during testing.
|
||||
</Alert>
|
||||
|
||||
<Alert severity="warning">
|
||||
By default, clicking/tapping a friends's icon will teleport your character to that character's location. If you keep this default behavior and you find that streaming pause is occurring under the [instance streaming](../../workspace/streaming.md) architecture, you may want to [request area streaming](../../workspace/streaming.md#request-area-streaming) around the teleport location as shown in the [clicked](#clicked) event code sample.
|
||||
</Alert>
|
||||
|
||||
### Connect to events
|
||||
|
||||
The **FriendsLocator** module exposes [events](#events) so that you can introduce custom behaviors when users interact with a locator icon.
|
||||
|
||||
1. Make sure that you've created the **ConfigureFriendsLocator** script outlined in [testing in Studio](#test-in-studio).
|
||||
2. Add lines 8 and 11-13 to the script:
|
||||
|
||||
```lua title="LocalScript - ConfigureFriendsLocator" highlight="8,11-13"
|
||||
local RunService = game:GetService("RunService")
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local FriendsLocator = require(ReplicatedStorage.FriendsLocator)
|
||||
|
||||
FriendsLocator.configure({
|
||||
showAllPlayers = RunService:IsStudio(), -- Allows for debugging in Studio
|
||||
teleportToFriend = false, -- Prevent teleport on icon click/tap
|
||||
})
|
||||
|
||||
FriendsLocator.clicked:Connect(function(player, playerCFrame)
|
||||
print("You clicked on locator icon for", player.DisplayName)
|
||||
end)
|
||||
```
|
||||
|
||||
3. Conduct a [multi-client test](#test-in-studio) and click on another character's locator icon. Notice that your character does not teleport to that location, and the event triggers to allow for custom handling of icon clicks.
|
||||
|
||||
### Custom locator UI
|
||||
|
||||
If the default style does not fit your experience, you can replace the default avatar portrait UI with your own UI.
|
||||
|
||||
<img src="../../assets/developer-modules/friends-locator/Custom-UI-Example.jpg" width="80%" />
|
||||
|
||||
To replace the default UI:
|
||||
|
||||
1. Create a new `Class.ScreenGui` instance inside the **StarterGui** container.
|
||||
|
||||
<img src="../../assets/studio/explorer/StarterGui-ScreenGui.png" width="320" />
|
||||
|
||||
1. Create a `Class.Frame` instance named **FriendLocator** as a child of the new `Class.ScreenGui`, then add elements like `Class.ImageLabel|ImageLabels`, `Class.TextLabel|TextLabels` to design your custom UI.
|
||||
|
||||
<img src="../../assets/developer-modules/friends-locator/Custom-UI-Objects-In-Frame.png" width="320" />
|
||||
|
||||
1. When finished, **disable** the parent `Class.ScreenGui` so that the module doesn't show the custom locator UI until needed.
|
||||
|
||||
<img src="../../assets/developer-modules/friends-locator/Custom-UI-ScreenGui-Disabled.png" width="320" />
|
||||
|
||||
1. **(Optional)** If you want the friend's avatar portrait and `Class.Player.DisplayName|DisplayName` to show up somewhere in the custom UI, you can place the following instances inside the **FriendLocator** frame.
|
||||
|
||||
- An `Class.ImageLabel` of the name **Portrait**.
|
||||
- A `Class.TextLabel` of the name **DisplayName**.
|
||||
|
||||
<img src="../../assets/developer-modules/friends-locator/Custom-UI-Portrait-DisplayName.png" width="320" />
|
||||
|
||||
The module will look for these items and display the friend's avatar portrait and/or display name respectively.
|
||||
|
||||
## API reference
|
||||
|
||||
### Functions
|
||||
|
||||
#### configure
|
||||
|
||||
<figcaption>
|
||||
configure(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default configuration options through the following keys/values in the `config` table.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`alwaysOnTop`</td>
|
||||
<td>If `true`, shows locator icons on top of everything, preventing them from being blocked by 3D world objects.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`showAllPlayers`</td>
|
||||
<td>If `true`, shows locations for all players, not just friends; this can help verify the module's functionality in Studio.</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`teleportToFriend`</td>
|
||||
<td>Teleports player character to the friend's location when their locator icon is clicked or tapped.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`thresholdDistance`</td>
|
||||
<td>Camera distance threshold at which locator icons appear; friends closer than this distance will not display icons.</td>
|
||||
<td>100</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`maxLocators`</td>
|
||||
<td>Maximum number of locator icons shown at any given time.</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript - ConfigureFriendsLocator" highlight="5-11"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local FriendsLocator = require(ReplicatedStorage.FriendsLocator)
|
||||
|
||||
FriendsLocator.configure({
|
||||
alwaysOnTop = true,
|
||||
showAllPlayers = false,
|
||||
teleportToFriend = true,
|
||||
thresholdDistance = 100,
|
||||
maxLocators = 10
|
||||
})
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
#### clicked
|
||||
|
||||
Fires when a locator icon is clicked/activated by the local player. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>player: `Class.Player`</td>
|
||||
<td>Player that the locator icon belongs to.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>playerCFrame: `Datatype.CFrame`</td>
|
||||
<td>`Datatype.CFrame` of the player's `Class.Humanoid.RootPart` that the locator icon belongs to.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local Players = game:GetService("Players")
|
||||
local Workspace = game:GetService("Workspace")
|
||||
|
||||
local FriendsLocator = require(ReplicatedStorage.FriendsLocator)
|
||||
|
||||
local localPlayer = Players.LocalPlayer
|
||||
|
||||
FriendsLocator.clicked:Connect(function(player, playerCFrame)
|
||||
-- Request streaming around target location
|
||||
if Workspace.StreamingEnabled then
|
||||
local success, errorMessage = pcall(function()
|
||||
localPlayer:RequestStreamAroundAsync(playerCFrame.Position)
|
||||
end)
|
||||
if not success then
|
||||
print(errorMessage)
|
||||
end
|
||||
end
|
||||
|
||||
print("You clicked on locator icon for", player.DisplayName, "at position", playerCFrame.Position)
|
||||
end)
|
||||
```
|
||||
|
||||
#### visibilityChanged
|
||||
|
||||
Fires when a locator icon is shown/hidden on the local player's screen. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>player: `Class.Player`</td>
|
||||
<td>`Class.Player` object that the locator icon belongs to.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>playerCFrame: `Datatype.CFrame`</td>
|
||||
<td>`Datatype.CFrame` of the player's `Class.Humanoid.RootPart` that the locator icon belongs to.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>isVisible: `boolean`</td>
|
||||
<td>Whether the locator icon is currently visible on the local player's screen. Note that this will still be `true` if `alwaysOnTop` is `false` and the locator renders behind an object in the 3D world.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local FriendsLocator = require(ReplicatedStorage.FriendsLocator)
|
||||
|
||||
FriendsLocator.visibilityChanged:Connect(function(player, playerCFrame, isVisible)
|
||||
print("Visibility of locator icon for", player.DisplayName, ":", isVisible)
|
||||
end)
|
||||
```
|
||||
59
.cursor/rules/roblox/en-us/resources/modules/index.md
Normal file
59
.cursor/rules/roblox/en-us/resources/modules/index.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
title: Developer modules
|
||||
description: Developer modules let you easily add powerful social features to your experiences.
|
||||
---
|
||||
|
||||
**Developer modules** let you easily add powerful social features to your experiences. Each module is **designed to work out of the box**, so the moment you press play it will simply work. If this isn't your style, you can configure each module to work in different ways.
|
||||
|
||||
<GridContainer numColumns="2">
|
||||
<figure>
|
||||
<Button href="../../resources/modules/selfie-mode.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Selfie Mode</Button>
|
||||
<video controls src="../../assets/developer-modules/selfie-mode/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Pose and capture memorable moments</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<Button href="../../resources/modules/merch-booth.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Merch Booth</Button>
|
||||
<video controls src="../../assets/developer-modules/merch-booth/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Sell avatar assets and more in an experience</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<Button href="../../resources/modules/friends-locator.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Friends Locator</Button>
|
||||
<video controls src="../../assets/developer-modules/friends-locator/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Easily spot your friends and teleport to them</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<Button href="../../resources/modules/spawn-with-friends.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Spawn With Friends</Button>
|
||||
<video controls src="../../assets/developer-modules/spawn-with-friends/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Join an experience right next to your friends</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<Button href="../../resources/modules/emote-bar.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Emote Bar</Button>
|
||||
<video controls src="../../assets/developer-modules/emote-bar/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Express yourself and have dance parties</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<Button href="../../resources/modules/profile-card.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Profile Card</Button>
|
||||
<video controls src="../../assets/developer-modules/profile-card/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Craft your identity within an experience</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<Button href="../../resources/modules/photo-booth.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Photo Booth</Button>
|
||||
<video controls src="../../assets/developer-modules/photo-booth/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Strike a pose with a unique background</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<Button href="../../resources/modules/surface-art.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Surface Art</Button>
|
||||
<video controls src="../../assets/developer-modules/surface-art/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Literally leave your mark in an experience</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<Button href="../../resources/modules/scavenger-hunt.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Scavenger Hunt</Button>
|
||||
<video controls src="../../assets/developer-modules/scavenger-hunt/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Encourage players to explore your space</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<Button href="../../resources/modules/social-interactions.md" fullWidth size='large' color='primary' variant='contained' style={{marginBottom:"4px;"}}>Social Interactions</Button>
|
||||
<video controls src="../../assets/developer-modules/social-interactions/Showcase-SM.mp4" width="100%"></video>
|
||||
<figcaption>Add a touch of realism to your avatars</figcaption>
|
||||
</figure>
|
||||
</GridContainer>
|
||||
1238
.cursor/rules/roblox/en-us/resources/modules/merch-booth.md
Normal file
1238
.cursor/rules/roblox/en-us/resources/modules/merch-booth.md
Normal file
File diff suppressed because it is too large
Load diff
368
.cursor/rules/roblox/en-us/resources/modules/photo-booth.md
Normal file
368
.cursor/rules/roblox/en-us/resources/modules/photo-booth.md
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
---
|
||||
title: Photo Booth
|
||||
description: The Photo Booth module lets players strike a unique pose with a background.
|
||||
---
|
||||
|
||||
Taking a photo is a perfect way to commemorate a great experience. The **PhotoBooth** [developer module](../../resources/modules/index.md) is an easy-to-use photo staging tool which lets the players strike a unique pose with a background that represents their experience.
|
||||
|
||||
<video src="../../assets/developer-modules/photo-booth/Showcase.mp4" controls width="100%"></video>
|
||||
|
||||
## Module usage
|
||||
|
||||
### Installation
|
||||
|
||||
To use the **PhotoBooth** module in an experience:
|
||||
|
||||
1. From Studio's **Window** menu or **Home** tab toolbar, open the [Toolbox](../../projects/assets/toolbox.md) and select the **Creator Store** tab.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" />
|
||||
|
||||
1. Make sure the **Models** sorting is selected, then click the **See All** button for **Categories**.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Categories-See-All.png" width="360" />
|
||||
|
||||
1. Locate and click the **Packages** tile.
|
||||
|
||||
1. Locate the **Photo Booth** module and click it, or drag-and-drop it into the 3D view.
|
||||
|
||||
<img src="../../assets/developer-modules/photo-booth/Toolbox-Icon.png" width="143" />
|
||||
|
||||
1. In the [Explorer](../../studio/explorer.md) window, move the entire **PhotoBooth** model into `Class.ReplicatedStorage`. Upon running the experience the module will begin running.
|
||||
|
||||
### Position the booth
|
||||
|
||||
The module comes with one **PhotoBooth** model that you can position in the 3D world. This model is what players will interact with to set up a photo.
|
||||
|
||||
1. Locate the **PhotoBooth** mesh inside the **Workspace** folder of the module's main folder.
|
||||
|
||||
<img src="../../assets/developer-modules/photo-booth/Bundled-Mesh-Explorer.png" width="320" />
|
||||
|
||||
1. Move it into the top-level **Workspace** hierarchy and position it where desired.
|
||||
|
||||
<img src="../../assets/developer-modules/photo-booth/Bundled-Mesh-Workspace.jpg" width="800" />
|
||||
|
||||
<Alert severity="info">
|
||||
It is not required that you use the packaged mesh for triggering photo printouts. The module uses `Class.CollectionService` to locate parts tagged as `PhotoBooth` and make them operate as photo booths. If desired, the `Class.CollectionService` tag name to search for can be changed by setting a different value for `photoboothTag` in a [configure](#configure) call.
|
||||
</Alert>
|
||||
|
||||
### Configuration
|
||||
|
||||
The module is preconfigured to work for most use cases, but it can be easily customized through the [configure](#configure) function. For example, to change the default message at the bottom of the photo:
|
||||
|
||||
1. In **StarterPlayerScripts**, create a new `Class.LocalScript` and rename it to **ConfigurePhotoBooth**.
|
||||
|
||||
<img src="../../assets/developer-modules/photo-booth/LocalScript-ConfigurePhotoBooth.png" width="320" />
|
||||
|
||||
1. Paste the following code into the new script.
|
||||
|
||||
```lua title="LocalScript - ConfigurePhotoBooth"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local PhotoBooth = require(ReplicatedStorage.PhotoBooth)
|
||||
|
||||
PhotoBooth.configure({
|
||||
frameMessage = "First Photo Booth Capture!",
|
||||
})
|
||||
```
|
||||
|
||||
<img src="../../assets/developer-modules/photo-booth/Changed-Message.jpg" width="800" />
|
||||
|
||||
### Connect to events
|
||||
|
||||
Every time the photo booth displays a new screen to a local client, a corresponding event is fired. These events can be connected in a `Class.LocalScript` so that you can respond with your own custom logic.
|
||||
|
||||
```lua title="LocalScript"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local PhotoBooth = require(ReplicatedStorage.PhotoBooth)
|
||||
|
||||
PhotoBooth.countdownStarted:Connect(function()
|
||||
print("The countdown has started")
|
||||
end)
|
||||
|
||||
PhotoBooth.printoutShown:Connect(function()
|
||||
print("The printout is showing")
|
||||
end)
|
||||
|
||||
PhotoBooth.promptShown:Connect(function()
|
||||
print("The camera prompt is showing")
|
||||
end)
|
||||
```
|
||||
|
||||
### GUI visibility
|
||||
|
||||
By default, the photo booth hides all `Class.ScreenGui|ScreenGuis` and `Class.CoreGui|CoreGuis` when a photo is staged. If you want to override this auto-hiding behavior and programmatically decide which GUIs should remain visible, include the [hideOtherGuis](#hideotherguis) and [showOtherGuis](#showotherguis) callbacks and respond with your own custom logic.
|
||||
|
||||
```lua title="LocalScript"
|
||||
local Players = game:GetService("Players")
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local StarterGui = game:GetService("StarterGui")
|
||||
|
||||
local PhotoBooth = require(ReplicatedStorage.PhotoBooth)
|
||||
|
||||
local player = Players.LocalPlayer
|
||||
local playerGui = player:WaitForChild("PlayerGui")
|
||||
local hiddenInstances = {}
|
||||
|
||||
-- Create a screen GUI that will not be hidden
|
||||
local specialGuiInstance = Instance.new("ScreenGui")
|
||||
-- Draw the screen GUI above the photo booth GUI
|
||||
specialGuiInstance.DisplayOrder = 1
|
||||
specialGuiInstance.Parent = playerGui
|
||||
-- Set attribute on screen GUI to prevent hiding
|
||||
specialGuiInstance:SetAttribute("ShowInPhotoBooth", true)
|
||||
-- Add text label to the GUI
|
||||
local specialLabel = Instance.new("TextLabel")
|
||||
specialLabel.Size = UDim2.fromScale(1, 0.1)
|
||||
specialLabel.Text = "Remains visible when taking a photo"
|
||||
specialLabel.Font = Enum.Font.GothamMedium
|
||||
specialLabel.TextSize = 24
|
||||
specialLabel.Parent = specialGuiInstance
|
||||
|
||||
PhotoBooth.hideOtherGuis(function()
|
||||
-- Hide all developer-defined screen GUIs except those marked with attribute
|
||||
local instances = playerGui:GetChildren()
|
||||
for _, instance in instances do
|
||||
if instance:IsA("ScreenGui") and not instance:GetAttribute("ShowInPhotoBooth") and instance.Enabled then
|
||||
instance.Enabled = false
|
||||
table.insert(hiddenInstances, instance)
|
||||
end
|
||||
end
|
||||
-- Hide specific core GUIs
|
||||
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, false)
|
||||
end)
|
||||
|
||||
PhotoBooth.showOtherGuis(function()
|
||||
-- Show all developer-defined screen GUIs that were hidden
|
||||
for _, instance in hiddenInstances do
|
||||
instance.Enabled = true
|
||||
end
|
||||
hiddenInstances = {}
|
||||
-- Show specific core GUIs that were hidden
|
||||
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, true)
|
||||
end)
|
||||
```
|
||||
|
||||
## API reference
|
||||
|
||||
### Functions
|
||||
|
||||
#### configure
|
||||
|
||||
<figcaption>
|
||||
configure(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default configuration options through the following keys/values in the `config` table. This function can only be called from a `Class.LocalScript`.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Appearance">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`frameMessage`</td>
|
||||
<td>Message that is shown at the bottom of the photo. Its duration can be controlled via the `fadeUiDelay` property.</td>
|
||||
<td>"Use your device to take a screenshot and share!"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`fadeUiDelay`</td>
|
||||
<td>Time to show the frame message before it fades out, in seconds. Set to a negative number to never fade.</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`closeButtonImage`</td>
|
||||
<td>Image to use for the close photo button, placed overtop the `closeButtonBackgroundImage` image.</td>
|
||||
<td>"rbxassetid://7027440823"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`closeButtonBackgroundImage`</td>
|
||||
<td>Background image to use for the close photo button.</td>
|
||||
<td>"rbxassetid://7027440891"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`cameraLandscapePosition`</td>
|
||||
<td>Distance of the photo booth's camera, in front and upward from the character, when taking a photo in landscape mode (`Datatype.Vector2`).</td>
|
||||
<td>(5, 2)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`cameraPortraitPosition`</td>
|
||||
<td>Distance of the photo booth's camera, in front and upward from the character, when taking a photo in portrait mode (`Datatype.Vector2`).</td>
|
||||
<td>(10, 1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`countdownFont`</td>
|
||||
<td>Font to use for the numbers in the countdown (`Enum.Font`).</td>
|
||||
<td>`Enum.Font|GothamBlack`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`countdownTextColor`</td>
|
||||
<td>Color of the numbers in the countdown (`Datatype.Color3`).</td>
|
||||
<td>[255, 255, 255]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`printoutCharacterPosition`</td>
|
||||
<td>Position of the character on the screen when the printout is showing (`Datatype.UDim2`).</td>
|
||||
<td>(0.5, 0, 0.5, 0)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`printoutCharacterSize`</td>
|
||||
<td>Amount of screen space the character takes up in the printout (`Datatype.UDim2`).</td>
|
||||
<td>(1, 0, 1, 0)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`characterAnimation`</td>
|
||||
<td>Asset ID of the animation the character takes in the photo, paused at its starting frame.</td>
|
||||
<td>"rbxassetid://6899663224"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`filterImage`</td>
|
||||
<td>Image to apply over the photo as a filter. If `nil`, a default filter that darkens the image edges will be used.</td>
|
||||
<td>`nil`</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Behavior">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`maxActivationDistance`</td>
|
||||
<td>Maximum distance, in studs, a player's character can be from the photo booth for the prompt to appear.</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`countdownBeepSound`</td>
|
||||
<td>Asset ID of the `Class.Sound` to play for each number shown in the countdown.</td>
|
||||
<td>"rbxassetid://7743999789"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`countdownFlashSound`</td>
|
||||
<td>Asset ID for the `Class.Sound` to play when the flash effect is shown.</td>
|
||||
<td>"rbxassetid://7744000850"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`countdownSeconds`</td>
|
||||
<td>Number of seconds to count down for.</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`photoboothTag`</td>
|
||||
<td>Tag used by `Class.CollectionService` to find all "booths" in the place.</td>
|
||||
<td>"PhotoBooth"</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
```lua title="LocalScript - ConfigurePhotoBooth"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local PhotoBooth = require(ReplicatedStorage.PhotoBooth)
|
||||
|
||||
PhotoBooth.configure({
|
||||
frameMessage = "What a cool pose!",
|
||||
fadeUiDelay = 5,
|
||||
maxActivationDistance = 5,
|
||||
printoutCharacterSize = UDim2.fromScale(1.5, 1.5),
|
||||
})
|
||||
```
|
||||
|
||||
#### setBackgrounds
|
||||
|
||||
<figcaption>
|
||||
setBackgrounds(backgrounds: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides the default backgrounds provided by the photo booth. Background images should be at 16:9 aspect ratio (1024×768) for an optimal experience and their asset IDs should be included in the backgrounds array. 1–4 (inclusive) backgrounds can be provided.
|
||||
|
||||
```lua title="LocalScript"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local PhotoBooth = require(ReplicatedStorage.PhotoBooth)
|
||||
|
||||
PhotoBooth.setBackgrounds({
|
||||
"rbxassetid://7018713114",
|
||||
"rbxassetid://950538356",
|
||||
})
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
#### countdownStarted
|
||||
|
||||
Fires when the countdown starts. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local PhotoBooth = require(ReplicatedStorage.PhotoBooth)
|
||||
|
||||
PhotoBooth.countdownStarted:Connect(function()
|
||||
print("The countdown has started")
|
||||
end)
|
||||
```
|
||||
|
||||
#### printoutShown
|
||||
|
||||
Fires when the printout is shown to the user. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local PhotoBooth = require(ReplicatedStorage.PhotoBooth)
|
||||
|
||||
PhotoBooth.printoutShown:Connect(function()
|
||||
print("The printout is showing")
|
||||
end)
|
||||
```
|
||||
|
||||
#### promptShown
|
||||
|
||||
Fires when the printout is closed and the camera button is showing again. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local PhotoBooth = require(ReplicatedStorage.PhotoBooth)
|
||||
|
||||
PhotoBooth.promptShown:Connect(function()
|
||||
print("The camera prompt is showing")
|
||||
end)
|
||||
```
|
||||
|
||||
### Callbacks
|
||||
|
||||
#### hideOtherGuis
|
||||
|
||||
<figcaption>
|
||||
hideOtherGuis(callback: `function`)
|
||||
</figcaption>
|
||||
|
||||
This callback runs immediately before the printout is displayed, letting you disable entire `Class.ScreenGui|ScreenGuis` or elements within them before the printout is shown. GUIs used by the photo booth have the attribute **ShowInPhotoBooth** set to **true**. See [GUI Visibility](#gui-visibility) for details and sample code.
|
||||
|
||||
#### showOtherGuis
|
||||
|
||||
<figcaption>
|
||||
showOtherGuis(callback: `function`)
|
||||
</figcaption>
|
||||
|
||||
This callback runs after the printout has been closed, letting you reenable entire `Class.ScreenGui|ScreenGuis` or elements within them. GUIs used by the photo booth have the attribute **ShowInPhotoBooth** set to **true**. See [GUI Visibility](#gui-visibility) for details and sample code.
|
||||
215
.cursor/rules/roblox/en-us/resources/modules/profile-card.md
Normal file
215
.cursor/rules/roblox/en-us/resources/modules/profile-card.md
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
---
|
||||
title: Profile Card
|
||||
description: The Profile Card module lets players see more information about other players in an experience.
|
||||
---
|
||||
|
||||
It can be interesting to learn about other players. The **ProfileCard** [developer module](../../resources/modules/index.md) is a great way to see more information about others within an experience, from badges achieved to the player's favorite experiences.
|
||||
|
||||
<video src="../../assets/developer-modules/profile-card/Showcase.mp4" controls width="100%"></video>
|
||||
|
||||
## Module usage
|
||||
|
||||
### Installation
|
||||
|
||||
To use the **ProfileCard** module in an experience:
|
||||
|
||||
1. From Studio's **Window** menu or **Home** tab toolbar, open the [Toolbox](../../projects/assets/toolbox.md) and select the **Creator Store** tab.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" />
|
||||
|
||||
1. Make sure the **Models** sorting is selected, then click the **See All** button for **Categories**.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Categories-See-All.png" width="360" />
|
||||
|
||||
1. Locate and click the **Packages** tile.
|
||||
|
||||
1. Locate the **Profile Card** module and click it, or drag-and-drop it into the 3D view.
|
||||
|
||||
<img src="../../assets/developer-modules/profile-card/Toolbox-Icon.png" width="143" />
|
||||
|
||||
1. In the [Explorer](../../studio/explorer.md) window, move the entire **ProfileCard** model into `Class.ReplicatedStorage`. Upon running the experience the module will begin running.
|
||||
|
||||
### Views
|
||||
|
||||
Profile cards have different views depending on whether you're viewing your own card or another player's card.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Your Card">
|
||||
When you first spawn into the experience, an icon appears over your character. Clicking the icon opens the profile card view. Once the card is closed, the icon disappears, but you can reopen the card at any time by clicking your character.
|
||||
|
||||
<img src="../../assets/developer-modules/profile-card/Player-Icon.jpg" width="800" />
|
||||
|
||||
When viewing your own card, it appears as it would to another player, except placeholder text will appear for any blank inputs. Additionally, the status string is subject to **text filtering**, as any free text input should be.
|
||||
|
||||
<GridContainer numColumns="2">
|
||||
<figure>
|
||||
<img src="../../assets/developer-modules/profile-card/Player-Card-Status-Empty.png" />
|
||||
<figcaption>Card without custom status</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="../../assets/developer-modules/profile-card/Player-Card-Status-Set.png" />
|
||||
<figcaption>Card with custom status</figcaption>
|
||||
</figure>
|
||||
</GridContainer>
|
||||
<GridContainer numColumns="2">
|
||||
<figure>
|
||||
<img src="../../assets/developer-modules/profile-card/Player-Card-Status-Entering.png" />
|
||||
<figcaption>Entering a custom status</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="../../assets/developer-modules/profile-card/Player-Card-Status-Invalid.png" />
|
||||
<figcaption>Attempt to enter invalid status</figcaption>
|
||||
</figure>
|
||||
</GridContainer>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Other Player's Card">
|
||||
Icons do not appear over other characters, but clicking on a character will open their profile card. The button in the upper-right corner of the card lets you quickly request that player as a connection.
|
||||
|
||||
Note that players under the age of 13 will only see the status message if it's appropriate for their age group.
|
||||
|
||||
<GridContainer numColumns="2">
|
||||
<figure>
|
||||
<img src="../../assets/developer-modules/profile-card/Other-Card-Status-Set.png" />
|
||||
<figcaption>Card with custom status</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="../../assets/developer-modules/profile-card/Other-Card-Status-Empty.png" />
|
||||
<figcaption>Card without custom status</figcaption>
|
||||
</figure>
|
||||
</GridContainer>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## API reference
|
||||
|
||||
### Functions
|
||||
|
||||
#### configure
|
||||
|
||||
<figcaption>
|
||||
configure(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default configuration options through the following keys/values in the `config` table. This function should be called from a `Class.LocalScript` within **StarterPlayerScripts**.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`alwaysOnTop`</td>
|
||||
<td>If `true`, shows locator icons on top of everything, preventing them from being blocked by 3D world objects.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`showPersonalIndicator`</td>
|
||||
<td>If `true`, shows the personal indicator when a player first joins the experience.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`showBlur`</td>
|
||||
<td>If `true`, shows the blurry screen background when a player enters edit mode.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`maxClickDistance`</td>
|
||||
<td>Maximum distance from the camera viewpoint a card will appear when a character is clicked, measured in studs.</td>
|
||||
<td>100</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`backgroundColor`</td>
|
||||
<td>Background color for the card (`Datatype.Color3`).</td>
|
||||
<td>[228, 255, 255]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`backgroundTransparency`</td>
|
||||
<td>Transparency of the card's `backgroundColor`.</td>
|
||||
<td>0.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`isScaled`</td>
|
||||
<td>If `true`, automatically scales the size of the text to fill the height of the space.</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`isTruncated`</td>
|
||||
<td>If `true`, automatically hides the ends of strings that would otherwise be too long for proper viewing.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`hasRoundedCorners`</td>
|
||||
<td>If `true`, the card's corners will be rounded.</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`cornerRadiusValue`</td>
|
||||
<td>Value of the `Class.UICorner` corner radius, if `hasRoundedCorners` is `true`.</td>
|
||||
<td>20</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`hasBorder`</td>
|
||||
<td>If `true`, shows a border for the card.</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`borderColor`</td>
|
||||
<td>Color of the card's border (`Datatype.Color3`). Only applies if `hasBorder` is `true`.</td>
|
||||
<td>[228, 255, 255]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`borderThickness`</td>
|
||||
<td>Thickness of the card's border, if `hasBorder` is `true`.</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`borderTransparency`</td>
|
||||
<td>Transparency of the card's border, if `hasBorder` is `true`.</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`borderLineJoinMode`</td>
|
||||
<td>Corner style of the card's border (`Enum.LineJoinMode`). Only applies if `hasBorder` is `true`.</td>
|
||||
<td>`Enum.LineJoinMode|Round`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`headerFontSize`</td>
|
||||
<td>Font size for the card's header.</td>
|
||||
<td>18</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`headerFontType`</td>
|
||||
<td>Font type for the card's header (`Enum.Font`).</td>
|
||||
<td>`Enum.Font|GothamBlack`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`textFontSize`</td>
|
||||
<td>Font size for the card's body text.</td>
|
||||
<td>15</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`textFontType`</td>
|
||||
<td>Font type for the card's body text (`Enum.Font`).</td>
|
||||
<td>`Enum.Font|GothamMedium`</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="5-10"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ProfileCard = require(ReplicatedStorage.ProfileCard)
|
||||
|
||||
ProfileCard.configure({
|
||||
alwaysOnTop = true,
|
||||
maxClickDistance = 50,
|
||||
backgroundColor = Color3.fromRGB(0, 0, 0),
|
||||
backgroundTransparency = 0.4
|
||||
})
|
||||
```
|
||||
665
.cursor/rules/roblox/en-us/resources/modules/scavenger-hunt.md
Normal file
665
.cursor/rules/roblox/en-us/resources/modules/scavenger-hunt.md
Normal file
|
|
@ -0,0 +1,665 @@
|
|||
---
|
||||
title: Scavenger Hunt
|
||||
description: The Scavenger Hunt module gives players an inherently gamified way to explore an experience.
|
||||
---
|
||||
|
||||
The **ScavengerHunt** [developer module](../../resources/modules/index.md) gives players an inherently gamified way to explore your experience, organically introducing them to the entire place. Player progress is persistent, so scavenger hunts can continue across sessions.
|
||||
|
||||
<video src="../../assets/developer-modules/scavenger-hunt/Showcase.mp4" controls width="100%"></video>
|
||||
|
||||
<Alert severity="warning">
|
||||
This module utilizes [data stores](../../cloud-services/data-stores/index.md). To test it in Studio, make sure **Enable Studio Access to API Services** is enabled from the **Security** section of Studio's **File** ⟩ **Experience Settings** window.
|
||||
</Alert>
|
||||
|
||||
## Module usage
|
||||
|
||||
### Installation
|
||||
|
||||
To use the **ScavengerHunt** module in an experience:
|
||||
|
||||
1. From Studio's **Window** menu or **Home** tab toolbar, open the [Toolbox](../../projects/assets/toolbox.md) and select the **Creator Store** tab.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" />
|
||||
|
||||
1. Make sure the **Models** sorting is selected, then click the **See All** button for **Categories**.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Categories-See-All.png" width="360" />
|
||||
|
||||
1. Locate and click the **Packages** tile.
|
||||
|
||||
1. Locate the **Scavenger Hunt** module and click it, or drag-and-drop it into the 3D view.
|
||||
|
||||
<img src="../../assets/developer-modules/scavenger-hunt/Toolbox-Icon.png" width="143" />
|
||||
|
||||
1. In the [Explorer](../../studio/explorer.md) window, move the entire **ScavengerHunt** model into `Class.ReplicatedStorage`. Upon running the experience the module will begin running.
|
||||
|
||||
### Use tokens
|
||||
|
||||
The scavenger hunt module uses **tokens** as the items which players search for and collect. The module comes with one token model that you can position in the 3D world.
|
||||
|
||||
1. Locate the **Token1** mesh inside the **Workspace** folder of the module's main folder.
|
||||
|
||||
<img src="../../assets/developer-modules/scavenger-hunt/Token1-Explorer.png" width="320" />
|
||||
|
||||
1. Move **Token1** into the top-level **Workspace** hierarchy and position it where desired.
|
||||
1. Give the token a **unique name**; this name is how the module tracks which tokens each player has collected.
|
||||
1. To add more tokens, duplicate an existing token and give it a unique name.
|
||||
|
||||
If you don't want to use the bundled mesh tokens, any `Class.Model` or `Class.BasePart` will work, as long as it meets the following criteria:
|
||||
|
||||
- Object has a `Class.CollectionService` tag of `ScavengerHuntPart`. If desired, the `Class.CollectionService` tag name which the module utilizes can be changed by setting a different value for `tokenTag` in a [configureServer](#configureserver) call.
|
||||
- Object contains a child `Class.StringValue` instance set to the "flavor text" to display when the token is collected.
|
||||
|
||||
<Grid container spacing={3}>
|
||||
<Grid item>
|
||||
<figure>
|
||||
<img src="../../assets/developer-modules/scavenger-hunt/Token-Model-Structure.png" width="320" />
|
||||
<figcaption>Model</figcaption>
|
||||
</figure>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<figure>
|
||||
<img src="../../assets/developer-modules/scavenger-hunt/Token-BasePart-Structure.png" width="320" />
|
||||
<figcaption>MeshPart</figcaption>
|
||||
</figure>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Alert severity="error">
|
||||
Remember that each token must have a unique name as a means of tracking player progress.
|
||||
</Alert>
|
||||
|
||||
<Alert severity="info">
|
||||
The module will automatically disable the `Class.BasePart.CanCollide|CanCollide` property of tokens at runtime so that players do not physically collide with them. As such, all tokens should be **anchored** so they do not fall through the world geometry.
|
||||
</Alert>
|
||||
|
||||
### Use regions
|
||||
|
||||
Regions differ slightly from tokens, as large areas that are marked as "collected" once the player enters them. Additionally, when a player leaves the region, the flavor text modal automatically dismisses and the region itself is removed from the workspace.
|
||||
|
||||
1. Create an anchored part around the region, such as a block or sphere. The module will automatically disable the `Class.BasePart.CanCollide|CanCollide` property on runtime so players do not physically collide with the region.
|
||||
1. Give it a **unique name**. This name is how the module tracks which regions each player has entered.
|
||||
1. Using the [Tags](../../studio/properties.md#instance-tags) section of the part's properties, apply the tag `ScavengerHuntPart` to the part so that `Class.CollectionService` detects it. If desired, the tag name which the module utilizes can be changed by setting a different value for `tokenTag` in a [configureServer](#configureserver) call.
|
||||
1. Include a child `Class.StringValue` instance set to the "flavor text" to display when the region is entered.
|
||||
|
||||
<img src="../../assets/developer-modules/scavenger-hunt/Region-Structure.png" width="320" />
|
||||
|
||||
<Alert severity="error">
|
||||
Remember that each region must have a unique name as a means of tracking player progress.
|
||||
</Alert>
|
||||
|
||||
### Configuration
|
||||
|
||||
The module is preconfigured to work for most use cases, but it can be easily customized. For example, to change the token rotation speed and customize the modal info message:
|
||||
|
||||
1. In **StarterPlayerScripts**, create a new `Class.LocalScript` and rename it to **ConfigureScavengerHunt**.
|
||||
1. Paste the following code into the new script.
|
||||
|
||||
```lua title="LocalScript - ConfigureScavengerHunt" highlight="5-9"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.configureClient({
|
||||
infoModalText = "Welcome to my Scavenger Hunt!",
|
||||
completeModalText = "Thanks for playing my Scavenger Hunt!",
|
||||
tokenRotationSpeed = 60,
|
||||
})
|
||||
```
|
||||
|
||||
### Collection events
|
||||
|
||||
Every time a player collects a token or enters a region, the [collected](#collected) event fires. You can listen to this event from a server-side `Class.Script` and respond accordingly. The connected function receives the `Class.Player` that collided with the token or entered the region and that token or region's name.
|
||||
|
||||
Similarly, when a player collects **all** tokens or enters **all** tagged regions, the [allCollected](#allcollected) event fires and the connected function receives the associated `Class.Player`. This function is only fired once per player and it can be used to reward that player with a [badge](../../production/publishing/badges.md), access to a new area, [in-experience currency](../../production/monetization/developer-products.md), etc.
|
||||
|
||||
```lua title="Script" highlight="5-7, 9-11"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.collected:Connect(function(player, itemName)
|
||||
print(player.DisplayName, itemName)
|
||||
end)
|
||||
|
||||
ScavengerHunt.allCollected:Connect(function(player)
|
||||
print(player.DisplayName .. " completed the hunt!")
|
||||
end)
|
||||
```
|
||||
|
||||
### Custom GUI
|
||||
|
||||
This module exposes several options to customize its default GUI, but you can opt to display custom GUI elements instead.
|
||||
|
||||
When `useCustomModals` is set to `true` in the [configureClient](#configureclient) function, the [showInfoModal](#showinfomodal) event fires every time the player activates the token tracker. Similarly, the [showCompleteModal](#showcompletemodal) event fires when the player has collected everything in the scavenger hunt. Both of these events can be listened to in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="6-10, 12-16"
|
||||
local Players = game:GetService("Players")
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.showInfoModal:Connect(function()
|
||||
-- Show a custom info modal
|
||||
local infoModal = Players.LocalPlayer.PlayerGui.ScavengerInfoModal
|
||||
infoModal.Enabled = true
|
||||
end)
|
||||
|
||||
ScavengerHunt.showCompleteModal:Connect(function()
|
||||
-- Show a custom complete modal
|
||||
local completeModal = Players.LocalPlayer.PlayerGui.ScavengerCompleteModal
|
||||
completeModal.Enabled = true
|
||||
end)
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
When using custom modals, be sure to provide a way for players to close/hide them, or an automatic dismissal after a delay.
|
||||
</Alert>
|
||||
|
||||
### GUI visibility
|
||||
|
||||
By default, the scavenger hunt hides all `Class.ScreenGui|ScreenGuis` and `Class.CoreGui|CoreGuis` (except for the player list) when the info modal or completion modal appears. If you want to override this auto-hiding behavior and programmatically decide which GUIs should remain visible, include the [hideOtherGuis](#hideotherguis) and [showOtherGuis](#showotherguis) callbacks and respond with your own custom logic.
|
||||
|
||||
```lua title="LocalScript" highlight="24, 37"
|
||||
local Players = game:GetService("Players")
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local StarterGui = game:GetService("StarterGui")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
local player = Players.LocalPlayer
|
||||
local playerGui = player:WaitForChild("PlayerGui")
|
||||
local hiddenInstances = {}
|
||||
|
||||
-- Create a screen GUI that will not be hidden
|
||||
local specialGuiInstance = Instance.new("ScreenGui")
|
||||
-- Draw the screen GUI above the scavenger hunt GUI
|
||||
specialGuiInstance.DisplayOrder = 1
|
||||
specialGuiInstance.Parent = playerGui
|
||||
-- Add text label to the GUI
|
||||
local specialLabel = Instance.new("TextLabel")
|
||||
specialLabel.Size = UDim2.fromScale(1, 0.1)
|
||||
specialLabel.Text = "Remains visible when displaying modals"
|
||||
specialLabel.Font = Enum.Font.GothamMedium
|
||||
specialLabel.TextSize = 24
|
||||
specialLabel.Parent = specialGuiInstance
|
||||
|
||||
ScavengerHunt.hideOtherGuis(function()
|
||||
-- Hide all developer-defined screen GUIs
|
||||
local instances = playerGui:GetChildren()
|
||||
for _, instance in instances do
|
||||
if instance:IsA("ScreenGui") and not instance.Name == "ScavengerHunt" and instance.Enabled then
|
||||
instance.Enabled = false
|
||||
table.insert(hiddenInstances, instance)
|
||||
end
|
||||
end
|
||||
-- Hide specific core GUIs
|
||||
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, false)
|
||||
end)
|
||||
|
||||
ScavengerHunt.showOtherGuis(function()
|
||||
-- Show all developer-defined screen GUIs that were hidden
|
||||
for _, instance in hiddenInstances do
|
||||
instance.Enabled = true
|
||||
end
|
||||
hiddenInstances = {}
|
||||
-- Show specific core GUIs that were hidden
|
||||
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, true)
|
||||
end)
|
||||
```
|
||||
|
||||
## API reference
|
||||
|
||||
### Functions
|
||||
|
||||
#### configureClient
|
||||
|
||||
<figcaption>
|
||||
configureClient(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default client-side configuration options through the following keys/values in the `config` table. This function can only be called from a `Class.LocalScript`.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="General">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`autoDismissTime`</td>
|
||||
<td>Time in seconds before the modal automatically dismisses itself or navigates to the next page if there is one. Set to 0 to disable.</td>
|
||||
<td>20</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`closeModalGamepad`</td>
|
||||
<td>Gamepad button used to close modals (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|ButtonA`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`closeModalKeyboard`</td>
|
||||
<td>Keyboard key used to close modals (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|E`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`completeModalText`</td>
|
||||
<td>Text to show on the modal that appears after clicking the token tracker when the scavenger hunt is complete.</td>
|
||||
<td>"Thanks for participating!"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`infoModalText`</td>
|
||||
<td>Text to show on the modal that appears after clicking the token tracker.</td>
|
||||
<td>"Find all the tokens to complete the hunt"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`tokenRotationSpeed`</td>
|
||||
<td>Speed at which the tokens rotate, in degrees per second. Set to 0 to prevent rotation.</td>
|
||||
<td>20</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`nextArrowImage`</td>
|
||||
<td>Image used to indicate there are more modal pages to show after the current modal page.</td>
|
||||
<td>"rbxassetid://8167172095"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`openTokenTrackerGamepad`</td>
|
||||
<td>Gamepad button used to show the modals that appear after activating the token tracker (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|ButtonY`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`openTokenTrackerKeyboard`</td>
|
||||
<td>Keyboard key used to show the modals that appear after activating the token tracker (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|Y`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`openTokenTrackerGamepadButtonImage`</td>
|
||||
<td>Image for the gamepad button that is used to activate the token tracker.</td>
|
||||
<td>"rbxassetid://8025860488"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`regionIcon`</td>
|
||||
<td>Icon to display next to the token tracker when entering regions.</td>
|
||||
<td>"rbxassetid://8073794624"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`tokenIcon`</td>
|
||||
<td>Icon to display next to the token tracker when collecting tokens.</td>
|
||||
<td>"rbxassetid://8073794477"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`tokenTrackerPositionSmallDevice`</td>
|
||||
<td>Position of the token tracker UI on small devices such as phones (`Datatype.UDim2`).</td>
|
||||
<td>(1, 0, 0, 84)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`tokenTrackerPositionLargeDevice`</td>
|
||||
<td>Position of the token tracker UI on larger devices like tablets and PC (`Datatype.UDim2`).</td>
|
||||
<td>(1, 0, 1, -16)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`useRegions`</td>
|
||||
<td>Instead of [tokens](#use-tokens), use [regions](#use-regions).</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Modals">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`modal.backgroundColor`</td>
|
||||
<td>Background color of the modals (`Datatype.Color3`).</td>
|
||||
<td>[0, 0, 0]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`modal.font`</td>
|
||||
<td>Font of the text that appears in a modal (`Enum.Font`).</td>
|
||||
<td>`Enum.Font|GothamMedium`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`modal.textColor`</td>
|
||||
<td>Color of the text that appears in a modal (`Datatype.Color3`).</td>
|
||||
<td>[255, 255, 255]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`modal.textSize`</td>
|
||||
<td>Size of the text that appears in a modal.</td>
|
||||
<td>16</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`useCustomModals`</td>
|
||||
<td>If true, default modals are not displayed. This lets you show custom modals as outlined in [Custom GUI](#custom-gui).</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`useCustomTokenTracker`</td>
|
||||
<td>If true, the default token tracker is not displayed. This lets you show a custom token tracker GUI instead.</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Navigation Beam">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`showNavigationBeam`</td>
|
||||
<td>If true, a `Class.Beam` from the player to the nearest token will be shown.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.color`</td>
|
||||
<td>`Datatype.ColorSequence` defining the beam's color across its segments. See `Class.Beam.Color` for details.</td>
|
||||
<td>[255, 255, 255] → [255, 255, 255]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.curveSize0`</td>
|
||||
<td>Position of the first control point in the beam's Bézier curve. See `Class.Beam.CurveSize0` for more info.</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.curveSize1`</td>
|
||||
<td>Position of the second control point in the beam's Bézier curve. See `Class.Beam.CurveSize1` for more info.</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.faceCamera`</td>
|
||||
<td>Whether the beam's segments will always face the camera regardless of its orientation. See `Class.Beam.FaceCamera` for details.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.lightEmission`</td>
|
||||
<td>Degree to which the colors of the beam are blended with the colors behind it. See `Class.Beam.LightEmission` for details.</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.lightInfluence`</td>
|
||||
<td>Degree to which the beam is influenced by the environment's lighting. See `Class.Beam.LightInfluence` for details.</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.segments`</td>
|
||||
<td>How many straight segments the beam is made up of.</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.texture`</td>
|
||||
<td>Asset ID of the texture to be displayed on the beam.</td>
|
||||
<td>"rbxassetid://8081777495"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.textureLength`</td>
|
||||
<td>Length of the beam's texture, depending on the setting for `navigationBeam.textureMode`. See `Class.Beam.TextureLength` for details.</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.textureMode`</td>
|
||||
<td>Manner in which the beam texture scales and repeats (`Enum.TextureMode`).</td>
|
||||
<td>`Enum.TextureMode|Wrap`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.textureSpeed`</td>
|
||||
<td>Speed at which the texture image moves along the beam.</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.transparency`</td>
|
||||
<td>`Datatype.NumberSequence` defining the beam's transparency across its segments. See `Class.Beam.Transparency` for details.</td>
|
||||
<td>(0, 0) → (0.15, 1) → (1, 1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.width0`</td>
|
||||
<td>Width of the beam at its base, in studs.</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.width1`</td>
|
||||
<td>Width of the beam at its end, in studs.</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`navigationBeam.zOffset`</td>
|
||||
<td>Distance, in studs, by which the beam's display is offset, relative to the camera.</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
```lua title="LocalScript"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.configureClient({
|
||||
infoModalText = "Welcome to my Scavenger Hunt!",
|
||||
completeModalText = "Thanks for playing my Scavenger Hunt!",
|
||||
tokenRotationSpeed = 60,
|
||||
navigationBeam = {
|
||||
lightEmission = 1
|
||||
},
|
||||
modal = {
|
||||
textSize = 14
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
#### configureServer
|
||||
|
||||
<figcaption>
|
||||
configureServer(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default server-side configuration options through the following keys/values in the `config` table. This function can only be called from a `Class.Script`.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`tokenTag`</td>
|
||||
<td>Tag used by `Class.CollectionService` to find all the tokens or regions used in the scavenger hunt.</td>
|
||||
<td>"ScavengerHuntPart"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`datastoreName`</td>
|
||||
<td>Name of the `Class.DataStore` used by the scavenger hunt to store each player's collection progress.</td>
|
||||
<td>"ScavengerHuntTokens"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`resetOnPlayerRemoving`</td>
|
||||
<td>If true, resets the user's progress when they leave the experience; convenient for not saving progress while testing the scavenger hunt.</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="Script" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.configureServer({
|
||||
tokenTag = "GreenGem",
|
||||
})
|
||||
```
|
||||
|
||||
#### disable
|
||||
|
||||
<figcaption>
|
||||
disable()
|
||||
</figcaption>
|
||||
|
||||
Hides all UI for the scavenger hunt, disconnects all input event listeners, and prevents players from collecting tokens or interacting with regions. This function can only be called from a `Class.Script`.
|
||||
|
||||
```lua title="Script" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.disable()
|
||||
```
|
||||
|
||||
#### enable
|
||||
|
||||
<figcaption>
|
||||
enable()
|
||||
</figcaption>
|
||||
|
||||
Shows all UI for the scavenger hunt, connects all input event listeners, and allows players to collect tokens and interact with regions. This function can only be called from a `Class.Script`.
|
||||
|
||||
```lua title="Script" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.enable()
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
#### collected
|
||||
|
||||
Fires when a player collides with a token or enters a region. The connected function will receive the `Class.Player` that collided with the token or entered the region and the name of the token that was collided into or the region that was entered. This event can only be connected in a `Class.Script`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>player: `Class.Player`</td>
|
||||
<td>User who collided with a token or entered a region.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>itemName: `Library.string` </td>
|
||||
<td>Name of the token that was collided into or the region that was entered.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>totalCollected: `number`</td>
|
||||
<td>Total number of tokens collected by the user represented by `player`.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="Script" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.collected:Connect(function(player, itemName, totalCollected)
|
||||
print(player.DisplayName, itemName, totalCollected)
|
||||
end)
|
||||
```
|
||||
|
||||
#### allCollected
|
||||
|
||||
Fires when a player collects all tokens or enters all regions in the scavenger hunt. The connected function will receive the `Class.Player` that collected all tokens, and it is only ever fired once per player. This event can only be connected in a `Class.Script`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>player: `Class.Player`</td>
|
||||
<td>Player who collected all tokens or entered all regions.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="Script" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.allCollected:Connect(function(player)
|
||||
print(player.DisplayName .. " completed the hunt!")
|
||||
end)
|
||||
```
|
||||
|
||||
#### showInfoModal
|
||||
|
||||
Fires when the player clicks on the token tracker when the `useCustomModals` [configuration](#configureclient) option is set to true. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="6-9"
|
||||
local Players = game:GetService("Players")
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.showInfoModal:Connect(function()
|
||||
local infoModal = Players.LocalPlayer.PlayerGui.InfoModal
|
||||
infoModal.Enabled = true
|
||||
end)
|
||||
```
|
||||
|
||||
#### showCompleteModal
|
||||
|
||||
Fires when the player clicks on the token tracker when the `useCustomModals` [configuration](#configureclient) option is set to `true` and the player has collected all tokens in the scavenger hunt. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="6-9"
|
||||
local Players = game:GetService("Players")
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local ScavengerHunt = require(ReplicatedStorage.ScavengerHunt)
|
||||
|
||||
ScavengerHunt.showCompleteModal:Connect(function()
|
||||
local completeModal = Players.LocalPlayer.PlayerGui.CompleteModal
|
||||
completeModal.Enabled = true
|
||||
end)
|
||||
```
|
||||
|
||||
### Callbacks
|
||||
|
||||
#### hideOtherGuis
|
||||
|
||||
<figcaption>
|
||||
hideOtherGuis(callback: `function`)
|
||||
</figcaption>
|
||||
|
||||
This callback runs immediately before a modal is displayed, letting you disable entire `Class.ScreenGui|ScreenGuis` or elements within them before the modal is shown. See [GUI Visibility](#gui-visibility) for details and sample code.
|
||||
|
||||
#### showOtherGuis
|
||||
|
||||
<figcaption>
|
||||
showOtherGuis(callback: `function`)
|
||||
</figcaption>
|
||||
|
||||
This callback runs immediately after a modal has been dismissed, letting you enable entire `Class.ScreenGui|ScreenGuis` or elements within them. See [GUI Visibility](#gui-visibility) for details and sample code.
|
||||
754
.cursor/rules/roblox/en-us/resources/modules/selfie-mode.md
Normal file
754
.cursor/rules/roblox/en-us/resources/modules/selfie-mode.md
Normal file
|
|
@ -0,0 +1,754 @@
|
|||
---
|
||||
title: Selfie Mode
|
||||
description: The Selfie Mode module lets players capture screenshots to commemorate fun moments.
|
||||
---
|
||||
|
||||
Players already take screenshots to commemorate fun moments in experiences. The **SelfieMode** [developer module](../../resources/modules/index.md) lets players capture a cleaner memory of that moment without the chat window or player list, while also supporting filter effects, hiding of other characters, and posing.
|
||||
|
||||
<video src="../../assets/developer-modules/selfie-mode/Showcase.mp4" controls width="100%"></video>
|
||||
|
||||
## Module Usage
|
||||
|
||||
### Installation
|
||||
|
||||
To use the **SelfieMode** module in an experience:
|
||||
|
||||
1. From Studio's **Window** menu or **Home** tab toolbar, open the [Toolbox](../../projects/assets/toolbox.md) and select the **Creator Store** tab.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" />
|
||||
|
||||
1. Make sure the **Models** sorting is selected, then click the **See All** button for **Categories**.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Categories-See-All.png" width="360" />
|
||||
|
||||
1. Locate and click the **Packages** tile.
|
||||
|
||||
1. Locate the **Selfie Mode** module and click it, or drag-and-drop it into the 3D view.
|
||||
|
||||
<img src="../../assets/developer-modules/selfie-mode/Toolbox-Icon.png" width="143" />
|
||||
|
||||
1. In the [Explorer](../../studio/explorer.md) window, move the entire **SelfieMode** package into `Class.ReplicatedStorage`. Upon running the experience the module will begin running.
|
||||
|
||||
### Configuration
|
||||
|
||||
The module is preconfigured to work for most use cases, but you can easily customize it through the [configure](#configure) function.
|
||||
|
||||
1. In **StarterPlayerScripts**, create a new `Class.LocalScript` and rename it to **ConfigureSelfieMode**.
|
||||
1. Paste the following code into the new script.
|
||||
|
||||
```lua title="LocalScript - ConfigureSelfieMode" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.configure({
|
||||
disableCharacterMovement = true
|
||||
})
|
||||
```
|
||||
|
||||
### Character Movement
|
||||
|
||||
It may be advantageous to prevent the player's character from moving while in selfie mode. You can achieve this by setting `disableCharacterMovement` to true in a [configure](#configure) call.
|
||||
|
||||
```lua title="LocalScript - ConfigureSelfieMode" highlight="6"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.configure({
|
||||
disableCharacterMovement = true
|
||||
})
|
||||
```
|
||||
|
||||
### Selfie Mode Actions
|
||||
|
||||
**SelfieMode** comes with the following [actions](#action), each of which you can use with the [activateAction](#activateaction), [deactivateAction](#deactivateaction), and [toggleAction](#toggleaction) functions, or detect through the [actionActivated](#actionactivated) and [actionDeactivated](#actiondeactivated) events.
|
||||
|
||||
#### Depth-of-Field
|
||||
|
||||
By default, **SelfieMode** shows a generic **depth‑of‑field** effect (subtle blur of the background) when a player toggles the action.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Off">
|
||||
<img src="../../assets/developer-modules/selfie-mode/Depth-Of-Field-Off.jpg" width="90%" />
|
||||
</TabItem>
|
||||
<TabItem label="On">
|
||||
<img src="../../assets/developer-modules/selfie-mode/Depth-Of-Field-On.jpg" width="90%" />
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<Alert severity="warning">
|
||||
This effect does not render on mobile devices such as phones and tablets. As such, it will not be offered as an action on those devices.
|
||||
|
||||
On non-mobile devices, the player's graphics quality must be eight or higher to render depth‑of‑field. If their graphics quality is less than eight, they'll be prompted to increase it.
|
||||
</Alert>
|
||||
|
||||
To change the default depth‑of‑field effect, set `depthOfFieldEffect` to your own `Class.DepthOfFieldEffect` instance in a [configure](#configure) call.
|
||||
|
||||
```lua title="LocalScript - ConfigureSelfieMode" highlight="5-9, 12"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
local customDepthOfField = Instance.new("DepthOfFieldEffect")
|
||||
customDepthOfField.NearIntensity = 0
|
||||
customDepthOfField.FarIntensity = 1
|
||||
customDepthOfField.FocusDistance = 5
|
||||
customDepthOfField.InFocusRadius = 5
|
||||
|
||||
SelfieMode.configure({
|
||||
depthOfFieldEffect = customDepthOfField
|
||||
})
|
||||
```
|
||||
|
||||
#### Lock Gaze
|
||||
|
||||
The **Lock Gaze** toggle causes the player's character to look at the camera while setting up the selfie pose, within a realistic range of how far their neck can turn.
|
||||
|
||||
#### Hide Others
|
||||
|
||||
By default, other characters are visible alongside the player's character. Players can obtain a perfect solo shot by clicking the **Hide Others** button. When toggled on, other characters fade out of view and remain invisible until the action is toggled off.
|
||||
|
||||
#### Filter
|
||||
|
||||
The **Filter** action lets the player apply a preset filter from the options **Pop**, **Soft**, **Antique**, **Cute**, **Dramatic**, and **Monochrome**.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Soft">
|
||||
<img src="../../assets/developer-modules/selfie-mode/Filters-Soft.jpg" width="90%" />
|
||||
</TabItem>
|
||||
<TabItem label="Dramatic">
|
||||
<img src="../../assets/developer-modules/selfie-mode/Filters-Dramatic.jpg" width="90%" />
|
||||
</TabItem>
|
||||
<TabItem label="Monochrome">
|
||||
<img src="../../assets/developer-modules/selfie-mode/Filters-Monochrome.jpg" width="90%" />
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
#### Pose
|
||||
|
||||
The **Pose** action lets the player select a preset pose from the options **Cheer**, **Clapping**, **Dolphin**, **Flossing**, **Guitar**, **Jump Wave**, **Louder**, **Top Rock**, **Twirl**, and **Wave**.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Flossing">
|
||||
<img src="../../assets/developer-modules/selfie-mode/Poses-Flossing.jpg" width="90%" />
|
||||
</TabItem>
|
||||
<TabItem label="Louder">
|
||||
<img src="../../assets/developer-modules/selfie-mode/Poses-Louder.jpg" width="90%" />
|
||||
</TabItem>
|
||||
<TabItem label="Twirl">
|
||||
<img src="../../assets/developer-modules/selfie-mode/Poses-Twirl.jpg" width="90%" />
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## API Reference
|
||||
|
||||
### Types
|
||||
|
||||
#### Action
|
||||
|
||||
Each action is represented by a dictionary with the following key-value pairs:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`name`</td>
|
||||
<td>string</td>
|
||||
<td>Name of the action, shown first in tooltips.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`description`</td>
|
||||
<td>string</td>
|
||||
<td>Description of the action, shown after **name** in tooltips.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`icon`</td>
|
||||
<td>string</td>
|
||||
<td>Asset ID for the action's icon.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`activeIcon`</td>
|
||||
<td>string</td>
|
||||
<td>Asset ID for the action's icon in "active" state. Can only be used on parent actions, not sub-actions.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`actions`</td>
|
||||
<td>table</td>
|
||||
<td>Optional list of sub-actions. This allows you to create submenus of various other actions.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`parent`</td>
|
||||
<td>[Action](#action)</td>
|
||||
<td>The parent of the action; this only applies to a sub-action and points to the action that contains it.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`onActivated`</td>
|
||||
<td>function</td>
|
||||
<td>Optional callback function that runs when a player activates an action or sub-action. Typically, if an action contains sub-actions, only the sub-actions will need a callback defined as a means of knowing that the player activated the sub-action and did not simply "expand" the parent action.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.actionActivated:Connect(function(action)
|
||||
print(action.name, "activated")
|
||||
end)
|
||||
|
||||
SelfieMode.actionDeactivated:Connect(function(action)
|
||||
print(action.name, "deactivated")
|
||||
end)
|
||||
```
|
||||
|
||||
### Enums
|
||||
|
||||
#### SelfieMode.Action
|
||||
|
||||
**SelfieMode** comes with several [actions](#action). You can use this enum with the [activateAction](#activateaction), [deactivateAction](#deactivateaction), and [toggleAction](#toggleaction) functions.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`DepthOfField`</td>
|
||||
<td>Reference to the [Depth‑of‑Field](#depth-of-field) action.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`LockGaze`</td>
|
||||
<td>Reference to the [Lock Gaze](#lock-gaze) action.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`HideOthers`</td>
|
||||
<td>Reference to the [Hide Others](#hide-others) action.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`Filter`</td>
|
||||
<td>Reference to the [Filter](#filter) action.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`Pose`</td>
|
||||
<td>Reference to the [Pose](#pose) action.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="6"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
-- Activate "Filter" action
|
||||
SelfieMode.activateAction(SelfieMode.Action.Filter)
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
#### configure
|
||||
|
||||
<figcaption>
|
||||
configure(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default configuration options through the following keys/values in the `config` table. This function can only be called from a `Class.LocalScript`.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`disableCharacterMovement`</td>
|
||||
<td>If true, prevents character from moving while selfie mode is open.</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`depthOfFieldEffect`</td>
|
||||
<td>Optional custom `Class.DepthOfFieldEffect` instance that appears when the player toggles the [Depth of Field](#depth-of-field) action.</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript - ConfigureSelfieMode" highlight="6"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.configure({
|
||||
disableCharacterMovement = true
|
||||
})
|
||||
```
|
||||
|
||||
#### openSelfieMode
|
||||
|
||||
<figcaption>
|
||||
openSelfieMode()
|
||||
</figcaption>
|
||||
|
||||
A player will typically open selfie mode with the "camera" button on the right side of the screen, but this function lets you open it through code. When implementing a custom button as shown below, you should disable the default button through [setHudButtonEnabled](#sethudbuttonenabled). This function can only be called from a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="8, 12"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
local button = script.Parent
|
||||
|
||||
-- Remove the default button
|
||||
SelfieMode.setHudButtonEnabled(false)
|
||||
|
||||
-- Connect the custom button
|
||||
button.Activated:Connect(function()
|
||||
SelfieMode.openSelfieMode()
|
||||
end)
|
||||
```
|
||||
|
||||
#### closeSelfieMode
|
||||
|
||||
<figcaption>
|
||||
closeSelfieMode()
|
||||
</figcaption>
|
||||
|
||||
A player will typically close selfie mode with the **⊗** button at the bottom of the screen, but this function lets you close it through code. Can only be called from a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.closeSelfieMode()
|
||||
```
|
||||
|
||||
#### isSelfieModeOpen
|
||||
|
||||
<figcaption>
|
||||
isSelfieModeOpen(): `boolean`
|
||||
</figcaption>
|
||||
|
||||
Returns `true` if selfie mode is open as a result of player action or through [openSelfieMode](#openselfiemode). This function can only be called from a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.openSelfieMode()
|
||||
|
||||
print(SelfieMode.isSelfieModeOpen())
|
||||
```
|
||||
|
||||
#### setHudButtonEnabled
|
||||
|
||||
<figcaption>
|
||||
setHudButtonEnabled()
|
||||
</figcaption>
|
||||
|
||||
Sets whether the default button to enter selfie mode is shown. Useful when implementing [openSelfieMode](#openselfiemode) through a custom UI button. This function can only be called from a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="8, 12"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
local button = script.Parent
|
||||
|
||||
-- Remove the default button
|
||||
SelfieMode.setHudButtonEnabled(false)
|
||||
|
||||
-- Connect the custom button
|
||||
button.Activated:Connect(function()
|
||||
SelfieMode.openSelfieMode()
|
||||
end)
|
||||
```
|
||||
|
||||
#### getAction
|
||||
|
||||
<figcaption>
|
||||
getAction(action: [SelfieMode.Action](#selfiemodeaction)): [Action](#action)
|
||||
</figcaption>
|
||||
|
||||
Gets an [Action](#action) type through a [SelfieMode.Action](#selfiemodeaction) enum.
|
||||
|
||||
```lua title="LocalScript" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
local lockGazeAction = SelfieMode.getAction(SelfieMode.Action.LockGaze)
|
||||
```
|
||||
|
||||
#### activateAction
|
||||
|
||||
<figcaption>
|
||||
activateAction(action: [SelfieMode.Action](#action))
|
||||
</figcaption>
|
||||
|
||||
Programmatically activates one of the default [actions](#selfie-mode-actions). This is the same as when a player toggles the action on from the action bar. Can only be called from a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="6"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
-- Activate "Filter" action
|
||||
SelfieMode.activateAction(SelfieMode.Action.Filter)
|
||||
```
|
||||
|
||||
#### deactivateAction
|
||||
|
||||
<figcaption>
|
||||
deactivateAction(action: [SelfieMode.Action](#action))
|
||||
</figcaption>
|
||||
|
||||
Programmatically deactivates one of the default [actions](#selfie-mode-actions). This is the same as when a player toggles the action off from the action bar. Can only be called from a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="6"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
-- Deactivate "Filter" action
|
||||
SelfieMode.deactivateAction(SelfieMode.Action.Filter)
|
||||
```
|
||||
|
||||
#### toggleAction
|
||||
|
||||
<figcaption>
|
||||
toggleAction(action: [SelfieMode.Action](#action)): `boolean`
|
||||
</figcaption>
|
||||
|
||||
Toggles an [action](#selfie-mode-actions) on if it's off, or toggles it off if it's on. This is the same as when a player clicks the action from the action bar. Returns the new "is toggled on" state as a boolean. Can only be called from a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="5, 7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
local lockGazeAction = SelfieMode.getAction(SelfieMode.Action.LockGaze)
|
||||
|
||||
local isEnabled = SelfieMode.toggleAction(lockGazeAction)
|
||||
|
||||
if isEnabled then
|
||||
print("Activated", lockGazeAction.name)
|
||||
else
|
||||
print("Deactivated", lockGazeAction.name)
|
||||
end
|
||||
```
|
||||
|
||||
#### setTheme
|
||||
|
||||
<figcaption>
|
||||
setTheme(theme: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Configures the selfie mode theme, including text size, font, button/tooltip colors, and more. This function can only be called from a `Class.LocalScript`.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="General">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`textSize`</td>
|
||||
<td>Size of all text.</td>
|
||||
<td>16</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`font`</td>
|
||||
<td>Font used across all UI (`Enum.Font`).</td>
|
||||
<td>`Enum.Font|GothamMedium`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`padding`</td>
|
||||
<td>Main padding used for laying out UI elements (`Datatype.UDim`).</td>
|
||||
<td>(0, 12)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`paddingSmall`</td>
|
||||
<td>Smaller padding used for applying subtle margins between elements (`Datatype.UDim`).</td>
|
||||
<td>(0, 6)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`paddingScreen`</td>
|
||||
<td>Padding used around the screen edges to give selfie mode some breathing room (`Datatype.UDim`).</td>
|
||||
<td>(0, 24)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`backgroundColor`</td>
|
||||
<td>Background color used for the bar that displays the actions (`Datatype.Color3`).</td>
|
||||
<td>[0, 0, 0]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`scrollBarColor`</td>
|
||||
<td>Color of the scrollbar used in `Class.ScrollingFrame` elements of the module (`Datatype.Color3`).</td>
|
||||
<td>[255, 255, 255]</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Buttons and Tooltips">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`openButtonBackgroundColor`</td>
|
||||
<td>Background color of the HUD button on the right side of the screen used to open selfie mode (`Datatype.Color3`).</td>
|
||||
<td>[255, 255, 255]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`openButtonIconColor`</td>
|
||||
<td>Color of the HUD button's camera icon (`Datatype.Color3`).</td>
|
||||
<td>[0, 0, 0]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`closeButtonBackgroundColor`</td>
|
||||
<td>Background color of the "close" button (`Datatype.Color3`).</td>
|
||||
<td>[0, 0, 0]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`closeButtonIconColor`</td>
|
||||
<td>Icon color for the "close" button (`Datatype.Color3`).</td>
|
||||
<td>[255, 255, 255]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`actionButtonBackgroundColor`</td>
|
||||
<td>Background color of the various action buttons used for toggling actions (`Datatype.Color3`).</td>
|
||||
<td>[255, 255, 255]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`actionButtonIconColor`</td>
|
||||
<td>Icon color for the various action buttons (`Datatype.Color3`).</td>
|
||||
<td>[0, 0, 0]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`tooltipBackgroundColor`</td>
|
||||
<td>Background color of tooltips and notifications (`Datatype.Color3`).</td>
|
||||
<td>[0, 0, 0]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`tooltipNameColor`</td>
|
||||
<td>Text color of tooltip names (`Datatype.Color3`). Also used as the text color for notifications.</td>
|
||||
<td>[255, 255, 255]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`tooltipDescriptionColor`</td>
|
||||
<td>Color of tooltip descriptions, slightly faded to give focus to tooltip names (`Datatype.Color3`). Not used for notifications.</td>
|
||||
<td>[169, 169, 169]</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
```lua title="LocalScript" highlight=""
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.setTheme({
|
||||
textSize = 20,
|
||||
font = Enum.Font.Michroma,
|
||||
backgroundColor = Color3.fromRGB(0, 40, 75),
|
||||
})
|
||||
```
|
||||
|
||||
#### setEnabled
|
||||
|
||||
<figcaption>
|
||||
setEnabled(isEnabled: `boolean`)
|
||||
</figcaption>
|
||||
|
||||
Sets whether selfie mode is enabled or not. When disabled, all UI for the module is removed and all events are disconnected. This function can only be called from a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.setEnabled(false)
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
#### selfieModeOpened
|
||||
|
||||
Fires when the player opens selfie mode or when [openSelfieMode](#openselfiemode) is called. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.selfieModeOpened:Connect(function()
|
||||
print("Selfie mode open")
|
||||
end)
|
||||
```
|
||||
|
||||
#### selfieModeClosed
|
||||
|
||||
Fires when the player closes selfie mode or when [closeSelfieMode](#closeselfiemode) is called. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.selfieModeClosed:Connect(function()
|
||||
print("Selfie mode closed")
|
||||
end)
|
||||
```
|
||||
|
||||
#### actionActivated
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>action: [SelfieMode.Action](#action)</td>
|
||||
<td>The activated [Action](#action).</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Fires when an action is activated; this may be one of the primary actions like [Depth of Field](#depth-of-field), [Lock Gaze](#lock-gaze), or [Hide Others](#hide-others); alternatively it may be a sub-action like a [filter](#filter) or [pose](#pose). The connected function receives the activated [Action](#action). This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.actionActivated:Connect(function(action)
|
||||
print(action.name, "activated")
|
||||
end)
|
||||
```
|
||||
|
||||
#### actionDeactivated
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>action: [SelfieMode.Action](#action)</td>
|
||||
<td>The deactivated [Action](#action).</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Fires when a primary action or sub-action is deactivated. The connected function receives the deactivated [Action](#action). This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.actionDeactivated:Connect(function(action)
|
||||
print(action.name, "deactivated")
|
||||
end)
|
||||
```
|
||||
|
||||
#### filterChanged
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>newFilter: `Library.string`</td>
|
||||
<td>The new filter.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>oldFilter: `Library.string`</td>
|
||||
<td>The previous filter.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Fires when a [filter](#filter) is applied or removed. The connected function receives the new filter name and the old filter name. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.filterChanged:Connect(function(newFilter, oldFilter)
|
||||
print("Filter changed from", oldFilter, "to", newFilter)
|
||||
end)
|
||||
```
|
||||
|
||||
#### poseChanged
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>newPose: `Library.string`</td>
|
||||
<td>The new pose.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>oldPose: `Library.string`</td>
|
||||
<td>The previous pose.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Fires when a [pose](#pose) is applied or removed. The connected function receives the new pose name and the old pose name. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SelfieMode = require(ReplicatedStorage.SelfieMode)
|
||||
|
||||
SelfieMode.poseChanged:Connect(function(newPose, oldPose)
|
||||
print("Pose changed from", oldPose, "to", newPose)
|
||||
end)
|
||||
```
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
---
|
||||
title: Social Interactions
|
||||
description: The Social Interactions module lets avatars better express themselves and their natural movements.
|
||||
---
|
||||
|
||||
Your avatar is your identity in any space you enter. The **SocialInteractions** [developer module](../../resources/modules/index.md) lets each user better express themselves and their natural movements, adding a touch of realism to the experience.
|
||||
|
||||
This module includes the following features:
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>**Body Orientation**</td>
|
||||
<td>Makes the head of everyone's avatar face where their corresponding user's camera is pointing, through a mix of neck and waist rotation. This provides a subtle cue as to who or what someone else is interacting with.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>**Chat Animations**</td>
|
||||
<td>Adds some liveliness to the in-experience chat by making avatars occasionally play animations, depending on the content of the messages they send. The list of "trigger words" that activate each animation is configurable.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<video src="../../assets/developer-modules/social-interactions/Showcase.mp4" controls width="100%"></video>
|
||||
|
||||
<Alert severity="warning">
|
||||
The body orientation feature uses `Datatype.CFrame` adjustment of the **Neck** and **Waist** joints on the character, meaning that custom rigs must include `Class.Motor6D` objects of the same name for the module to work properly.
|
||||
</Alert>
|
||||
|
||||
## Module Usage
|
||||
|
||||
### Installation
|
||||
|
||||
To use the **SocialInteractions** module in an experience:
|
||||
|
||||
1. From Studio's **Window** menu or **Home** tab toolbar, open the [Toolbox](../../projects/assets/toolbox.md) and select the **Creator Store** tab.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" />
|
||||
|
||||
1. Make sure the **Models** sorting is selected, then click the **See All** button for **Categories**.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Categories-See-All.png" width="360" />
|
||||
|
||||
1. Locate and click the **Packages** tile.
|
||||
|
||||
1. Locate the **Social Interactions** module and click it, or drag-and-drop it into the 3D view.
|
||||
|
||||
<img src="../../assets/developer-modules/social-interactions/Toolbox-Icon.png" width="143" />
|
||||
|
||||
1. In the [Explorer](../../studio/explorer.md) window, move the entire **SocialInteractions** model into `Class.ReplicatedStorage`. Upon running the experience the module will begin running.
|
||||
|
||||
### Configuration
|
||||
|
||||
Simply inserting the **SocialInteractions** module will enable both the **body orientation** and **chat animations** features inside your place. To adjust the default behavior:
|
||||
|
||||
1. In **StarterPlayerScripts**, create a new `Class.LocalScript` and rename it to **ConfigureSocialInteractions**.
|
||||
|
||||
<img src="../../assets/developer-modules/social-interactions/LocalScript-ConfigureSocialInteractions.png" width="320" />
|
||||
|
||||
1. Paste the following code into the new script, using the [configure](#configure) function to customize the module's behavior.
|
||||
|
||||
```lua title="LocalScript" highlight="6-9"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SocialInteractions = require(ReplicatedStorage.SocialInteractions)
|
||||
|
||||
-- Make waist rotation more pronounced and disable the chat animations feature
|
||||
SocialInteractions.configure({
|
||||
waistOrientationWeight = 0.75,
|
||||
useChatAnimations = false,
|
||||
})
|
||||
```
|
||||
|
||||
### Chat Animation Trigger Words
|
||||
|
||||
The list of "trigger words" that activate each chat animation is configurable and Luau string patterns are utilized to increase recognizable words. For example, one combination used by the **Wave** animation is `he+y+o*`, meaning that `hey`, `heyyy`, `heyo`, `heyyyyo`, `heeeeyyyyo`, and other variations qualify to trigger the animation.
|
||||
|
||||
Also note that trigger words are **case-insensitive**, so typing `hey` is the same as `HEY`, `Hey`, and other variations.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Animation</th>
|
||||
<th>Animation ID</th>
|
||||
<th>Word Patterns</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Wave</td>
|
||||
<td>`3344650532`</td>
|
||||
<td>
|
||||
`hell+o+`
|
||||
`h+i+o*`
|
||||
`wa+[sz]+u+p+`
|
||||
`y+o+`
|
||||
`greetings*`
|
||||
`salutations*`
|
||||
`goo+d+%smorning+`
|
||||
`he+y+o*`
|
||||
`howdy+`
|
||||
`what's*%s*up+`
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Applaud</td>
|
||||
<td>`5911729486`</td>
|
||||
<td>
|
||||
`ya+y+`
|
||||
`h[ou]+r+a+y+`
|
||||
`woo+t*`
|
||||
`woo+h+oo+`
|
||||
`bravo+`
|
||||
`congratulations+`
|
||||
`congrats+`
|
||||
`gg`
|
||||
`pog+`
|
||||
`poggers+`
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Agree</td>
|
||||
<td>`4841397952`</td>
|
||||
<td>
|
||||
`ye+s*`
|
||||
`ye+a+h*`
|
||||
`y[eu]+p+`
|
||||
`o+k+`
|
||||
`o+k+a+y+`
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Disagree</td>
|
||||
<td>`4841401869`</td>
|
||||
<td>
|
||||
`no+`
|
||||
`no+pe+`
|
||||
`yi+ke+s+`
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shrug</td>
|
||||
<td>`3334392772`</td>
|
||||
<td>
|
||||
`not+%s+sure+`
|
||||
`idk+`
|
||||
`don't%s+know+`
|
||||
`i%s+don't%s+know+`
|
||||
`who+%s+knows+`
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Laugh</td>
|
||||
<td>`3337966527`</td>
|
||||
<td>
|
||||
`lo+l+`
|
||||
`rof+l+`
|
||||
`ha[ha]*`
|
||||
`he[he]+`
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sleep</td>
|
||||
<td>`4686925579`</td>
|
||||
<td>
|
||||
`zzz+`
|
||||
`yawn+`
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
The list of trigger words that activate each animation is configurable, and additional animations can be added via the [setTriggerWordsForChatAnimation](#settriggerwordsforchatanimation) function. For example, the following `Class.LocalScript` links the [Tilt](https://www.roblox.com/catalog/3360692915/Tilt) animation with the string pattern of `cra+zy` to support trigger words like `crazy` and `craaaaaazy`. It also registers an additional string pattern of `coo+l` for the [Applaud](https://www.roblox.com/catalog/5915779043/Applaud) animation to support words like `cool` and `coooool`.
|
||||
|
||||
```lua title="LocalScript" highlight="6, 9"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SocialInteractions = require(ReplicatedStorage.SocialInteractions)
|
||||
|
||||
-- Register string pattern for the "Tilt" animation
|
||||
SocialInteractions.setTriggerWordsForChatAnimation("rbxassetid://3334538554", {"cra+zy"})
|
||||
|
||||
-- Register additional string pattern for the "Applaud" animation
|
||||
SocialInteractions.setTriggerWordsForChatAnimation("rbxassetid://5911729486", {"coo+l"})
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Functions
|
||||
|
||||
#### configure
|
||||
|
||||
<figcaption>
|
||||
configure(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default configuration options through the following keys/values in the `config` table. This function can only be called from a `Class.LocalScript`.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`useBodyOrientation`</td>
|
||||
<td>Toggles the **body orientation** feature.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`waistOrientationWeight`</td>
|
||||
<td>Body orientation uses a mix of waist and neck rotation; this parameter determines which of the two is prevalent. A value of 1 places complete emphasis on the waist while 0 places complete emphasis on the neck.</td>
|
||||
<td>0.5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`useChatAnimations`</td>
|
||||
<td>Toggles the **chat animations** feature.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`useDefaultTriggerWordsForChatEmotes`</td>
|
||||
<td>Chat animations comes with a default list of [trigger words](#chat-animation-trigger-words). Set this parameter to `false` if you'd like to turn them off and provide your own.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="6-9"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SocialInteractions = require(ReplicatedStorage.SocialInteractions)
|
||||
|
||||
-- Make waist rotation more pronounced and disable the chat animations feature
|
||||
SocialInteractions.configure({
|
||||
waistOrientationWeight = 0.75,
|
||||
useChatAnimations = false,
|
||||
})
|
||||
```
|
||||
|
||||
#### setTriggerWordsForChatAnimation
|
||||
|
||||
<figcaption>
|
||||
setTriggerWordsForChatAnimation(animationId: `Library.string`, triggerWords: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Registers a new animation in the chat animation feature. Typing any word that matches a string pattern included in the `triggerWords` table will activate the animation whose ID is passed as the first parameter.
|
||||
|
||||
Note that trigger words are **case-insensitive** to players, so a pattern of `woah` will accept chat phrases of `woah`, `WOAH`, `Woah`, and other variations.
|
||||
|
||||
```lua title="LocalScript" highlight="6-9"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SocialInteractions = require(ReplicatedStorage.SocialInteractions)
|
||||
|
||||
-- Register new string pattern for a custom animation
|
||||
SocialInteractions.setTriggerWordsForChatAnimation(
|
||||
"rbxassetid://3334538554",
|
||||
{"cra+zy", "woah+"}
|
||||
)
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
#### onChatAnimationPlayed
|
||||
|
||||
Fires when a chat animation plays. The connected function receives the animation ID and the word that triggered the animation as its arguments. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>animationId: `Library.string` </td>
|
||||
<td>Animation ID that played.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>triggerWord: `Library.string`</td>
|
||||
<td>Chat word that triggered the animation.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="5-7"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SocialInteractions = require(ReplicatedStorage.SocialInteractions)
|
||||
|
||||
SocialInteractions.onChatAnimationPlayed:Connect(function(animationId, triggerWord)
|
||||
print(animationId, triggerWord)
|
||||
end)
|
||||
```
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
---
|
||||
title: Spawn With Friends
|
||||
description: The Spawn With Friends module automatically moves spawning players near one of their friends.
|
||||
---
|
||||
|
||||
It can be challenging to locate friends in-experience. The **SpawnWithFriends** [developer module](../../resources/modules/index.md) automatically moves spawning players near one of their friends present in the experience. This module can also be configured to teleport a player on command instead of automatically.
|
||||
|
||||
<video src="../../assets/developer-modules/spawn-with-friends/Showcase.mp4" controls width="100%"></video>
|
||||
|
||||
<Alert severity="warning">
|
||||
Before spawning occurs, in order to avoid spawning a character inside the map's geometry, the system confirms that there is enough space. Thus, this module might work better in experiences with large, open spaces.
|
||||
</Alert>
|
||||
|
||||
## Module Usage
|
||||
|
||||
### Installation
|
||||
|
||||
To use the **SpawnWithFriends** module in an experience:
|
||||
|
||||
1. From Studio's **Window** menu or **Home** tab toolbar, open the [Toolbox](../../projects/assets/toolbox.md) and select the **Creator Store** tab.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" />
|
||||
|
||||
1. Make sure the **Models** sorting is selected, then click the **See All** button for **Categories**.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Categories-See-All.png" width="360" />
|
||||
|
||||
1. Locate and click the **Packages** tile.
|
||||
|
||||
1. Locate the **Spawn With Friends** module and click it, or drag-and-drop it into the 3D view.
|
||||
|
||||
<img src="../../assets/developer-modules/spawn-with-friends/Toolbox-Icon.png" width="143" />
|
||||
|
||||
1. In the [Explorer](../../studio/explorer.md) window, move the entire **SpawnWithFriends** model into `Class.ReplicatedStorage`. Upon running the experience the module will begin running.
|
||||
|
||||
### Restricted Spawn Areas
|
||||
|
||||
This module may result in players spawning in restricted areas like VIP rooms, access-only spaces, etc. To prevent players from teleporting to these areas:
|
||||
|
||||
1. Fill the restricted area with invisible `Class.BasePart.Anchored|Anchored` blocks. Make sure `Class.BasePart.CanCollide|CanCollide`, `Class.BasePart.CanTouch|CanTouch`, and `Class.BasePart.CanQuery|CanQuery` are **disabled** for all blocks.
|
||||
|
||||
<figure>
|
||||
<img src="../../assets/developer-modules/spawn-with-friends/Restricted-Block.jpg" width="800" />
|
||||
<figcaption>Block filling the entire prison room to prevent players from spawning inside</figcaption>
|
||||
</figure>
|
||||
|
||||
1. Using the [Tags](../../studio/properties.md#instance-tags) section of each block's properties, apply the tag `RestrictedSpawnArea` so that `Class.CollectionService` detects them.
|
||||
|
||||
1. Paste the following code into a `Class.Script` within **ServerScriptService**.
|
||||
|
||||
```lua title="Script"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local CollectionService = game:GetService("CollectionService")
|
||||
|
||||
local SpawnWithFriends = require(ReplicatedStorage.SpawnWithFriends)
|
||||
|
||||
local function validator(playerToTeleport, destinationPlayer, teleportationPoint)
|
||||
-- Iterate through all tagged parts
|
||||
for _, area in CollectionService:GetTagged("RestrictedSpawnArea") do
|
||||
local relativePosition = area.CFrame:PointToObjectSpace(teleportationPoint.Position)
|
||||
local size = area.Size
|
||||
local inXBounds = relativePosition.X < size.X / 2 and relativePosition.X > -size.X / 2
|
||||
local inZBounds = relativePosition.Z < size.Z / 2 and relativePosition.Z > -size.Z / 2
|
||||
if inXBounds and inZBounds then
|
||||
return false -- Spawn destination is within restricted area; abort teleportation
|
||||
end
|
||||
end
|
||||
return true -- Spawn destination doesn't overlap any restricted area; proceed with teleportation
|
||||
end
|
||||
|
||||
SpawnWithFriends.setTeleportationValidator(validator)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Functions
|
||||
|
||||
#### configure
|
||||
|
||||
<figcaption>
|
||||
configure(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default configuration options through the following keys/values in the `config` table. This function can only be called from a `Class.Script`.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`teleportToFriendOnRespawn`</td>
|
||||
<td>If set to `false`, teleportation to a friend will only happen manually via [teleportToRandomFriend](#teleporttorandomfriend).</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`teleportDistance`</td>
|
||||
<td>How far away players should spawn from each other, measured in studs.</td>
|
||||
<td>5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`maxCharacterVelocity`</td>
|
||||
<td>Characters moving faster than this value won't be picked as teleportation candidates, for instance those in moving vehicles.</td>
|
||||
<td>48</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`bypassFriendshipCheck`</td>
|
||||
<td>If set to true, **all** players will be candidates for teleportation, not just friends.</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`showLogs`</td>
|
||||
<td>Whether or not to display log messages in the output.</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="Script" highlight="5-11"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SpawnWithFriends = require(ReplicatedStorage.SpawnWithFriends)
|
||||
|
||||
SpawnWithFriends.configure({
|
||||
teleportToFriendOnRespawn = true,
|
||||
teleportDistance = 5,
|
||||
maxCharacterVelocity = 48,
|
||||
bypassFriendshipCheck = false,
|
||||
showLogs = false
|
||||
})
|
||||
```
|
||||
|
||||
#### teleportToRandomFriend
|
||||
|
||||
<figcaption>
|
||||
teleportToRandomFriend(playerToTeleport: `Class.Player`): `boolean`
|
||||
</figcaption>
|
||||
|
||||
Manually triggers teleportation of a player to one of their friends in the experience. Returns a boolean indicating whether or not teleportation succeeded; failure to teleport can be caused by the absence of friends in the server or the inability to find an unobstructed teleportation point. This function can only be called from a `Class.Script`.
|
||||
|
||||
#### setTeleportationValidator
|
||||
|
||||
<figcaption>
|
||||
setTeleportationValidator(validator: `function`)
|
||||
</figcaption>
|
||||
|
||||
Allows you to perform custom pre-teleportation checks by hooking up a validator callback function. The callback receives three parameters:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`playerToTeleport`</td>
|
||||
<td>Reference to the `Class.Player` that is being teleported.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`destinationPlayer`</td>
|
||||
<td>Reference to the target `Class.Player` that `playerToTeleport` is being teleported to.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`teleportationPoint`</td>
|
||||
<td>`Datatype.CFrame` where `playerToTeleport` is teleporting to.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
This function and its callback can only be used in a `Class.Script` and the callback returns a boolean indicating whether teleportation should proceed. For example, the `return` logic in the following validator function ensures that the spawning player and destination player are on the same team.
|
||||
|
||||
```lua title="Script" highlight="6-8, 10"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SpawnWithFriends = require(ReplicatedStorage.SpawnWithFriends)
|
||||
|
||||
-- Teleports players only if they are on the same team
|
||||
local function validator(playerToTeleport, destinationPlayer, teleportationPoint)
|
||||
return playerToTeleport.Team == destinationPlayer.Team
|
||||
end
|
||||
|
||||
SpawnWithFriends.setTeleportationValidator(validator)
|
||||
```
|
||||
586
.cursor/rules/roblox/en-us/resources/modules/surface-art.md
Normal file
586
.cursor/rules/roblox/en-us/resources/modules/surface-art.md
Normal file
|
|
@ -0,0 +1,586 @@
|
|||
---
|
||||
title: Surface Art
|
||||
description: The Surface Art module lets players literally leave their mark in an experience.
|
||||
---
|
||||
|
||||
Players often enjoy feeling like they're a part of constructing the space they're in. The **SurfaceArt** [developer module](../../resources/modules/index.md) lets players literally leave their mark in an experience.
|
||||
|
||||
<video src="../../assets/developer-modules/surface-art/Showcase.mp4" controls width="100%"></video>
|
||||
|
||||
<Alert severity="warning">
|
||||
By default, a player can place 2 pieces of art across all of the tagged surfaces in the workspace. All of a player's art will be removed when they leave the experience.
|
||||
</Alert>
|
||||
|
||||
## Module Usage
|
||||
|
||||
### Installation
|
||||
|
||||
To use the **SurfaceArt** module in an experience:
|
||||
|
||||
1. From Studio's **Window** menu or **Home** tab toolbar, open the [Toolbox](../../projects/assets/toolbox.md) and select the **Creator Store** tab.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" />
|
||||
|
||||
1. Make sure the **Models** sorting is selected, then click the **See All** button for **Categories**.
|
||||
|
||||
<img src="../../assets/studio/toolbox/Creator-Store-Categories-See-All.png" width="360" />
|
||||
|
||||
1. Locate and click the **Packages** tile.
|
||||
|
||||
1. Locate the **Surface Art** module and click it, or drag-and-drop it into the 3D view.
|
||||
|
||||
<img src="../../assets/developer-modules/surface-art/Toolbox-Icon.png" width="143" />
|
||||
|
||||
1. In the [Explorer](../../studio/explorer.md) window, move the entire **SurfaceArt** model into `Class.ReplicatedStorage`. Upon running the experience the module will begin running.
|
||||
|
||||
### Positioning the Canvas
|
||||
|
||||
The module comes with one **SurfaceCanvas** model that you can position in the 3D world. This model is what players will interact with to place art on its surface.
|
||||
|
||||
1. Locate the **SurfaceCanvas** mesh inside the **Workspace** folder of the module's main folder.
|
||||
|
||||
<img src="../../assets/developer-modules/surface-art/Bundled-Mesh-Explorer.png" width="320" />
|
||||
|
||||
1. Move it into the top-level **Workspace** hierarchy and position it where desired.
|
||||
|
||||
<img src="../../assets/developer-modules/surface-art/Position-Canvas.jpg" width="800" />
|
||||
|
||||
1. Upon publishing/running a test session, players will be able to interact with the object via a `Class.ProximityPrompt` and place art on the defined surface.
|
||||
|
||||
<img src="../../assets/developer-modules/surface-art/SurfaceArt-UI.jpg" width="800" />
|
||||
|
||||
<Alert severity="info">
|
||||
It is not required that you use the packaged mesh for placing art. The module uses `Class.CollectionService` to locate parts tagged as `SurfaceCanvas` and make them operate as canvases. Any tagged canvas must be a `Class.BasePart` and it should have an [attribute](../../studio/properties.md#instance-attributes) defining the surface face as outlined in [Changing the Canvas Face](#changing-the-canvas-face).
|
||||
</Alert>
|
||||
|
||||
### Changing the Canvas Face
|
||||
|
||||
Under the hood, the module uses a `Class.SurfaceGui` to display art items. To configure which surface the art appears on:
|
||||
|
||||
1. Select the **SurfaceCanvas** mesh.
|
||||
1. At the bottom of the **Properties** window, locate the **SurfaceCanvasFace** attribute with a default value of **Right**.
|
||||
|
||||
<img src="../../assets/developer-modules/surface-art/Canvas-Attribute.png" width="320" />
|
||||
|
||||
1. Click the attribute and enter one of six values that describe a `Enum.NormalId`.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute Value</th>
|
||||
<th>Corresponding Normal ID</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>**Front**</td>
|
||||
<td>`Enum.NormalId.Front`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>**Back**</td>
|
||||
<td>`Enum.NormalId.Back`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>**Right**</td>
|
||||
<td>`Enum.NormalId.Right`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>**Left**</td>
|
||||
<td>`Enum.NormalId.Left`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>**Top**</td>
|
||||
<td>`Enum.NormalId.Top`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>**Bottom**</td>
|
||||
<td>`Enum.NormalId.Bottom`</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Using Custom Art Assets
|
||||
|
||||
<Alert severity="info">
|
||||
Currently, the surface art module only supports using the same set of assets for all tagged canvases.
|
||||
</Alert>
|
||||
|
||||
To better fit the theme of your experience, you may use your own set of custom assets instead of the defaults. This can be done via the [configure](#configure) function, called from a `Class.Script` in **ServerScriptService**.
|
||||
|
||||
```lua title="Script" highlight="5-14, 16-18"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
local customAssets = {
|
||||
CustomAsset1 = {
|
||||
name = "Custom Asset 1",
|
||||
assetId = "rbxassetid://7322508294",
|
||||
},
|
||||
CustomAsset2 = {
|
||||
name = "Custom Asset 2",
|
||||
assetId = "rbxassetid://7322547665",
|
||||
},
|
||||
}
|
||||
|
||||
SurfaceArt.configure({
|
||||
assets = customAssets,
|
||||
})
|
||||
```
|
||||
|
||||
### Clearing All Canvases
|
||||
|
||||
To remove all existing art from all canvases in the world, call the [removeAllArt](#removeallart) function from a `Class.Script`.
|
||||
|
||||
```lua title="Script" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
SurfaceArt.removeAllArt()
|
||||
```
|
||||
|
||||
### Showing Custom Effects
|
||||
|
||||
There may be cases where you'd like to include additional visual effects when an artwork is placed. This module exposes an event called [artChanged](#artchanged) on the client that you can connect to and add your own logic.
|
||||
|
||||
```lua title="LocalScript" highlight="22"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
local function createParticleEmitter(canvas, position)
|
||||
local attachment = Instance.new("Attachment")
|
||||
attachment.Position = canvas.CFrame:PointToObjectSpace(position)
|
||||
attachment.Axis = Vector3.new(0, 0, 1)
|
||||
attachment.SecondaryAxis = Vector3.new(1, 0, 0)
|
||||
attachment.Parent = canvas
|
||||
|
||||
local particleEmitter = Instance.new("ParticleEmitter")
|
||||
particleEmitter.Speed = NumberRange.new(50)
|
||||
particleEmitter.Rate = 50
|
||||
particleEmitter.Color = ColorSequence.new(Color3.fromRGB(128, 254, 7))
|
||||
particleEmitter.SpreadAngle = Vector2.new(35, 35)
|
||||
particleEmitter.Parent = attachment
|
||||
|
||||
return attachment
|
||||
end
|
||||
|
||||
SurfaceArt.artChanged:Connect(function(canvas, spot, spotPosition, artId, ownerId)
|
||||
if artId then
|
||||
-- Show some sparkles for 3 seconds
|
||||
task.spawn(function()
|
||||
local emitterAttachment = createParticleEmitter(canvas, spotPosition)
|
||||
task.wait(3)
|
||||
emitterAttachment:Destroy()
|
||||
end)
|
||||
end
|
||||
end)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Types
|
||||
|
||||
#### SurfaceArtAsset
|
||||
|
||||
Images to be used as art for the canvas are represented by a table with two values.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`name`</td>
|
||||
<td>Metadata display name.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`assetId`</td>
|
||||
<td>Asset ID of the image to include.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Functions
|
||||
|
||||
#### configure
|
||||
|
||||
<figcaption>
|
||||
configure(config: `Library.table`)
|
||||
</figcaption>
|
||||
|
||||
Overrides default configuration options through the following keys/values in the `config` table. This function can only be called from a `Class.Script`.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="General">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`enabled`</td>
|
||||
<td>Toggles the module's functionality on or off.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`assets`</td>
|
||||
<td>List of [SurfaceArtAsset](#surfaceartasset) types.</td>
|
||||
<td>(see code below)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`quotaPerPlayer`</td>
|
||||
<td>Maximum number of art pieces that can be placed by each player.</td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Appearance">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`rowsPerCanvas`</td>
|
||||
<td>Number of rows in the canvas grid.</td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`colsPerCanvas`</td>
|
||||
<td>Number of columns in the canvas grid.</td>
|
||||
<td>5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`itemsPerPage`</td>
|
||||
<td>Number of items to skip when paging left and right.</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`canvasPaddingLeft`</td>
|
||||
<td>Left padding for the surface canvas (`Datatype.UDim`).</td>
|
||||
<td>(0, 8)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`canvasPaddingRight`</td>
|
||||
<td>Right padding for the surface canvas (`Datatype.UDim`).</td>
|
||||
<td>(0, 8)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`canvasPaddingTop`</td>
|
||||
<td>Top padding for the surface canvas (`Datatype.UDim`).</td>
|
||||
<td>(0, 8)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`canvasPaddingBottom`</td>
|
||||
<td>Bottom padding for the surface canvas (`Datatype.UDim`).</td>
|
||||
<td>(0, 8)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`promptImage`</td>
|
||||
<td>Icon shown in the proximity prompt to enter art selection view.</td>
|
||||
<td>"rbxassetid://8076723774"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`leftArrowPageImage`</td>
|
||||
<td>Image for the left arrow to flip to the previous page.</td>
|
||||
<td>"rbxassetid://6998633654"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`leftArrowItemImage`</td>
|
||||
<td>Image for the left arrow to select the previous art item.</td>
|
||||
<td>"rbxassetid://8072765021"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`rightArrowPageImage`</td>
|
||||
<td>Image for the right arrow to flip to the next page.</td>
|
||||
<td>"rbxassetid://6998635824"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`rightArrowItemImage`</td>
|
||||
<td>Image for the right arrow to select the next art item.</td>
|
||||
<td>"rbxassetid://8072764852"</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Interaction">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Description</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`promptKeyCode`</td>
|
||||
<td>Keyboard shortcut used to activate the prompt to enter art selection (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|E`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`promptRequiresLineOfSight`</td>
|
||||
<td>Boolean value that determines if the proximity prompt has to be in line of sight between user and canvas.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`promptMaxActivationDistance`</td>
|
||||
<td>Maximum distance a player's character can be from the canvas for the prompt to appear.</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`promptExclusivity`</td>
|
||||
<td>`Enum.ProximityPromptExclusivity` specifying which prompts can be shown at the same time.</td>
|
||||
<td>`Enum.ProximityPromptExclusivity|OnePerButton`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`usePageHotkeys`</td>
|
||||
<td>Whether page hotkeys are used. If true, `nextPageKey` and `prevPageKey` are used to cycle between pages.</td>
|
||||
<td>true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`nextPageKey`</td>
|
||||
<td>Key used to cycle to the next page of artwork (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|E`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`nextItemKey`</td>
|
||||
<td>Key used to cycle to the next item of artwork (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|Right`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`prevPageKey`</td>
|
||||
<td>Key used to cycle to the previous page of artwork (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|Q`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`prevItemKey`</td>
|
||||
<td>Key used to cycle to the previous item of artwork (`Enum.KeyCode`).</td>
|
||||
<td>`Enum.KeyCode|Left`</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
```lua title="Script" highlight="5-9"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
SurfaceArt.configure({
|
||||
quotaPerPlayer = 4,
|
||||
promptKeyCode = Enum.KeyCode.T,
|
||||
promptMaxActivationDistance = 8,
|
||||
})
|
||||
```
|
||||
|
||||
#### getCanvases
|
||||
|
||||
<figcaption>
|
||||
getCanvases(): `Library.table`
|
||||
</figcaption>
|
||||
|
||||
Returns all of the canvases tagged with the `SurfaceCanvas` tag.
|
||||
|
||||
```lua title="Script" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
local canvases = SurfaceArt.getCanvases()
|
||||
```
|
||||
|
||||
#### placeArt
|
||||
|
||||
<figcaption>
|
||||
placeArt(player: `Class.Player`, canvas: `Class.BasePart`)
|
||||
</figcaption>
|
||||
|
||||
Places an art piece programmatically on behalf of a player. Note that the `canvas` object must be tagged with the `SurfaceCanvas` tag when the server is initialized. It is recommended to use this only with a canvas returned from [getCanvases](#getcanvases).
|
||||
|
||||
```lua title="Script" highlight="9-10"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
local remoteEvent = ReplicatedStorage:WaitForChild("SurfaceArtRemoteEvent")
|
||||
|
||||
remoteEvent.OnServerEvent:Connect(function(player)
|
||||
-- Place the Bloxy Award from default art assets into the first canvas
|
||||
local canvases = SurfaceArt.getCanvases()
|
||||
SurfaceArt.placeArt(player, canvases[1], "BloxyAward")
|
||||
end)
|
||||
```
|
||||
|
||||
#### removeAllArt
|
||||
|
||||
<figcaption>
|
||||
removeAllArt()
|
||||
</figcaption>
|
||||
|
||||
Removes all artwork from all surfaces.
|
||||
|
||||
```lua title="Script" highlight="5"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
SurfaceArt.removeAllArt()
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
#### artChanged
|
||||
|
||||
Fires when an artwork is changed at a particular location on a canvas. When an artwork is removed, `artId` will be `nil`. Note that a `Datatype.Vector3` value is passed as the third parameter to the event handler so that you can position a [custom effect](#showing-custom-effects) at the exact position where the artwork is placed. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>canvas: `Class.BasePart`</td>
|
||||
<td>Canvas upon which the artwork was changed.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>spot: `Class.Frame`</td>
|
||||
<td>Internal `Class.Frame` that contains the artwork `Class.ImageLabel`.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>spotPosition: `Datatype.Vector3`</td>
|
||||
<td>Exact position where the artwork was placed.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>artId: `Library.string`</td>
|
||||
<td>Asset ID of the new artwork.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ownerUserId: `number`</td>
|
||||
<td>`Class.Player.UserId|UserId` of the player who placed the art.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="5-9"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
SurfaceArt.artChanged:Connect(function(canvas, spot, spotPosition, artId, ownerId)
|
||||
print("Art placed at:", spotPosition)
|
||||
print("Art asset ID:", artId)
|
||||
print("Art placed by:", ownerId)
|
||||
end)
|
||||
```
|
||||
|
||||
#### promptShown
|
||||
|
||||
Fires when a canvas interaction prompt is shown to a player. The connected function receives the canvas upon which the prompt is showing. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>canvas: `Class.BasePart`</td>
|
||||
<td>Canvas upon which the prompt is showing.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="6-8"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
SurfaceArt.promptShown:Connect(function(canvas)
|
||||
print(Players.LocalPlayer, canvas)
|
||||
end)
|
||||
```
|
||||
|
||||
#### promptHidden
|
||||
|
||||
Fires when a canvas interaction prompt is hidden. The connected function receives the canvas upon which the prompt was showing. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
<table size="small">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan='2'>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>canvas: `Class.BasePart`</td>
|
||||
<td>Canvas upon which the prompt was showing.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```lua title="LocalScript" highlight="6-8"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
SurfaceArt.promptClosed:Connect(function(canvas)
|
||||
print(Players.LocalPlayer, canvas)
|
||||
end)
|
||||
```
|
||||
|
||||
#### selectorShown
|
||||
|
||||
Fires when the surface art selector UI is shown to a player. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="6-8"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
SurfaceArt.selectorShown:Connect(function()
|
||||
print(Players.LocalPlayer, "opened surface art selector")
|
||||
end)
|
||||
```
|
||||
|
||||
#### selectorHidden
|
||||
|
||||
Fires when the surface art selector UI is hidden for a player. This event can only be connected in a `Class.LocalScript`.
|
||||
|
||||
```lua title="LocalScript" highlight="6-8"
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local SurfaceArt = require(ReplicatedStorage.SurfaceArt)
|
||||
|
||||
SurfaceArt.selectorHidden:Connect(function()
|
||||
print(Players.LocalPlayer, "closed surface art selector")
|
||||
end)
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue