-
Notifications
You must be signed in to change notification settings - Fork 863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Physics behavior editor #825
Conversation
@@ -27,11 +28,15 @@ export default ( | |||
.getExtraInfo() | |||
.toJSArray() | |||
.map(value => ({ value, label: value })); | |||
const dialog = PropertiesRenderingService.getDialogComponent( | |||
property.getExtraInfo().toJSArray()[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks risky to me. [0] could return undefined and you typed getDialogComponent
as taking a string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah, I know, I feel a bit bad each time I read that "line", very WIP maybe?
I've to add some extra safe checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you could actually move this into the getDialog
function? Would defer the call to getDialogComponent until it's really needed - so no useless call and easier to debug calls to getDialogComponent too
You're 100% sure you're running the version of libGD.js with the fix right? |
I'm adding the behavior demo that you created (test beds for joints) and when converting it for the webapp, the whole behavior is not saved, so there is some issue somewhere 🤔 |
Mmm no sorry it was another issue (forgot to load extensions in the script that create the examples files for the web-app). |
What would be the best way to show an image preview in the behaviors editor? passing the resources manager information to the GDevelop/newIDE/app/src/ObjectEditor/ObjectEditorDialog.js Lines 106 to 113 in 0cecf68
Sounds fine, it's done for the object properties some lines before, but then passing the resource to the PropertiesEditor looks weird:GDevelop/newIDE/app/src/BehaviorsEditor/index.js Lines 182 to 185 in 0cecf68
What do you think? |
Sorry for the delay, mmm I guess we can start by passing resourceSources down to the PropertiesEditor. Make it an optional Prop (so that it's not mandatory for other property editors). Will see if there is a better way, but I don't think so (when thinking about it, if a PropertiesEditor has to shown fields that need the resources... then it needs to have the resources). |
* Dynamic dimension labels in function of the shape * Preview box, circle and edge * Prevent invalid properties values
Just a thought, are you adding a zoom to this editor so it's not like the existing hitbox one and if you are, will this code be usable there? |
|
||
type Props = {| | ||
onInstancesModified?: Instances => void, | ||
instances: Instances, | ||
schema: Schema, | ||
mode?: 'column' | 'row', | ||
project?: Project, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use gdProject
:) Typing for objects of libGD.js is done inside flow-typed/libGD.js
file. Most of the definitions right now are very simple, but it's important to always use the proper type, because in the future we might want to write them properly or autogenerate them from C++ classes.
render() { | ||
const { mode } = this.props; | ||
|
||
for (var i = 0, len = this.props.schema.length; i < len; i++) { | ||
if (this.props.schema[i].getDialog) { | ||
return ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused about this part. Shouldn't that be done below, for each field? (by below I mean, after if (field.getValue) something like this: if (field.getDialog) return this._renderDialogField(field);
)
I was thinking of getDialog as something that is specific for a field, not something that would overwrite all the properties editor - in this case, better don't even have a property editor in the first place.
Do you think it would be possible to instead display the content of the "dialog" inline with other fields? That would reduce the need to create custom dialogs for only the fields that need it.
Otherwise, it looks weird to me to have a field having a "getDialog", that will "hijack" the whole editor for all the rest of the field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But how to make it to not render fields defined in the custom dialog?
For example if I render everything it will render my dialog and the density
property, and I need the density property defined to use it in the dialog... or an I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me think about it, but I think we can move toward a solution that is more similar to ObjectsEditorService
, but for Behaviors (BehaviorsEditorService
). i.e: we register the editor that you created for the behavior. If a behavior does not have a registered editor, then BehaviorsEditorService
will create a PropertiesEditor, like what we do now.
I was thinking of doing the same for ObjectsEditorService
: if you don't set an editor for your object, a default editor showing the properties will be displayed.
So both ObjectsEditorService
and BehaviorsEditorService
would work the same. It would avoid having a strange handling of "getDialog" in PropertiesEditor, allow custom editors while providing a default editor for most behaviors/objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!, will read the ObjectsEditorService
in-depth.
Things to check out:
btw the wiki article is growing (http://wiki.compilgames.net/doku.php/gdevelop5/behaviors/physics2), will start adding images and instructions once the editor is completed :) |
This is incredible work! ❤️ I'll take a look at this as soon as possible, thanks for listing the things to check out.
Yep, zoom should be something that should be added to work with anything showing a preview. I think it's outside of the scope of the extension.
That looks great! Yeah the goal is that any component that you use for building the UI is already themed. Glad it worked without you doing anything special :)
Great! The wiki article together with this full featured extensions and editor will be super appreciated by all users! |
Great that the zoom code when added will work for all 😁 |
/> | ||
</Line> | ||
<Line> | ||
<div style={{ width: '50%' }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can use two <Column noMargin>
instead of div with width 50%
this.forceUpdate(); | ||
}} | ||
> | ||
{[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the array seems unnecessary ( {[ ... ]} )
</SelectField> | ||
</Line> | ||
<Line> | ||
<div style={{ width: '33%' }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer using <Column noMargin>
rather than div
|
||
renderBitProperty( | ||
properties: Object, | ||
isLayer: boolean, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than passing isLayer, it would be a bit more extensible if you pass "propertyName" :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, don't know why I did it this way... :P
(don't care about the approve thing, I just wanted to comment ^^) |
I'm happy you've not said I'm using the properties and states all upside down :) |
No, most things make sense :) Will have to check more thoroughly because I only did a quick pass so expect more comments but we're going in the right direction, especially once we have the BehaviorsEditorService! :) |
import AddCircle from 'material-ui/svg-icons/content/add-circle'; | ||
import Delete from 'material-ui/svg-icons/action/delete'; | ||
|
||
type Vertex = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use exact object typing here? ( "burger" {| ... |} notation )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also do export type Vertex = ...
to import it in another file.
// @flow | ||
import * as React from 'react'; | ||
|
||
type Vertex = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better do import { type Vertex } from './PolygonEditor'
const { draggedVertex } = this.state; | ||
if (!draggedVertex) return; | ||
|
||
const pointOnScreen = this._svg.createSVGPoint(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recognize this code ;) I think at some point we'll have to factor this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I see what you did there, coordinate systems between different elements is a pain :/
|
||
this.state = { | ||
image: '', | ||
imageWidth: 9, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for this 9 here? ^^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, that's just a very sexy 0 :D
}); | ||
}; | ||
|
||
_isPolygonConvex(properties: Object) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpicking: properties is a gdMapStringPropertyDescriptor
(even if this map to Object for now).
I hope to be able to bring better typing to GDevelop.js later, I've seen some projects like nbind creating typing automatically.
); | ||
} | ||
|
||
renderNumericProperty( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that instead of doing a renderXXX method, you could extract this function out of the component, call it NumericProperty, and have an object as argument. Let's call this argument... props :)
function NumericProperty(props: {| properties: Object, name: string, limit: boolean, min: number, step: number |})
And boom, you have a component :) Well actually, you need to pass project and behavior and a "onUpdate" callback. Then you can do in your render:
<NumericProperty
properties={properties}
name={...}
limit
min={...}
step={...}
onUpdate={...}
/>
(btw, this is what is super great with React. The cost of abstracting something in a component is literally to move a function... this make the barrier to refactoring and abstracting things ultra low).
It's a bit more readable that using renderXXX
methods. It also allow to move these extracted component in other files if needed (here it's fine to keep them in a single file, colocating components is a good thing as long as they are not too big).
Applied the suggested changes, "expand" in the columns did the trick. Also moved the polygon convexity check to the polygon editor, has a lot more sense to be there, and added the limit to 8 vertices. |
constructor(props: Props) { | ||
super(props); | ||
|
||
this.resourcesLoader = ResourcesLoader; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, I think we can entirely avoid a constructor by doing:
resourcesLoader = ResourcesLoader;
state = {
image: '',
imageWidth: 0,
imageHeight: 0,
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, something I would love to change, readed the constructor was the recommend way when you had default state values, but I trust you :)
)} | ||
</Line> | ||
<Line> | ||
<SemiControlledTextField // Debug vertices raw content |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is to be removed once we've fixed the issue with vertices?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, this and the vertices array check/reset.
</EmptyMessage> | ||
)} | ||
</div> | ||
<BehaviorComponent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great 👍
Can you explain me again the issue with the vertices loading? I'll try to reproduce the issue and fix it |
); | ||
|
||
return ( | ||
<div style={styles.propertiesContainer}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've copied this editor almost exactly for the future default editor for objects 👍
Note that we can use <Column>
instead of the div
and remove the custom style propertiesContainer
. This will use the margins from Column
which are standardized across the app.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will change it then :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The vertices array is not loaded properly from the game file (initial game parsing). Try it: edit an object with a polygon and save, if you edit the game file you'll notice the vertices are properly saved. Open the game again in GD and the vertices array is converted to a degenerated object instantly. The weird part is that I've un/serialized the behavior content in a hardcoded string and the serializer loads the vertices correctly. |
Seems that the only missing points from my original list are the bad vertices loading and the warnings about mixing ">" and "!==" without parenthesis removed by prettify. |
Ok, for the warnings about mixing operators, put |
Found the culprit for the vertices! Turns out that this was the issue: 4ian/GDevelop.js@7feb8d3#diff-0b0a8f42de3a19264369288a15d8b56bR133 So in JavaScript, with GDevelop.js, it's more efficient to let JavaScript parse JSON (using JSON.parse) and then traverse this object to create the associated gd.SerializerElement (that can feed into GDevelop.js) instead of using gd.Serializer.fromJSON (which does the parsing using the C++ written JSON serializer) (JSON.parse was super optimized by browsers vendors and is running as machine code) So what I did was to add an adhoc "special" function called gd.Serializer.fromJSObject. This is the function doing the step I was talking about "traverse this object to create the associated gd.SerializerElement". The issue was that I properly fixed earlier gd.Serializer.fromJSON to understand arrays and store them as SerializerElement that are arrays, but I totally forgot to update gd.Serializer.fromJSObject. I was able to save a polygon, open it again, modify it, save it and open it again. Ideally, I will add a test case for this in the tests of GDevelop.js. |
I've opened a pull request some hours ago in GDevelop.js, hehe I won! |
Oh sorry I missed the pull request (but I've made sure to be notified of any future one). Good job, you won indeed, here is your medal: 🥇;) |
Yeah, let me do some save/loads and polygon tests |
I've noticed that the polygon editor renders the top-left polygon origin in the same way than from the origin point, not sure if it's possible to fix?, can you access the object origin point from the IDE? |
I don't think there is anything like this. By the way, ideally we would automatically load a preview of the object rather than asking to the user to select an image, which is I think a bit strange/counter intuitive? |
Yeah, that would require lot of work, as it has to be abstracted from the object type, for example should the preview render a text object (using the default string)? A nice future goal, make the image preview not truncated at the image topleft, support zoom, image origin and maybe a coordinates converter. And add an object renderer that can make a render of an object into a texture, and pass this texture and the object origin to the image preview. |
I think ideally it should work by creating a Pixi renderer (instead of the image) and then rendering the instance (the renderers extending RenderedInstance) like it's done in the scene editor ( |
Will merge now :) |
Huge huge thanks @Lizard-13 for working on this! This new editor will be something that will definitely help people take advantage of the new physics engine!! As next steps, we should I think concentrate on having a few examples and a exhaustive wiki page. |
Will take a look right now. |
Fixed, polygons work perfect, the problem was on not-polygon shapes :/ |
Also adds custom polygon support.
@4ian Now the parser works fine, I can make a fast test and check that un/serializing an isolated behavior content string convert the string to JSON and to string again correctly, arrays included. But for some reason, it doesn't work when opening a project file, I'm doing the following:
vertices
is[]
{}
Again, the parser works fine with the same isolated behavior string, am I going crazy?