Adding different layout options from the 2D editor - godot

I would like to make the following views for portrait and landscape mode:
In portrait, show the views vertically as
A
B
C
(looks like they are in a VBox)
In landscape, show the views as
A C
B
(looks like HBox(VBox(A, B), C))
I am able to do this with the use of a custom container, but it means measuring sizes myself, and requiring that all 3 nodes by immediate children in my container.
I was wondering if there was a different approach where we can define two completely separate layouts in the editor, and associate certain nodes with the nodes we want; this is a pattern I'm more familiar with through android dev, where we can create two completely different layouts and associate certain views by having the same id.
For this case, I would be able to create the layouts I mentioned above with the existing VBox and HBox, and tell the root note to place A, B, C where they should be. The children no longer need to be immediate children of the root container, and I can add other nodes to one of the layouts and not the other. If a user switches between these two layouts, I expect that the contents within the shared nodes (A, B, C) be retained.
Is there a way of doing something like this in Godot?

You can do what you're describing by creating two separate layouts in the editor and instantiating + replacing when needed.
extends Control
const LANDSCAPE_LAYOUT = preload("res://Landscape.tscn")
const PORTRAIT_LAYOUT = preload("res://Portrait.tscn")
var orientation = 0
onready var layout = $Layout // root node of UI you will replace
func _process(delta):
if orientation != OS.screen_orientation:
_change_layout()
func _change_layout():
orientation = OS.screen_orientation
var new_layout = null
match orientation:
0:
new_layout = LANDSCAPE_LAYOUT.instance()
1:
new_layout = PORTRAIT_LAYOUT.instance()
_:
return // feel free to include the other cases in ScreenOrientation enum.
var layout_position = layout.get_position_in_parent()
remove_child(layout)
add_child(new_layout)
move_child(new_layout, layout_position)
layout = new_layout
Similar to the Android activity lifecycle, you are destroying and recreating a portion of your UI whenever the orientation changes.
I'm checking orientation manually because there's no way to get a callback for it currently. If you're going to have multiple nodes checking the orientation, it might be useful to set up a singleton instead and emit a signal when it detects a change.

Related

Is there a `HVBoxContainer` for Godot?

Think of an RPG game where you might need to present a list of buttons. A user might enter a room where they have to select from a series of options (buttons). Is there a type of container/panel that would show clickable buttons horizontally, but wrap if needed?
The best analogy I can think of to picture the situation is, Imagine needing to click on an item in a backpack, but each item is potentially a different width. (I can make them all the same height but the width then varies)
.---[My Backpack]------.
| aaa bbb cccc ddd |
| ee fff g |
| |
| |
`----------------------'
(The options come from a database, so its unknown at compile time how many options might be in a room, so I am going to need to programmatically add options.)
The very bottom of this godot document introduces custom container layouts, but it's unclear to me how this would work in practice
Flow container for Godot 3.5 or newer
Godot 3.5 (currently in beta) introduces HFlowContainer and VFlowContainer that will serve the propuse described.
The HFlowContainer will fill a row and when they overflow, it will add a new row and continue there. The VFlowContainer will work on a similar fashion but with columns.
Flow containers before Godot 3.5
For older versions of Godot you can use the HFlowContainer addon which you can find it in the asset library (here). Note that there is no VFlowContainer counterpart.
As everything on the asset library it is free and open source, so feel free to read the code and modify it, which can be serve as starting point if you want to make your own custom Container.
Making your own custom Container
The gist of making a custom Container is that it must position its children.
For that effect you react to NOTIFICATION_SORT_CHILDREN in the _notification method. You might also want to react to NOTIFICATION_RESIZED.
You can have a method - which I'll call layout - that you call when you get the notifications:
func _notification(what):
if what == NOTIFICATION_SORT_CHILDREN:
layout()
And also call layout from the setters (setget) of the properties that define how the Container must organize its children. To call layout from anywhere other than _notification, you might want to use call_deferred("layout") to prevent any possible re-layout loops from hanging or crashing the game.
The layout method would iterate over the visible children Controls and use get_combined_minimum_size to figure out their size.
Something like this:
func layout() -> void:
# …
for child in get_children():
var control := child as Control
if not is_instance_valid(control) or not control.visible:
continue
var size := control.get_combined_minimum_size()
# …
Then using that information compute the position and size for the children Controls. When there is room for the Controls to grow, you may want to split it among them according to their size_flags_stretch_ratio.
Once you have the position and size for a Control decided, use fit_child_in_rect to position them, which will take into account grow and size flags.
Thus - barring the simplest Containers - you will need to iterate over the children Controls twice. And for that you might find useful to have an auxiliary data structure to temporarily store them.

Make Godot "Script Variables" control appearance in 2D editor?

I have a "Player" scene, which holds everything about a player, the sprite, the animations, the shadow, and a collection of other things.
A script variable 1,2,3,4, etc.. controls which image/texture/sprite data is loaded, to control the appearance.
But when I drop them on the 2D editor, they all have the default image, so they all look identical. Which is confusing. Whats the best way to make each player appear different in the editor?
This code in the player script is good at allowing setting a player number, and loading a different image set, but it doesn't show in the 2D editor. Changing the character number makes the image change at runtime:
export var characterNumber = 1
var player1 = preload("res://Player/Player1.tres")
var player2 = preload("res://Player/Player2.tres")
func _ready():
if characterNumber == 1:
get_node("Sprite").set_texture(player1)
if characterNumber == 2:
get_node("Sprite").set_texture(player2)
Alternatively, I could have multiple sprites in a generic player scene, and turn them on and off depending on the characterNumber, but again, the same problem occurs, the change isn't visible until runtime.
One idea is multiple children scenes, but I cant work out how to turn sprites on or off depending on a variable or some other type of setting.
What am I doing wrong?
In your script your want to make it a 'tool' so it can execute inside your editor, and not only when you launch the game.
see https://docs.godotengine.org/en/stable/tutorials/plugins/running_code_in_the_editor.html
In your case, you might use something like the following: (make sure to do "Scene -> Reload saved scene" to reload the constructor if your change the node's property)... a more ergonomic (but takes more processing) solution is to put it in the _process func
tool
export var characterNumber = 1
var player1 = preload("res://Player/Player1.tres")
var player2 = preload("res://Player/Player2.tres")
func _ready():
if Engine.editor_hint:
if characterNumber == 1:
print("executing custom in editor logic")
if characterNumber == 1:
get_node("Sprite").set_texture(player1)
if characterNumber == 2:
get_node("Sprite").set_texture(player2)
func _process(_delta):
if Engine.editor_hint:
# only rotate the object if we set the character number to 1
if characterNumber == 1:
rotate(Vector3(0,1,0), deg2rad(15*_delta))
set_my_texture() #quick n dirty way for fast reload
func set_my_texture():
if characterNumber == 1:
get_node("Sprite").set_texture(player1)
if characterNumber == 2:
get_node("Sprite").set_texture(player2)
Ryu's approach of using a tool script would work. You can use Engine.editor_hint to identify when your script is running in the editor.
By the way, combine it with setget, so you can define a setter function that will run when you modify the variable. You should not need _process, which would be running every frame.
Anyway, let me cover a few alternatives:
You can make inherited scenes (from the context menu of an existing scene in the FileSystem panel choose "New Inherited Scene"), and there modify it however you want. You can change properties such as the texture of sprites, or you can add other scene instances as children. This solves the problem of placing an instance of a particular variation of your scene, and being able to tell it apart in the editor, without the need to run your script on the editor.
If you have all the textures you want in single atlas/sprite sheet, you can use an AnimatedSprite, except you are not going to use it to animate. Instead put all the textures in a single animation, and then change the frame to pick the texture you want. This gets close to what you want in that you just change a number (the frame).
For completeness I'll also mention that you can use an AtlasTexture to load a texture form an sprite sheet. On the texture of your Sprite (for example), select "New AtlasTexture", then atlas of the AtlasTexture load your sprite sheet, and set region to take the area of the texture atlas you want. I suggest setting the size (width and height of the region) first. This approach will also work for anywhere you might need a texture, although tweaking the region is more work that simply setting a number. By the way, AnimatedTexture can serve a similar role, but it does not give you a way to specify the frame you want.
And yes, you could control any of these form a tool script.
Addendum: by the way, you know you can enable "Editable Children" on the scene instances on the Scene panel, right? It is in the context menu. That lets you edit the instances directly. I wanted to mention it, just in case that helps you.

Changing the Layout/Look of the app via Settings in Kotlin/Android

I'm trying to let the user change the layout of the Main Activity via settings. So for example someone can select the newest layout or the original older layout. What would be the best way to do this. Thanks.
All your layouts should have the same number of views, with the same IDs.
If you do so, then you can have a ConstraintLayout as the root layout, and create clones of the layout with the child items arranged in different ways. Then, based on the setting, you would apply the constrains from a specific layout to the master layout.
Check this for reference
Context context = this;
mConstraintSet2.clone(context, R.layout.state2); // get constraints from layout
setContentView(R.layout.state1);
mConstraintLayout = (ConstraintLayout) findViewById(R.id.activity_main);
mConstraintSet2.applyTo(mConstraintLayout)

Particles generated behind sprite

I just started out with Phaser.
I have a simple sprite in the middle of the screen, and whenever I click the sprite, I emit a particle at the clicked x,y coordinates.
My problem is that the particles are generated behind the sprite. I have tried setting z on the sprite to 1 and the emitter to 1000 without luck.
What am I missing?
var emitter = game.add.emitter(game.world.centerX, game.world.centeryY);
emitter.makeParticles('phaser');
var sprite = game.add.sprite(game.world.centerX, game.world.centerY, 'phaser');
sprite.scale.setTo(2, 2);
sprite.inputEnabled = true;
sprite.events.onInputDown.add(function(sender, pointer){
emitter.emitX = pointer.x;
emitter.emitY = pointer.y;
emitter.emitParticle();
}, this);
http://phaser.io/sandbox/cxBVeHrx
EDIT
My actual code is based on the Phaser-ES6-Boilerplate. Even though BdRs answer solves the issue in the sandbox code, I'm not able to utilize this in my real code.
I have uploaded both the code and a running example. Hopefully someone can tell me where I have screwed things up...
Separate Phaser items don't have a z-order, instead it just depends on the order you create and add them to game. Each new sprite or emitter or group etc. will be displayed on top of all previously added items.
So, simply changing your code to something like this should work.
// first the sprite
var sprite = game.add.sprite(game.world.centerX, game.world.centerY, 'phaser');
sprite.scale.setTo(2, 2);
// then the particles in front of sprite
var emitter = game.add.emitter(game.world.centerX, game.world.centeryY);
emitter.makeParticles('phaser');
// then maybe text in front of particles and sprite
var mytest = game.add.bitmapText(10, 20, 'myfont', 'Level 1', 16);
// etc.
Btw sprites do have a .z value but that only used when it's part of a Phaser.Group, it will then be used as the display z-order but only within that group of sprites.
By default, phaser will not sort objects that get added to any group, it will just render them in the order that they get added. In your case, you can just add the emitter to the group after you add the sprite (the group in this case is the 'game' object).
Of course, having to add objects in the drawing order is not ideal, and if you need to have them sorted dynamically, not possible.
Another way is you can sort objects within a group using the 'sort' function, in which you give it the name of a parameter to sort by, and you sort whenever you need to (in some cases, in the Update callback).
Sorting every frame can be a performance hit though, especially if you have a lot of objects. Another way you could go about this is by adding groups, sorting those groups in draw order (think of them like layers), and then adding objects to those groups in any order. Any group that needs sorting within itself you can sort as well. This way, you can choose to have (for example) a background layer not needing to be sorted but everything added to that layer will be behind every other layer.
Good answers from everybody, but you are missing that every GameObject has a depth property which serves exactly the z-index purpose. This way you do not need to rely on the order of objects creation.
There is also an official
example.
Hope this helps.

JavaFX 2 change layout dynamically at runtime?

Swing had LayoutManager's separate from the containers. So far as I can tell, JavaFX doesn't do that.
I have a complex structure of nodes that I want the user to be able to toggle between several different layout approaches. Something equivalent to the user specifying flow and all containers are converted to the equivalent of FlowPanes. Then they could choose vertical and everything is laid out vertically.
Is there a way to do this other than swapping out the nodes/recreating the whole structure?
I should note: the hierarchy changes at runtime and it is deeply nested.
I mention Swing because this is straightforward to do in Swing by maintaining a list of all containers in the entire hierarchy, and with a simple loop (or tree traversal without the list) setting a new LayoutManager on them. JavaFX doesn't seem to have this possibility because the layout behavior appears to be internal to the nodes.
Isn't something like this working ?
AnchorPane main=new AnchorPane();
AnchorPane sub1=new AnchorPane();
sub1.getChildren().add(btn);
main.getChildren().add(sub1);
When you want to switch the layout
AnchorPane sub2=new AnchorPane();
main.getChildren().remove(sub1);
main.getChildren().add(sub2);
Edit
I guess I missed how you are doing layouts. This is how I envisioned it.
Definitions to Various Components
MainLayout
-> CustomLayout 1
-> References to various components. ( Essentially you are not creating all the components for every layout, rather you are referring to them in each layout )
-> CustomLayout 2
-> References to various components. ( More or less a different arrangement of the same components, adds some component references and removes some )
-> CustomLayout 3
-> References to various components.
Making a bold statement, but if there were a tool in JavaFX, how would it do this automatically ? Each template needs to know where it should render a particular component and arguably the easiest way to do this is just create a new template that arranges the components in a different layout and swap the template when user wants to see a different layout.
This is not easy to do in Swing. You would still need to set all the layout constraints on the individual components again, unless your layout is very straightforward.
I don't see how there is much difference in this between swing and javaFX. In JavaFX you would need to add the same controls to a different container (VBox, HBox etc.) but you still don't need to recreate the controls every time. It is a little awkward to find the containers in the middle of the node hierarchy but I'm sure there is some kind of elegant recursive solution :)

Resources