添加ReactUI-未显示,待继续调试
This commit is contained in:
+8
-2
@@ -1,4 +1,10 @@
|
|||||||
import * as UE from 'ue'
|
import * as UE from 'ue'
|
||||||
import {argv} from 'puerts'
|
import {argv} from 'puerts';
|
||||||
|
import {ReactUMG} from 'react-umg';
|
||||||
|
import * as UI from './ui';
|
||||||
|
|
||||||
console.log("---------------------------------0---------------------")
|
console.log('--------------------------0----------------------')
|
||||||
|
//用React来写UI
|
||||||
|
let world = (argv.getByName("GameInstance") as UE.GameInstance).GetWorld();
|
||||||
|
ReactUMG.init(world);
|
||||||
|
UI.Load();
|
||||||
|
|||||||
@@ -0,0 +1,293 @@
|
|||||||
|
import * as Reconciler from 'react-reconciler'
|
||||||
|
import * as puerts from 'puerts'
|
||||||
|
import * as UE from 'ue'
|
||||||
|
|
||||||
|
let world: UE.World;
|
||||||
|
|
||||||
|
function deepEquals(x: any, y: any) {
|
||||||
|
if ( x === y ) return true;
|
||||||
|
|
||||||
|
if ( ! ( x instanceof Object ) || ! ( y instanceof Object ) ) return false;
|
||||||
|
|
||||||
|
for (var p in x) { // all x[p] in y
|
||||||
|
if (p == 'children' || p == 'Slot') continue;
|
||||||
|
if (!deepEquals(x[p], y[p])) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var p in y) {
|
||||||
|
if (p == 'children' || p == 'Slot') continue;
|
||||||
|
if (!x.hasOwnProperty(p)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const exports: {lazyloadComponents:{}}
|
||||||
|
|
||||||
|
class UEWidget {
|
||||||
|
type: string;
|
||||||
|
callbackRemovers: {[key: string] : () => void};
|
||||||
|
nativePtr: UE.Widget;
|
||||||
|
slot: any;
|
||||||
|
nativeSlotPtr: UE.PanelSlot;
|
||||||
|
|
||||||
|
constructor (type: string, props: any) {
|
||||||
|
this.type = type;
|
||||||
|
this.callbackRemovers = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.init(type, props);
|
||||||
|
} catch(e) {
|
||||||
|
console.error("create " + type + " throw " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(type: string, props: any) {
|
||||||
|
let classPath = exports.lazyloadComponents[type];
|
||||||
|
if (classPath) {
|
||||||
|
//this.nativePtr = asyncUIManager.CreateComponentByClassPathName(classPath);
|
||||||
|
this.nativePtr = UE.NewObject(UE.Class.Load(classPath)) as UE.Widget;
|
||||||
|
} else {
|
||||||
|
this.nativePtr = new UE[type]();
|
||||||
|
}
|
||||||
|
|
||||||
|
let myProps = {};
|
||||||
|
for (const key in props) {
|
||||||
|
let val = props[key];
|
||||||
|
if (key == 'Slot') {
|
||||||
|
this.slot = val;
|
||||||
|
} else if (typeof val === 'function') {
|
||||||
|
this.bind(key, val);
|
||||||
|
} else if(key !== 'children') {
|
||||||
|
myProps[key] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log("UEWidget", type, JSON.stringify(myProps))
|
||||||
|
puerts.merge(this.nativePtr, myProps);
|
||||||
|
//console.log(type + ' inited')
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(name: string, callback: Function) {
|
||||||
|
let nativePtr = this.nativePtr
|
||||||
|
let prop = nativePtr[name];
|
||||||
|
if (typeof prop.Add === 'function') {
|
||||||
|
prop.Add(callback);
|
||||||
|
this.callbackRemovers[name] = () => {
|
||||||
|
prop.Remove(callback);
|
||||||
|
}
|
||||||
|
} else if (typeof prop.Bind == 'function') {
|
||||||
|
prop.Bind(callback);
|
||||||
|
this.callbackRemovers[name] = () => {
|
||||||
|
prop.Unbind();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("unsupport callback " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(oldProps: any, newProps: any) {
|
||||||
|
let myProps = {};
|
||||||
|
let propChange = false;
|
||||||
|
for(var key in newProps) {
|
||||||
|
let oldProp = oldProps[key];
|
||||||
|
let newProp = newProps[key];
|
||||||
|
if (key != 'children' && oldProp != newProp) {
|
||||||
|
if (key == 'Slot') {
|
||||||
|
this.slot = newProp;
|
||||||
|
//console.log("update slot..", this.toJSON());
|
||||||
|
puerts.merge(this.nativeSlotPtr, newProp);
|
||||||
|
UE.UMGManager.SynchronizeSlotProperties(this.nativeSlotPtr)
|
||||||
|
} else if (typeof newProp === 'function') {
|
||||||
|
this.unbind(key);
|
||||||
|
this.bind(key, newProp);
|
||||||
|
} else {
|
||||||
|
myProps[key] = newProp;
|
||||||
|
propChange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (propChange) {
|
||||||
|
//console.log("update props", this.toJSON(), JSON.stringify(myProps));
|
||||||
|
puerts.merge(this.nativePtr, myProps);
|
||||||
|
UE.UMGManager.SynchronizeWidgetProperties(this.nativePtr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(name: string) {
|
||||||
|
let remover = this.callbackRemovers[name];
|
||||||
|
this.callbackRemovers[name] = undefined;
|
||||||
|
if (remover) {
|
||||||
|
remover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindAll() {
|
||||||
|
for(var key in this.callbackRemovers) {
|
||||||
|
this.callbackRemovers[key]();
|
||||||
|
}
|
||||||
|
this.callbackRemovers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
appendChild(child: UEWidget) {
|
||||||
|
let nativeSlot = (this.nativePtr as UE.PanelWidget).AddChild(child.nativePtr);
|
||||||
|
//console.log("appendChild", (await this.nativePtr).toJSON(), (await child.nativePtr).toJSON());
|
||||||
|
child.nativeSlot = nativeSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeChild(child: UEWidget) {
|
||||||
|
child.unbindAll();
|
||||||
|
(this.nativePtr as UE.PanelWidget).RemoveChild(child.nativePtr);
|
||||||
|
//console.log("removeChild", (await this.nativePtr).toJSON(), (await child.nativePtr).toJSON())
|
||||||
|
}
|
||||||
|
|
||||||
|
set nativeSlot(value: UE.PanelSlot) {
|
||||||
|
this.nativeSlotPtr = value;
|
||||||
|
//console.log('setting nativeSlot', value.toJSON());
|
||||||
|
if (this.slot) {
|
||||||
|
puerts.merge(this.nativeSlotPtr, this.slot);
|
||||||
|
UE.UMGManager.SynchronizeSlotProperties(this.nativeSlotPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UEWidgetRoot {
|
||||||
|
nativePtr: UE.ReactWidget;
|
||||||
|
Added: boolean;
|
||||||
|
|
||||||
|
constructor(nativePtr: UE.ReactWidget) {
|
||||||
|
this.nativePtr = nativePtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
appendChild(child: UEWidget) {
|
||||||
|
let nativeSlot = this.nativePtr.AddChild(child.nativePtr);
|
||||||
|
child.nativeSlot = nativeSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeChild(child: UEWidget) {
|
||||||
|
child.unbindAll();
|
||||||
|
this.nativePtr.RemoveChild(child.nativePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
addToViewport(z : number) {
|
||||||
|
if (!this.Added) {
|
||||||
|
this.nativePtr.AddToViewport(z);
|
||||||
|
this.Added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFromViewport() {
|
||||||
|
this.nativePtr.RemoveFromViewport();
|
||||||
|
}
|
||||||
|
|
||||||
|
getWidget() {
|
||||||
|
return this.nativePtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostConfig : Reconciler.HostConfig<string, any, UEWidgetRoot, UEWidget, UEWidget, any, any, {}, any, any, any, any> = {
|
||||||
|
getRootHostContext () {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
//CanvasPanel()的parentHostContext是getRootHostContext返回的值
|
||||||
|
getChildHostContext (parentHostContext: {}) {
|
||||||
|
return parentHostContext;//no use, share one
|
||||||
|
},
|
||||||
|
appendInitialChild (parent: UEWidget, child: UEWidget) {
|
||||||
|
parent.appendChild(child);
|
||||||
|
},
|
||||||
|
appendChildToContainer (container: UEWidgetRoot, child: UEWidget) {
|
||||||
|
container.appendChild(child);
|
||||||
|
},
|
||||||
|
appendChild (parent: UEWidget, child: UEWidget) {
|
||||||
|
parent.appendChild(child);
|
||||||
|
},
|
||||||
|
createInstance (type: string, props: any) {
|
||||||
|
return new UEWidget(type, props);
|
||||||
|
},
|
||||||
|
createTextInstance (text: string) {
|
||||||
|
return new UEWidget("TextBlock", {Text: text});
|
||||||
|
},
|
||||||
|
finalizeInitialChildren () {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
getPublicInstance (instance: UEWidget) {
|
||||||
|
console.warn('getPublicInstance');
|
||||||
|
return instance
|
||||||
|
},
|
||||||
|
now: Date.now,
|
||||||
|
prepareForCommit () {
|
||||||
|
//log('prepareForCommit');
|
||||||
|
},
|
||||||
|
resetAfterCommit (container: UEWidgetRoot) {
|
||||||
|
container.addToViewport(0);
|
||||||
|
},
|
||||||
|
resetTextContent () {
|
||||||
|
console.error('resetTextContent not implemented!');
|
||||||
|
},
|
||||||
|
shouldSetTextContent (type, props) {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
commitTextUpdate (textInstance: UEWidget, oldText: string, newText: string) {
|
||||||
|
if (oldText != newText) {
|
||||||
|
textInstance.update({}, {Text: newText})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
//return false表示不更新,真值将会出现到commitUpdate的updatePayload里头
|
||||||
|
prepareUpdate (instance: UEWidget, type: string, oldProps: any, newProps: any) {
|
||||||
|
try{
|
||||||
|
return !deepEquals(oldProps, newProps);
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e.message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
commitUpdate (instance: UEWidget, updatePayload: any, type : string, oldProps : any, newProps: any) {
|
||||||
|
try{
|
||||||
|
instance.update(oldProps, newProps);
|
||||||
|
} catch(e) {
|
||||||
|
console.error("commitUpdate fail!, " + e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeChildFromContainer (container: UEWidgetRoot, child: UEWidget) {
|
||||||
|
console.error('removeChildFromContainer');
|
||||||
|
//container.removeChild(child).catch(e => {
|
||||||
|
// console.error('removeChildFromContainer , e:' + e.message);
|
||||||
|
//});
|
||||||
|
},
|
||||||
|
removeChild(parent: UEWidget, child: UEWidget) {
|
||||||
|
parent.removeChild(child);
|
||||||
|
},
|
||||||
|
|
||||||
|
//useSyncScheduling: true,
|
||||||
|
supportsMutation: true,
|
||||||
|
isPrimaryRenderer: true,
|
||||||
|
supportsPersistence: false,
|
||||||
|
supportsHydration: false,
|
||||||
|
|
||||||
|
shouldDeprioritizeSubtree: undefined,
|
||||||
|
setTimeout: undefined,
|
||||||
|
clearTimeout: undefined,
|
||||||
|
cancelDeferredCallback: undefined,
|
||||||
|
noTimeout: undefined,
|
||||||
|
scheduleDeferredCallback: undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
const reconciler = Reconciler(hostConfig)
|
||||||
|
|
||||||
|
export const ReactUMG = {
|
||||||
|
render: function(reactElement: React.ReactNode) {
|
||||||
|
if (world == undefined) {
|
||||||
|
throw new Error("init with World first!");
|
||||||
|
}
|
||||||
|
let root = new UEWidgetRoot(UE.UMGManager.CreateReactWidget(world));
|
||||||
|
const container = reconciler.createContainer(root, false, false);
|
||||||
|
reconciler.updateContainer(reactElement, container, null, null);
|
||||||
|
return root;
|
||||||
|
},
|
||||||
|
init: function(inWorld: UE.World) {
|
||||||
|
world = inWorld;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { VerticalBox, CanvasPanel, ReactUMG, CanvasPanelSlot, Button, HorizontalBox/*, TextureImage*/ } from 'react-umg';
|
||||||
|
import {StatusBar} from './ui-components'
|
||||||
|
interface Props {
|
||||||
|
names: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
names: string[];
|
||||||
|
buttonTextureIndex: 0 | 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let SlotOfVerticalBox: CanvasPanelSlot = {
|
||||||
|
LayoutData: {
|
||||||
|
Offsets: {
|
||||||
|
Left: 120,
|
||||||
|
Top: 120,
|
||||||
|
Right: 480,
|
||||||
|
Bottom: 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Hello extends React.Component<Props, State> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
names: props.names,
|
||||||
|
buttonTextureIndex : 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<CanvasPanel>
|
||||||
|
<VerticalBox Slot={SlotOfVerticalBox}>
|
||||||
|
<HorizontalBox>
|
||||||
|
<Button OnHovered={() => this.setState({buttonTextureIndex: 1})} OnUnhovered={() => this.setState({buttonTextureIndex: 0})} >
|
||||||
|
{this.state.buttonTextureIndex == 0 ? 'normal' : 'hovered'}
|
||||||
|
</Button>
|
||||||
|
</HorizontalBox>
|
||||||
|
{this.state.names.map((name, idx) => <StatusBar name={name} key={idx}/>)}
|
||||||
|
</VerticalBox>
|
||||||
|
</CanvasPanel>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Load(){
|
||||||
|
return ReactUMG.render(
|
||||||
|
<Hello names={["Health:", "Energy:"]}/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { Button, HorizontalBox, TextBlock, ProgressBar, HorizontalBoxSlot } from 'react-umg';
|
||||||
|
import {LinearColor} from 'ue'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
name: string;
|
||||||
|
initialPercent?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
percent: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
let SlotOfProgressBar: HorizontalBoxSlot = {
|
||||||
|
Size: {
|
||||||
|
SizeRule: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StatusBar extends React.Component<Props, State> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
if ((props.initialPercent || 0) < 0) {
|
||||||
|
throw new Error('initialPercent < 0');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
percent: props.initialPercent || 0.5
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get color(): Partial<LinearColor> {
|
||||||
|
return {R: 1 - this.state.percent , G: 0, B: this.state.percent};
|
||||||
|
}
|
||||||
|
|
||||||
|
onIncrement = () => this.setState({percent: this.state.percent + 0.01});
|
||||||
|
onDecrement = () => this.setState({percent: this.state.percent - 0.01});
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<HorizontalBox>
|
||||||
|
<TextBlock Text={`${this.props.name}(${this.state.percent.toFixed(2)})`}/>
|
||||||
|
<ProgressBar Percent={this.state.percent} Slot={SlotOfProgressBar} FillColorAndOpacity={this.color}/>
|
||||||
|
<Button OnClicked={this.onIncrement} >+</Button>
|
||||||
|
<Button OnClicked={this.onDecrement} >-</Button>
|
||||||
|
</HorizontalBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user