Skip to content

Commit

Permalink
Refactor part 7
Browse files Browse the repository at this point in the history
  • Loading branch information
memothelemo committed Oct 28, 2021
1 parent a0aad33 commit e2a33b2
Show file tree
Hide file tree
Showing 18 changed files with 505 additions and 1 deletion.
5 changes: 4 additions & 1 deletion default.project.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@
}
},
"Game": {
"$path": "out/shared"
"$path": "out/shared",
"Interface": {
"$path": "out/interface"
}
}
},
"StarterPlayer": {
Expand Down
17 changes: 17 additions & 0 deletions src/interface/context/transparency.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Roact, { createContext } from "@rbxts/roact";
import { RoactBindable } from "types/roact/value";

const TransparencyContext = createContext<RoactBindable<number>>(0);

export default TransparencyContext;

/**
* Wrapper for TransaprencyContext
*
* **IMPORTANT**: Make sure you have a context for
* TransparencyContext otherwise some elements don't work
* well with transparency
*/
export function withTransparency(callback: (alpha: RoactBindable<number>) => Roact.Element) {
return <TransparencyContext.Consumer render={callback} />;
}
14 changes: 14 additions & 0 deletions src/interface/frame/background/base.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Roact, { mount, unmount } from "@rbxts/roact";
import RoactChildrenTest from "interface/storybook/childrenTest";
import { HoarcekatStory } from "types/roact/hoarcekat";
import BackgroundFrame from "./base";

export = identity<HoarcekatStory>(parent => {
const tree = mount(
<BackgroundFrame Color={Color3.fromRGB(23, 128, 233)}>
<RoactChildrenTest />
</BackgroundFrame>,
parent,
);
return () => unmount(tree);
});
33 changes: 33 additions & 0 deletions src/interface/frame/background/base.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Roact from "@rbxts/roact";
import { RoactBindable } from "types/roact/value";
import TransparencyContext from "../../context/transparency";

// The reason it can be exported because it can be extended even further than this component
export interface BackgroundFrameProps {
FullScreen?: boolean;
Color?: RoactBindable<Color3>;
Transparency?: RoactBindable<number>;
}

/** Bring the app into a wide full screen! */
export default function BackgroundFrame(props: Roact.PropsWithChildren<BackgroundFrameProps>) {
return (
<frame
Size={props.FullScreen ? new UDim2(1, 0, 1, 40) : UDim2.fromScale(1, 1)}
Position={UDim2.fromOffset(0, -40)}
BackgroundColor3={props.Color}
Transparency={props.Transparency}
>
<frame
Key="Container"
Position={props.FullScreen ? UDim2.fromOffset(0, 40) : new UDim2()}
Size={new UDim2(1, 0, 1, -40)}
BackgroundTransparency={1}
>
<TransparencyContext.Provider value={props.Transparency ?? 0}>
{props[Roact.Children]}
</TransparencyContext.Provider>
</frame>
</frame>
);
}
69 changes: 69 additions & 0 deletions src/interface/frame/background/fade.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Linear, SingleMotor, Spring } from "@rbxts/flipper";
import Roact, { Binding, Component } from "@rbxts/roact";
import { BindingUtil } from "shared/util/binding";
import BackgroundFrame, { BackgroundFrameProps } from "./base";

type LinearMotorMethod = {
TweenMethod: "Linear";
LinearProps?: {
velocity: number;
};
};

type SpringMotorMethod = {
TweenMethod: "Spring";
SpringProps?: {
frequency: number;
damping: number;
};
};

type Props = Omit<BackgroundFrameProps, "Transparency"> & {
Visible: boolean;
} & (LinearMotorMethod | SpringMotorMethod);

/** BackgroundFrame but it is fading whenever the transparency property changes */
export default class FadeBackgroundFrame extends Component<Props> {
public binding: Binding<number>;
public motor: SingleMotor;

public constructor(props: Props) {
super(props);

this.motor = new SingleMotor(0);
this.binding = BindingUtil.makeBindingFromMotor(this.motor);
}

public getTransparencyFromProp() {
return (this.props.Visible === undefined ? false : this.props.Visible) === true ? 0 : 1;
}

/** Updates transparency based on the props available */
public updateTransparency() {
const constant_value = this.getTransparencyFromProp();
this.motor.setGoal(
this.props.TweenMethod === "Linear"
? new Linear(constant_value, { ...this.props.LinearProps })
: new Spring(constant_value, { ...this.props.SpringProps }),
);
}

public didUpdate(lastProps: Props) {
if (this.props.Visible !== lastProps.Visible) {
this.updateTransparency();
}
}

public render() {
// excluding props and injecting it to BackgroundFrame
// to avoid unexpected collisions
const spread_props = { ...this.props };
spread_props[Roact.Children] = undefined;
spread_props.Visible = undefined as unknown as boolean;
return (
<BackgroundFrame {...spread_props} Transparency={this.binding}>
{this.props[Roact.Children]}
</BackgroundFrame>
);
}
}
32 changes: 32 additions & 0 deletions src/interface/frame/background/fadeLinear.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Roact, { mount, unmount } from "@rbxts/roact";
import RoactHooks from "@rbxts/roact-hooks";
import RoactChildrenTest from "interface/storybook/childrenTest";
import { Thread } from "shared/util/thread";
import { HoarcekatStory } from "types/roact/hoarcekat";
import FadeBackgroundFrame from "./fade";

const TestBench: RoactHooks.FC = (_, { useState, useEffect }) => {
const [visible, setVisible] = useState(false);

useEffect(() => {
const connection = Thread.Loop(1, () => setVisible(!visible));
return () => connection.Disconnect();
});

return (
<FadeBackgroundFrame
Color={Color3.fromRGB(233, 122, 9)}
TweenMethod="Linear"
LinearProps={{ velocity: 2 }}
Visible={visible}
>
<RoactChildrenTest />
</FadeBackgroundFrame>
);
};

export = identity<HoarcekatStory>(parent => {
const Component = new RoactHooks(Roact)(TestBench);
const tree = mount(<Component />, parent);
return () => unmount(tree);
});
32 changes: 32 additions & 0 deletions src/interface/frame/background/fadeSpring.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Roact, { mount, unmount } from "@rbxts/roact";
import RoactHooks from "@rbxts/roact-hooks";
import RoactChildrenTest from "interface/storybook/childrenTest";
import { Thread } from "shared/util/thread";
import { HoarcekatStory } from "types/roact/hoarcekat";
import FadeBackgroundFrame from "./fade";

const TestBench: RoactHooks.FC = (_, { useState, useEffect }) => {
const [visible, setVisible] = useState(false);

useEffect(() => {
const connection = Thread.Loop(1, () => setVisible(!visible));
return () => connection.Disconnect();
});

return (
<FadeBackgroundFrame
Color={Color3.fromRGB(233, 122, 9)}
TweenMethod="Spring"
SpringProps={{ frequency: 2, damping: 1 }}
Visible={visible}
>
<RoactChildrenTest />
</FadeBackgroundFrame>
);
};

export = identity<HoarcekatStory>(parent => {
const Component = new RoactHooks(Roact)(TestBench);
const tree = mount(<Component />, parent);
return () => unmount(tree);
});
14 changes: 14 additions & 0 deletions src/interface/frame/background/invisible.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Roact, { mount, unmount } from "@rbxts/roact";
import RoactChildrenTest from "interface/storybook/childrenTest";
import { HoarcekatStory } from "types/roact/hoarcekat";
import InvisibleBackgroundFrame from "./invisible";

export = identity<HoarcekatStory>(parent => {
const tree = mount(
<InvisibleBackgroundFrame>
<RoactChildrenTest />
</InvisibleBackgroundFrame>,
parent,
);
return () => unmount(tree);
});
9 changes: 9 additions & 0 deletions src/interface/frame/background/invisible.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Roact, { PropsWithChildren } from "@rbxts/roact";

export default function InvisibleBackgroundFrame(props: PropsWithChildren) {
return (
<frame BackgroundTransparency={1} Size={UDim2.fromScale(1, 1)}>
{props[Roact.Children]}
</frame>
);
}
41 changes: 41 additions & 0 deletions src/interface/frame/spring/base.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Roact, { mount, unmount } from "@rbxts/roact";
import RoactHooks from "@rbxts/roact-hooks";
import RoactChildrenTest from "interface/storybook/childrenTest";
import { Thread } from "shared/util/thread";
import { HoarcekatStory } from "types/roact/hoarcekat";
import BaseSpringFrame from "./base";

function generateProps() {
return {
size: UDim2.fromScale(math.random(), math.random()),
position: UDim2.fromScale(math.random(), math.random()),
};
}

const TestBench: RoactHooks.FC = (_, { useState, useEffect }) => {
const [props, setProps] = useState(generateProps());

useEffect(() => {
const connection = Thread.Loop(2, () => setProps(generateProps()));
return () => connection.Disconnect();
});

return (
<BaseSpringFrame
Size={props.size}
Position={props.position}
SpringProps={{
frequency: 2,
damping: 1,
}}
>
<RoactChildrenTest />
</BaseSpringFrame>
);
};

export = identity<HoarcekatStory>(parent => {
const Component = new RoactHooks(Roact)(TestBench);
const tree = mount(<Component />, parent);
return () => unmount(tree);
});
107 changes: 107 additions & 0 deletions src/interface/frame/spring/base.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// This script is based on my other scrapped Gitlab repo

import { Instant, SingleMotor, Spring } from "@rbxts/flipper";
import Roact, { Binding, Component } from "@rbxts/roact";
import { BindingUtil } from "shared/util/binding";

export interface BaseSpringFrameProps extends Omit<Roact.JsxInstance<Frame>, "Position" | "Size"> {
Position?: UDim2;
Size?: UDim2;
SpringProps?: {
frequency?: number;
damping?: number;
};
}

/** A simple frame allows to move freely with animations! */
export default class BaseSpringFrame extends Component<BaseSpringFrameProps> {
private lastPosition?: UDim2;
private lastSize?: UDim2;

private positionMotor: SingleMotor;
private positionBinding: Binding<number>;

private sizeMotor: SingleMotor;
private sizeBinding: Binding<number>;

public constructor(props: BaseSpringFrameProps) {
super(props);

this.positionMotor = new SingleMotor(0);
this.positionBinding = BindingUtil.makeBindingFromMotor(this.positionMotor);

this.sizeMotor = new SingleMotor(0);
this.sizeBinding = BindingUtil.makeBindingFromMotor(this.sizeMotor);

this.lastPosition = this.props.Position;
this.lastSize = this.props.Size;
}

private isPositionChanged(lastProps: BaseSpringFrameProps) {
return (
lastProps.Position !== this.props.Position &&
this.props.Position !== undefined &&
lastProps.Position !== undefined
);
}

private isSizeChanged(lastProps: BaseSpringFrameProps) {
return lastProps.Size !== this.props.Size && this.props.Size !== undefined && lastProps.Size !== undefined;
}

private makeSpringFromProps(value: number) {
return new Spring(value, { ...this.props.SpringProps });
}

public didUpdate(lastProps: BaseSpringFrameProps) {
// make sure it did changed the position
if (this.isPositionChanged(lastProps)) {
this.lastPosition = lastProps.Position;
this.positionMotor.setGoal(new Instant(0));

// a simple fix?
this.positionMotor.step(1);

// assume the position is valid
this.positionMotor.setGoal(this.makeSpringFromProps(1));
}

// make sure it did changed the size
if (this.isSizeChanged(lastProps)) {
this.lastSize = lastProps.Size;
this.sizeMotor.setGoal(new Instant(0));

// a simple fix?
this.sizeMotor.step(1);

// assume the position is valid
this.sizeMotor.setGoal(this.makeSpringFromProps(1));
}
}

public render() {
const spread_props = { ...this.props };
spread_props[Roact.Children] = undefined;
spread_props.Position = undefined;
spread_props.Size = undefined;
spread_props.SpringProps = undefined;

return (
<frame
{...spread_props}
Position={this.positionBinding.map(alpha => {
const new_position = this.props.Position ?? new UDim2();
const last_position = this.lastPosition ?? new UDim2();
return last_position.Lerp(new_position, alpha);
})}
Size={this.sizeBinding.map(alpha => {
const new_size = this.props.Size ?? new UDim2();
const last_size = this.lastSize ?? new UDim2();
return last_size.Lerp(new_size, alpha);
})}
>
{this.props[Roact.Children]}
</frame>
);
}
}
Loading

0 comments on commit e2a33b2

Please sign in to comment.