Compare commits
4 commits
3530d84142
...
f5584a9b0c
Author | SHA1 | Date | |
---|---|---|---|
f5584a9b0c | |||
968e054158 | |||
808ed82e3f | |||
cfccbe4883 |
16 changed files with 128 additions and 160 deletions
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "roblox-ts-game",
|
||||
"name": "goopler",
|
||||
"globIgnorePaths": [
|
||||
"**/package.json",
|
||||
"**/tsconfig.json"
|
||||
|
|
|
@ -36,9 +36,11 @@
|
|||
"@rbxts/log": "^0.6.3",
|
||||
"@rbxts/matter": "^0.6.2-ts.6",
|
||||
"@rbxts/plasma": "^0.4.1-ts.1",
|
||||
"@rbxts/reflex": "^4.2.0",
|
||||
"@rbxts/rewire": "^0.3.0",
|
||||
"@rbxts/roact": "^1.4.4-ts.0",
|
||||
"@rbxts/roact-hooks": "^0.4.1-ts.3",
|
||||
"@rbxts/roact-hooked": "^2.6.0",
|
||||
"@rbxts/roact-reflex": "^2.1.0",
|
||||
"@rbxts/services": "^1.5.1",
|
||||
"@rbxts/testez": "^0.4.2-ts.0",
|
||||
"@rbxts/variant": "^1.0.2",
|
||||
|
|
|
@ -7,14 +7,14 @@ An in-dev game that I plan to make a shooter game out of.
|
|||
|
||||
— reidlab
|
||||
|
||||
# Ui theming is based on Catppucin Mocha. You can find the colors [here](https://github.com/catppuccin/catppuccin) and the style guide [here](https://github.com/catppuccin/catppuccin/blob/main/docs/style-guide.md)
|
||||
Ui theming is based on Catppucin Mocha. You can find the colors [here](https://github.com/catppuccin/catppuccin) and the style guide [here](https://github.com/catppuccin/catppuccin/blob/main/docs/style-guide.md)
|
||||
|
||||
# Hacks
|
||||
* I get a strange error about private identifiers in [`./src/ReplicatedStorage/ecs/state.ts`](./src/ReplicatedStorage/ecs/state.ts)
|
||||
* I decided to omit the "TS" folder from [`./default.project.json:40`](./default.project.json) due to the script override not working in Health.server.ts in StarterCharacterScripts.
|
||||
|
||||
# Todo
|
||||
* __Work on next:__ Add hotbar animations, might need reflex || rodux
|
||||
* __Work on next:__ Add hotbar animations and state, might need reflex
|
||||
* Add tests
|
||||
* Add guns
|
||||
* Add the bound tags in [`./src/ReplicatedStorage/ecs/boundTags.ts`](./src/ReplicatedStorage/ecs/boundTags.ts)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
import { UseProducerHook, useProducer } from "@rbxts/roact-reflex"
|
||||
import { rootProducer } from "../producer"
|
||||
|
||||
export const useRootProducer: UseProducerHook<rootProducer> = useProducer
|
9
src/ReplicatedStorage/reflex/uiStore/producer/index.ts
Normal file
9
src/ReplicatedStorage/reflex/uiStore/producer/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { InferDispatchers, InferState, combineProducers, loggerMiddleware } from "@rbxts/reflex"
|
||||
|
||||
export type rootProducer = typeof producer
|
||||
export type rootState = InferState<rootProducer>
|
||||
export type rootDispatchers = InferDispatchers<rootProducer>
|
||||
|
||||
export const producer = combineProducers({
|
||||
|
||||
}).applyMiddleware(loggerMiddleware)
|
32
src/ReplicatedStorage/ui/components/padding.tsx
Normal file
32
src/ReplicatedStorage/ui/components/padding.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import Hooks from "@rbxts/roact-hooked"
|
||||
import Roact from "@rbxts/roact"
|
||||
|
||||
interface paddingProps extends Roact.JsxInstanceProperties<UIPadding> {
|
||||
padding?: UDim | Roact.Binding<UDim>
|
||||
paddingX?: UDim | Roact.Binding<UDim>
|
||||
paddingY?: UDim | Roact.Binding<UDim>
|
||||
|
||||
Event?: Roact.JsxInstanceEvents<UIPadding>
|
||||
Change?: Roact.JsxInstanceChangeEvents<UIPadding>
|
||||
}
|
||||
|
||||
function padding(props: paddingProps): Roact.Element {
|
||||
const { padding, paddingX, paddingY } = props
|
||||
|
||||
const spreadableProps = { ...props } as Partial<paddingProps>
|
||||
delete spreadableProps.padding
|
||||
delete spreadableProps.paddingX
|
||||
delete spreadableProps.paddingY
|
||||
|
||||
return (
|
||||
<uipadding
|
||||
{...spreadableProps}
|
||||
PaddingBottom={paddingY ?? padding}
|
||||
PaddingTop={paddingY ?? padding}
|
||||
PaddingLeft={paddingX || padding}
|
||||
PaddingRight={paddingX || padding}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default padding
|
|
@ -1,32 +0,0 @@
|
|||
import Hooks from "@rbxts/roact-hooks"
|
||||
import Roact from "@rbxts/roact"
|
||||
|
||||
interface PaddingProps extends Roact.JsxInstanceProperties<UIPadding> {
|
||||
Padding?: UDim | Roact.Binding<UDim>
|
||||
PaddingX?: UDim | Roact.Binding<UDim>
|
||||
PaddingY?: UDim | Roact.Binding<UDim>
|
||||
|
||||
Event?: Roact.JsxInstanceEvents<UIPadding>
|
||||
Change?: Roact.JsxInstanceChangeEvents<UIPadding>
|
||||
}
|
||||
|
||||
const padding: Hooks.FC<PaddingProps> = (props, _hooks) => {
|
||||
const { Padding, PaddingX, PaddingY } = props
|
||||
|
||||
const spreadableProps = { ...props } as Partial<PaddingProps>
|
||||
delete spreadableProps.Padding
|
||||
delete spreadableProps.PaddingX
|
||||
delete spreadableProps.PaddingY
|
||||
|
||||
return (
|
||||
<uipadding
|
||||
{...spreadableProps}
|
||||
PaddingBottom={PaddingY ?? Padding}
|
||||
PaddingTop={PaddingY ?? Padding}
|
||||
PaddingLeft={PaddingX || Padding}
|
||||
PaddingRight={PaddingX || Padding}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default new Hooks(Roact)(padding)
|
|
@ -1,64 +0,0 @@
|
|||
import Hooks from "@rbxts/roact-hooks"
|
||||
import Roact from "@rbxts/roact"
|
||||
import Padding from "./padding"
|
||||
|
||||
function colorBetween(startColor: Color3, endColor: Color3, degree: number): Color3 {
|
||||
return startColor.Lerp(endColor, degree)
|
||||
}
|
||||
|
||||
interface percentageBarProps extends Roact.JsxInstanceProperties<UIPadding> {
|
||||
current: number
|
||||
max: number
|
||||
highColor: Color3
|
||||
lowColor: Color3
|
||||
bgColor: Color3
|
||||
text?: string
|
||||
|
||||
Event?: Roact.JsxInstanceEvents<Frame>
|
||||
Change?: Roact.JsxInstanceChangeEvents<Frame>
|
||||
}
|
||||
|
||||
const percentageBar: Hooks.FC<percentageBarProps> = (props, _hooks) => {
|
||||
const { current, max, highColor, lowColor, bgColor, text } = props
|
||||
|
||||
const spreadableProps = { ...props } as Partial<percentageBarProps>
|
||||
delete spreadableProps.current
|
||||
delete spreadableProps.max
|
||||
delete spreadableProps.highColor
|
||||
delete spreadableProps.lowColor
|
||||
delete spreadableProps.bgColor
|
||||
delete spreadableProps.text
|
||||
|
||||
return (
|
||||
<frame BackgroundColor3={bgColor} BorderSizePixel={0} {...spreadableProps}>
|
||||
<frame BackgroundTransparency={1} Size={new UDim2(current / max, 0, 1, 0)} ZIndex={1} BorderSizePixel={0}>
|
||||
<frame BackgroundColor3={colorBetween(lowColor, highColor, current / max)} Size={new UDim2(1, 0, 1, 0)} BorderSizePixel={0}/>
|
||||
</frame>
|
||||
<frame Size={new UDim2(1, 0, 1, 0)} BackgroundTransparency={1}>
|
||||
<Padding PaddingY={new UDim(.1, 0)} PaddingX={new UDim(0, 8)}/>
|
||||
<textlabel
|
||||
BackgroundTransparency={1}
|
||||
Text={`${math.floor(current)} / ${math.floor(max)}`}
|
||||
ZIndex={2}
|
||||
Size={new UDim2(1, 0, 1, 0)}
|
||||
TextXAlignment={Enum.TextXAlignment.Right}
|
||||
TextColor3={Color3.fromHex("#cdd6f4")}
|
||||
TextScaled
|
||||
/>
|
||||
{(text !== undefined) ? (
|
||||
<textlabel
|
||||
BackgroundTransparency={1}
|
||||
Text={text}
|
||||
ZIndex={2}
|
||||
Size={new UDim2(1, 0, 1, 0)}
|
||||
TextXAlignment={Enum.TextXAlignment.Left}
|
||||
TextColor3={Color3.fromHex("#cdd6f4")}
|
||||
TextScaled
|
||||
/>
|
||||
) : undefined}
|
||||
</frame>
|
||||
</frame>
|
||||
)
|
||||
}
|
||||
|
||||
export default new Hooks(Roact)(percentageBar)
|
4
src/ReplicatedStorage/ui/store/hooks/useUiProducer.ts
Normal file
4
src/ReplicatedStorage/ui/store/hooks/useUiProducer.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { UseProducerHook, useProducer } from "@rbxts/roact-reflex"
|
||||
import { rootProducer } from "../producer"
|
||||
|
||||
export const useUiProducer: UseProducerHook<rootProducer> = useProducer
|
9
src/ReplicatedStorage/ui/store/producer/index.ts
Normal file
9
src/ReplicatedStorage/ui/store/producer/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { InferDispatchers, InferState, combineProducers, loggerMiddleware } from "@rbxts/reflex"
|
||||
|
||||
export type rootProducer = typeof producer
|
||||
export type rootState = InferState<rootProducer>
|
||||
export type rootDispatchers = InferDispatchers<rootProducer>
|
||||
|
||||
export const producer = combineProducers({
|
||||
|
||||
}).applyMiddleware(loggerMiddleware)
|
|
@ -1,15 +1,19 @@
|
|||
import { World } from "@rbxts/matter"
|
||||
import { clientState } from "ReplicatedStorage/ecs/state"
|
||||
import WorldProvider from "./ui/contexts/worldContext"
|
||||
import { WorldContext } from "./ui/contexts/worldContext"
|
||||
import Roact from "@rbxts/roact"
|
||||
import Main from "./ui/main"
|
||||
import { ReflexProvider } from "@rbxts/roact-reflex"
|
||||
import { producer } from "ReplicatedStorage/ui/store/producer"
|
||||
|
||||
const showGUI = (world: World, state: clientState): void => {
|
||||
const playerGui = state.player.WaitForChild("PlayerGui") as PlayerGui
|
||||
const tree = (
|
||||
<WorldProvider clientState={state} world={world}>
|
||||
<WorldContext.Provider value={{ world: world, clientState: state }}>
|
||||
<ReflexProvider producer={producer}>
|
||||
<Main/>
|
||||
</WorldProvider>
|
||||
</ReflexProvider>
|
||||
</WorldContext.Provider>
|
||||
)
|
||||
Roact.mount(tree, playerGui, "gooplerGUI")
|
||||
}
|
||||
|
|
|
@ -1,31 +1,16 @@
|
|||
import { World } from "@rbxts/matter"
|
||||
import Roact, { createContext } from "@rbxts/roact"
|
||||
import Hooks, { CoreHooks } from "@rbxts/roact-hooks"
|
||||
import Roact from "@rbxts/roact"
|
||||
import { useContext } from "@rbxts/roact-hooked"
|
||||
import { clientState } from "ReplicatedStorage/ecs/state"
|
||||
|
||||
interface WorldContextValue {
|
||||
interface worldContextProps {
|
||||
world: World
|
||||
clientState: clientState
|
||||
}
|
||||
|
||||
interface Props {
|
||||
world: World
|
||||
clientState: clientState
|
||||
}
|
||||
export const WorldContext = Roact.createContext<worldContextProps | undefined>(undefined)
|
||||
|
||||
const WorldProviderWithoutHooks: Hooks.FC<Props> = (props) => {
|
||||
const { world, clientState } = props
|
||||
|
||||
return <WorldContext.Provider value={{ world, clientState }}>{props[Roact.Children]}</WorldContext.Provider>
|
||||
}
|
||||
|
||||
const WorldProvider = new Hooks(Roact)(WorldProviderWithoutHooks)
|
||||
|
||||
export default WorldProvider
|
||||
|
||||
const WorldContext = createContext<WorldContextValue | undefined>(undefined)
|
||||
|
||||
export const useWorldContext = ({ useContext }: CoreHooks): WorldContextValue => {
|
||||
export function useWorldContext(): worldContextProps {
|
||||
const context = useContext(WorldContext)
|
||||
if (!context) {
|
||||
error("useContext must be called within a Provider")
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import Roact from "@rbxts/roact"
|
||||
import Hooks from "@rbxts/roact-hooks"
|
||||
import Slot from "./slot"
|
||||
import { useWorldContext } from "../contexts/worldContext"
|
||||
import Padding from "ReplicatedStorage/ui/padding"
|
||||
import Padding from "ReplicatedStorage/ui/components/padding"
|
||||
import { StarterGui } from "@rbxts/services"
|
||||
|
||||
interface hotbarProps extends Roact.JsxInstanceProperties<Frame> {
|
||||
|
@ -10,13 +9,12 @@ interface hotbarProps extends Roact.JsxInstanceProperties<Frame> {
|
|||
Change?: Roact.JsxInstanceChangeEvents<Frame>
|
||||
}
|
||||
|
||||
// no fuck off
|
||||
StarterGui.SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
|
||||
|
||||
const hotbar: Hooks.FC<hotbarProps> = (props, hooks) => {
|
||||
function hotbar(props: hotbarProps): Roact.Element {
|
||||
const spreadableProps = { ...props } as Partial<hotbarProps>
|
||||
|
||||
const { clientState } = useWorldContext(hooks)
|
||||
const { clientState } = useWorldContext()
|
||||
|
||||
const keycodes: Enum.KeyCode[] = [
|
||||
Enum.KeyCode.One,
|
||||
|
@ -30,6 +28,18 @@ const hotbar: Hooks.FC<hotbarProps> = (props, hooks) => {
|
|||
Enum.KeyCode.Nine
|
||||
]
|
||||
|
||||
const items: Roact.Element[] = []
|
||||
clientState.backpack.GetChildren().forEach((tool, i) => {
|
||||
items.push(
|
||||
<Slot
|
||||
Key={`Item${i}`}
|
||||
index={i + 1}
|
||||
keycode={keycodes[i]}
|
||||
tool={tool as Tool}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<frame
|
||||
{...spreadableProps}
|
||||
|
@ -44,19 +54,11 @@ const hotbar: Hooks.FC<hotbarProps> = (props, hooks) => {
|
|||
VerticalAlignment={Enum.VerticalAlignment.Bottom}
|
||||
/>
|
||||
<Padding
|
||||
Padding={new UDim(0, 10)}
|
||||
padding={new UDim(0, 10)}
|
||||
/>
|
||||
{
|
||||
clientState.backpack.GetChildren().map((tool, i) => (
|
||||
<Slot
|
||||
index={i + 1}
|
||||
keycode={keycodes[i]}
|
||||
tool={tool as Tool}
|
||||
/>
|
||||
))
|
||||
}
|
||||
{...items}
|
||||
</frame>
|
||||
)
|
||||
}
|
||||
|
||||
export default new Hooks(Roact)(hotbar)
|
||||
export default hotbar
|
|
@ -1,8 +1,8 @@
|
|||
import Roact from "@rbxts/roact"
|
||||
import Hooks from "@rbxts/roact-hooks"
|
||||
import { useEffect } from "@rbxts/roact-hooked"
|
||||
import { useWorldContext } from "../contexts/worldContext"
|
||||
import { ContextActionService, HttpService } from "@rbxts/services"
|
||||
import Padding from "ReplicatedStorage/ui/padding"
|
||||
import Padding from "ReplicatedStorage/ui/components/padding"
|
||||
|
||||
interface slotProps extends Roact.JsxInstanceProperties<Frame> {
|
||||
index: number
|
||||
|
@ -13,21 +13,22 @@ interface slotProps extends Roact.JsxInstanceProperties<Frame> {
|
|||
Change?: Roact.JsxInstanceChangeEvents<Frame>
|
||||
}
|
||||
|
||||
const slot: Hooks.FC<slotProps> = (props, hooks) => {
|
||||
function slot(props: slotProps): Roact.Element {
|
||||
const { index, keycode, tool } = props
|
||||
const { useEffect } = hooks
|
||||
|
||||
const spreadableProps = { ...props } as Partial<slotProps>
|
||||
delete spreadableProps.index
|
||||
delete spreadableProps.keycode
|
||||
delete spreadableProps.tool
|
||||
|
||||
const { clientState } = useWorldContext(hooks)
|
||||
const { clientState } = useWorldContext()
|
||||
|
||||
const handleActivated = (): void => {
|
||||
tool.Parent !== clientState.character
|
||||
? clientState.character.Humanoid.EquipTool(tool)
|
||||
: clientState.character.Humanoid.UnequipTools()
|
||||
if (tool.Parent !== clientState.character) {
|
||||
clientState.character.Humanoid.EquipTool(tool)
|
||||
} else {
|
||||
clientState.character.Humanoid.UnequipTools()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe opt this into our system for inputs?
|
||||
|
@ -46,7 +47,9 @@ const slot: Hooks.FC<slotProps> = (props, hooks) => {
|
|||
return (
|
||||
<frame
|
||||
BackgroundColor3={Color3.fromHex("#11111b")}
|
||||
BackgroundTransparency={.7}
|
||||
BackgroundTransparency={
|
||||
.7
|
||||
}
|
||||
Size={new UDim2(1, 0, 1, 0)}
|
||||
>
|
||||
<uiaspectratioconstraint
|
||||
|
@ -56,7 +59,7 @@ const slot: Hooks.FC<slotProps> = (props, hooks) => {
|
|||
CornerRadius={new UDim(0, 8)}
|
||||
/>
|
||||
<Padding
|
||||
PaddingY={new UDim(.3, 0)}
|
||||
paddingY={new UDim(.3, 0)}
|
||||
/>
|
||||
<textlabel
|
||||
TextColor3={Color3.fromHex("#cdd6f4")}
|
||||
|
@ -80,4 +83,4 @@ const slot: Hooks.FC<slotProps> = (props, hooks) => {
|
|||
)
|
||||
}
|
||||
|
||||
export default new Hooks(Roact)(slot)
|
||||
export default slot
|
|
@ -1,15 +1,17 @@
|
|||
import Roact from "@rbxts/roact"
|
||||
import Hooks from "@rbxts/roact-hooks"
|
||||
import Hotbar from "./hotbar/hotbar"
|
||||
import { withHookDetection } from "@rbxts/roact-hooked"
|
||||
|
||||
interface mainProps extends Roact.JsxInstanceEvents<ScreenGui> {
|
||||
Event?: Roact.JsxInstanceEvents<ScreenGui>
|
||||
Change?: Roact.JsxInstanceChangeEvents<ScreenGui>
|
||||
}
|
||||
|
||||
const main: Hooks.FC<mainProps> = (props, _hooks) => {
|
||||
export default function main(props: mainProps): Roact.Element {
|
||||
const spreadableProps = { ...props } as Partial<mainProps>
|
||||
|
||||
withHookDetection(Roact)
|
||||
|
||||
return (
|
||||
<screengui ResetOnSpawn={true} IgnoreGuiInset {...spreadableProps}>
|
||||
<Hotbar
|
||||
|
@ -20,5 +22,3 @@ const main: Hooks.FC<mainProps> = (props, _hooks) => {
|
|||
</screengui>
|
||||
)
|
||||
}
|
||||
|
||||
export default new Hooks(Roact)(main)
|
18
yarn.lock
18
yarn.lock
|
@ -113,15 +113,25 @@
|
|||
resolved "https://registry.yarnpkg.com/@rbxts/plasma/-/plasma-0.4.1-ts.1.tgz#3d8db367c3220e6b6953cdddbf8af9f087165392"
|
||||
integrity sha512-RhLkC3GQW0KeyqjFwvOUbHhsIJOHmXg+BhcKLp0IgUDVgC5GktShi3zmW6GQ319yod+RlUDG1XHjOnP3Omo4bA==
|
||||
|
||||
"@rbxts/reflex@^4.2.0":
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@rbxts/reflex/-/reflex-4.2.0.tgz#10d064de5e293f1aea429846d4d8739821cb575a"
|
||||
integrity sha512-zkoffeK86feq1cX3+Dd31UCVplI18L7PiD7MI2HRij4wz4jGzqEbpiE9fJT2g5DLxEcNvfgZZEHvxlM2IT7xTw==
|
||||
|
||||
"@rbxts/rewire@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@rbxts/rewire/-/rewire-0.3.0.tgz#47f0cd651fe405cf418936799d2a4dac6b1bb7ce"
|
||||
integrity sha512-wChhGZ3kEkEsMK9ZuwKpwRsC7OGVZlvxrYMR3beFgCIPXE58JKLziBLkDACmd709XCCEmsMAqv9HMCMhSTD08Q==
|
||||
|
||||
"@rbxts/roact-hooks@^0.4.1-ts.3":
|
||||
version "0.4.1-ts.3"
|
||||
resolved "https://registry.yarnpkg.com/@rbxts/roact-hooks/-/roact-hooks-0.4.1-ts.3.tgz#af9b549f5912bd50640c2887aa698e21154fadd3"
|
||||
integrity sha512-+8A42hDsSwZNnXDe1XIRpJhjSpxFvkBa8nB5QM1zuL2q5G6h6SGp7augY6vp6euze/gH4/Laho07PUM8bz0RKQ==
|
||||
"@rbxts/roact-hooked@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@rbxts/roact-hooked/-/roact-hooked-2.6.0.tgz#cbe3e244e1d52d879083c62b6662c4d082c6d30b"
|
||||
integrity sha512-2lVbmKVregnXjshCDWuU05mv7XphxBPzeqSXDZmGh9cLqR+9DihEzsGGQrorU5VbsoL//4cOhYEAt3lTyo3dAw==
|
||||
|
||||
"@rbxts/roact-reflex@^2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rbxts/roact-reflex/-/roact-reflex-2.1.0.tgz#fb0eebcccdaf7cfe1c030ed26ce119c4e8994780"
|
||||
integrity sha512-2RKp9P4MQn2rxK6xk0lcaAZNlD9+X2zLvqkueFSuW4HvgrX3wWtk4RGKjRzRu+pvnszIhdgJpsUZT+lyTObsSQ==
|
||||
|
||||
"@rbxts/roact@^1.4.4-ts.0":
|
||||
version "1.4.4-ts.0"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue