Porting game to MonoAGS

Started by cat, Sun 13/05/2018 21:12:08

Previous topic - Next topic

tzachs

Quote from: cat on Mon 28/01/2019 20:35:27
Okay, setting the pivot of each sprite to 0.5 did it.
Great to hear!

Quote from: cat on Mon 28/01/2019 20:35:27
I reuse some sprites for various animations and making separate folders for it would be unnecessary overhead. I'll stick to manual sprite creation for now.
Sure.
Hopefully when the editor is ready it will allow you to share the sprites without having to work so hard for it.

cat

Quote from: tzachs on Tue 29/01/2019 02:22:19
Hopefully when the editor is ready it will allow you to share the sprites without having to work so hard for it.
For me it is not a question of working hard to set up the folder structure, but of "don't repeat yourself". If I have the same sprite in various folders and want to change it, I have to take care to replace every instance of it. Also, with high-res games, this could increase size (granted, not with my three mouse sprites, but you get the idea).

tzachs

Quote from: cat on Tue 29/01/2019 09:00:38
Quote from: tzachs on Tue 29/01/2019 02:22:19
Hopefully when the editor is ready it will allow you to share the sprites without having to work so hard for it.
For me it is not a question of working hard to set up the folder structure, but of "don't repeat yourself". If I have the same sprite in various folders and want to change it, I have to take care to replace every instance of it. Also, with high-res games, this could increase size (granted, not with my three mouse sprites, but you get the idea).
By "working hard" I meant writing all of that code that you wrote in order not to duplicate the sprites. The editor will generate that code for you.

cat


cat

#104
Finally some more MonoAGS!

I found a slight quirk (using the latest master branch, but could be the issue existed before):

I change to my main room using
Code: ags
await game.State.Player.ChangeRoomAsync(Rooms.Stage, 2300, 100);


In the room, OnAfterFadeIn, I start a cutscene
Code: ags

        private void OnAfterFadeIn()
        {
            PlayIntroCutscene();
        }

        private async void PlayIntroCutscene()
        {
            Characters.Cornelius.PlaceOnWalkableArea();
            
            await Characters.Cornelius.SayAsync("Hello, here I am.");
            await Characters.Mortimer.SayAsync("* squeak *");

            FollowCat();
        }

Now, when I click somewhere on the screen while the cat is talking, it will immediately slide to the clicked position without walk animation being played.


And another question: You probably have told me already, but how does setting an object's baseline work? I didn't find a baseline property.

tzachs

Quote from: cat on Sun 28/04/2019 20:25:55
Finally some more MonoAGS!
Hooray!  ;-D

Quote from: cat on Sun 28/04/2019 20:25:55Now, when I click somewhere on the screen while the cat is talking, it will immediately slide to the clicked position without walk animation being played.
Hmm, I'll look into that.
But, do you even want to allow walking the cat during the cutscene? Because if you don't, you can put "Characters.Cornelius.Enabled = false;" at the beginning of the scene (and "Characters.Cornelius.Enabled = true" when you want to return control to the player).

Also, slightly off-topic, but you can wrap your cutscene with "game.State.Cutscene.Start()" and "game.State.Cutscene.End()" in order to allow the player to skip the scene (how the player can trigger skipping the scene is controlled with "game.State.Custcene.SkipTrigger").

Quote from: cat on Sun 28/04/2019 20:25:55
And another question: You probably have told me already, but how does setting an object's baseline work? I didn't find a baseline property.
The short answer is that the Z property is the object's baseline (and by default, unless you explicitly set Z, Z will equal Y).

The longer answer is that the order in which objects render first depends on their render layer. For example, by default, all GUIs are created in a separate layer than room objects, and as the GUIs layer has a lower Z than the object layer, all guis will appear in front of all room objects, even if their individual Z says otherwise.
In other words, the object's Z is compared only for objects in the same render layer.
Also, you can add a Z offset for individual sprites, those are added to the object's Z when the comparison is made. So if you have an animation for an object in which you need one of the frames to appear behind something, you can give that specific frame an individual Z offset to make that happen.
And lastly, if you use object composition (i.e Cornelius the cat might have a gun as a separate object and that gun has the cat as its parent), then the children objects will only be compared against themselves, and will use their parents for comparing against other objects.

cat

#106
Quote from: tzachs on Sun 28/04/2019 22:42:35
Hmm, I'll look into that.
Thanks!

Quote
But, do you even want to allow walking the cat during the cutscene? Because if you don't, you can put "Characters.Cornelius.Enabled = false;" at the beginning of the scene (and "Characters.Cornelius.Enabled = true" when you want to return control to the player).
Does this mean I have to disable the character everytime I have a cutscene? With AGS, talking was blocking, so noone could walk around during a scripted dialog scene.
Didn't you build something that disables walking while talking?

Edit: I found the post I was talking about: https://www.adventuregamestudio.co.uk/forums/index.php?topic=56055.msg636597241#msg636597241

Quote
Also, slightly off-topic, but you can wrap your cutscene with "game.State.Cutscene.Start()" and "game.State.Cutscene.End()" in order to allow the player to skip the scene (how the player can trigger skipping the scene is controlled with "game.State.Custcene.SkipTrigger").
Thanks, but this is not the final intro cutscene anyway. I wanted to write it last to avoid having to skip a cutscene everytime when testing.

Quote
The short answer is that the Z property is the object's baseline (and by default, unless you explicitly set Z, Z will equal Y).

The longer answer is that the order in which objects render first depends on their render layer. For example, by default, all GUIs are created in a separate layer than room objects, and as the GUIs layer has a lower Z than the object layer, all guis will appear in front of all room objects, even if their individual Z says otherwise.
In other words, the object's Z is compared only for objects in the same render layer.
Also, you can add a Z offset for individual sprites, those are added to the object's Z when the comparison is made. So if you have an animation for an object in which you need one of the frames to appear behind something, you can give that specific frame an individual Z offset to make that happen.
And lastly, if you use object composition (i.e Cornelius the cat might have a gun as a separate object and that gun has the cat as its parent), then the children objects will only be compared against themselves, and will use their parents for comparing against other objects.
Wow, lot's of options! Thanks for the explanation.

tzachs

Quote from: cat on Mon 29/04/2019 08:49:19
Does this mean I have to disable the character everytime I have a cutscene? With AGS, talking was blocking, so noone could walk around during a scripted dialog scene.
Right, I didn't want to disable the player automatically for every event handling, because I wanted to allow writing "responsive cutscenes" (which is not always trivial to do with AGS).
The plan is for the editor to (by default) automatically inject disabling/enabling the player when handling events (along with starting/ending a cutscene and hiding/changing the mouse cursor).

Quote from: cat on Mon 29/04/2019 08:49:19
Didn't you build something that disables walking while talking?

Edit: I found the post I was talking about: https://www.adventuregamestudio.co.uk/forums/index.php?topic=56055.msg636597241#msg636597241
Right, hence the "i'll look into that"  :)

Crimson Wizard

#108
Quote from: tzachs on Mon 29/04/2019 14:44:20
Quote from: cat on Mon 29/04/2019 08:49:19
Does this mean I have to disable the character everytime I have a cutscene? With AGS, talking was blocking, so noone could walk around during a scripted dialog scene.
Right, I didn't want to disable the player automatically for every event handling, because I wanted to allow writing "responsive cutscenes" (which is not always trivial to do with AGS).
The plan is for the editor to (by default) automatically inject disabling/enabling the player when handling events (along with starting/ending a cutscene and hiding/changing the mouse cursor).

tzachs, I had some thinking about this recently, after discussing blocking/nonblocking problem with a person, and there's a concept of "control stack" shaping in my head.
To put things briefly, you logically divide the game entities into "control layers" (which may be unrelated to anything else), which form a "control stack". Then, you may order certain layer to "pause" which would efficiently stop updates in the layer and anything below.

Such scheme will let user to decide which parts of the game are paused at any given time. For example, on the top of the stack there's a main menu. Lower are in-game menus (inventory etc). If game menus have animations, calling main menu in "modal mode" will automatically stop them.
If you want blocking dialogs, you can move participants to the separate layer above the rest of the game, which would effectively allow to pause everything "behind them".
Want blocking cutscene - have "cutscene layer" and attach involved entities to it.
If you like game keep playing idle animations but want all the story-related triggers to pause, you split story script and run it attached to some "controlling entity" on the lowest layer. And so on.

tzachs

Yes, and I think it can maybe go hand-in-hand with the "time machine" feature we once discussed: i.e a group of entities are assigned to a specific "time machine" (your "control layer") which then allows you to slow down/speed up time, rewind, forward and pause, whereas pause is the same pause that you were talking about (pausing time will also effectively block inputs).

cat

That concept of "time-machine" and "control-layers" sounds very interesting!

cat

I created the first very basic dialog. It works, but the dialog options are partly hidden behind my stage GUI. Is is possible to change the order of elements? Or do I have to implement IDialogLayout as written in the documentation?

tzachs

Ah, good catch.
I've put the dialogs on the same layer as the GUIs by default, so they can be behind other GUIs. I'll change the default and put them in their own layer.

Meanwhile, you can change the layer for your stage to be behind other GUIs (but still in front of room objects):
Code: csharp

stage.RenderLayer = new AGSRenderLayer(AGSLayers.UI.Z + 1);

cat

Quote from: tzachs on Tue 30/04/2019 21:14:21
Ah, good catch.
I've put the dialogs on the same layer as the GUIs by default, so they can be behind other GUIs. I'll change the default and put them in their own layer.

Meanwhile, you can change the layer for your stage to be behind other GUIs (but still in front of room objects):
Code: csharp

stage.RenderLayer = new AGSRenderLayer(AGSLayers.UI.Z + 1);

Nice! I didn't know you could create your own layers.
I agree that it could be useful to put other GUIs in front of the dialog. Would it be possible to change the Z-order of the dialog itself but keeping it in the UI Layer?

One more question: In the start-up logic of the game, I set game.Settings.Defaults.SpeechFont and TextFont to a custom font. This works very well for spoken text as well as the "Loading" label of AGSSplashScreen, but it doesn't work for the dialog options. They are tiny (remember, the game is high-res) and with a different font. Would it be possible to use the TextFont there?

tzachs

Quote from: cat on Wed 01/05/2019 12:24:49
Would it be possible to change the Z-order of the dialog itself but keeping it in the UI Layer?
Yes, this should do the trick:
Code: csharp

var dialog = factory.GetDialog(...);
dialog.Graphics.Z = 50;


Quote from: cat on Wed 01/05/2019 12:24:49
One more question: In the start-up logic of the game, I set game.Settings.Defaults.SpeechFont and TextFont to a custom font. This works very well for spoken text as well as the "Loading" label of AGSSplashScreen, but it doesn't work for the dialog options. They are tiny (remember, the game is high-res) and with a different font. Would it be possible to use the TextFont there?
Ah, right, I missed that.
It should be fixed in this branch: https://github.com/tzachshabtay/MonoAGS/pull/316
Do you want to test it before I merge to master?

cat

Quote from: tzachs on Thu 02/05/2019 03:36:26
Do you want to test it before I merge to master?
Sure, I will test it in the evening.


I had a quick look at the pull request and a more general question comes up:
It is great that you can specify lots of config for each individual dialog line, but I'd assume that most users will want to have all dialog options look the same, i.e. have one color for all options and another color for all hovered. In your pull request you create a custom getDialogOption() function, but ideally something like this should be provided by the framework.
Is it possible to set the color as default? Or have a hook where to put a custom function for styling all dialog options, like in AGS where you can use a few functions to make your owner drawn GUI? Not sure what would be the best option for this. And would it be possible to use graphics for dialog options?
What are your plans on how this will develop in the future?

tzachs

Right. Ideally I would like you to be able to set defaults for everything, i.e the default settings in which you set the default text & speech fonts should also have a section for dialogs where you can set default colors, default render layer, etc (maybe I'll just add it for this PR, it's pretty simple).

As for hooks, you can either, like you said, override IDialogLayout and make changes to dialog options there, or you can override IDialogFactory and create your own dialog & dialog options.

And yes, it's possible to use graphics for dialog options:
Code: csharp

var option = factory.GetDialogOption("Hello!");
option.Label.Image = myImage; 

//and label has all of the regular object's components, so you can also do:
option.Label.StartAnimation(myAnimation);
option.Label.TweenY(...); //etc

cat

Quote from: tzachs on Thu 02/05/2019 03:36:26
It should be fixed in this branch: https://github.com/tzachshabtay/MonoAGS/pull/316
I tried it and it works  :)

I noticed one more quirk with the Z-order: I set the z-order of the stage frame panel with
Code: ags
panel.RenderLayer = new AGSRenderLayer(AGSLayers.UI.Z + 1);


The dialog text is now shown above the stage frame, but the black background box is shown behind.

When I use
Code: ags
dialog.Graphics.Z = 50;

the same thing happens. Even weirder, in this case the black background is even shown behind the characters!

tzachs

Right, another thing to fix (forgot to put the black box on the same layer as the dialog options).
I'll add the fix to the PR, but in the meantime, you can do:

Code: csharp

var dialog = factory.GetDialog(...);
dialog.Graphics.RenderLayer = AGSLayers.UI;

tzachs

I pushed the fixes to the PR.

One breaking change: defaults.TextFont and defaults.SpeechFont changed to defaults.Fonts.Text and defaults.Fonts.Speech.
I also added defaults.Fonts.Dialog (which you can leave blank to use the text font), and also a default section for dialogs (defaults.Dialog) in which you can set stuff like colors, for example to change the color of hovered dialog options to green:

Code: csharp

game.Settings.Defaults.Dialog.Hovered.Brush = game.Factory.Graphics.Brushes.LoadSolidBrush(Colors.Green);


I also added a dialog rendering layer which by default sits in front of the UI and behind the speech (and you can override it in the defaults.Dialog section as well).

SMF spam blocked by CleanTalk