Compare commits

...

4 commits

Author SHA1 Message Date
f5584a9b0c update imports, update game name 2023-08-15 18:15:40 -07:00
968e054158 make uicomponents folder 2023-08-15 18:08:11 -07:00
808ed82e3f update todo 2023-08-15 17:59:25 -07:00
cfccbe4883 swap to roact-hooked, init roact-reflex 2023-08-15 17:58:36 -07:00
16 changed files with 128 additions and 160 deletions

View file

@ -1,5 +1,5 @@
{
"name": "roblox-ts-game",
"name": "goopler",
"globIgnorePaths": [
"**/package.json",
"**/tsconfig.json"

View file

@ -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",

View file

@ -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)

View file

@ -0,0 +1,4 @@
import { UseProducerHook, useProducer } from "@rbxts/roact-reflex"
import { rootProducer } from "../producer"
export const useRootProducer: UseProducerHook<rootProducer> = useProducer

View 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)

View 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

View file

@ -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)

View file

@ -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)

View file

@ -0,0 +1,4 @@
import { UseProducerHook, useProducer } from "@rbxts/roact-reflex"
import { rootProducer } from "../producer"
export const useUiProducer: UseProducerHook<rootProducer> = useProducer

View 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)

View file

@ -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")
}

View file

@ -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")

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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"