Author Topic: Porting game to MonoAGS  (Read 5356 times)

tzachs

  • Local Moderator
  • AGS Baker
  • Mittens Vassal
  • Parking Goat- games that goats like!
    • I can help with translating
    •  
    • tzachs worked on a game that was nominated for an AGS Award!
Re: Porting game to MonoAGS
« Reply #80 on: 11 Nov 2018, 21:38 »
When the player performs a right click when an inventory is active, there is a null reference exception at AGS.Engine.TwoButtonsInputScheme.SetInv entoryCursor(IInventoryItem inventoryItem) in line 37
onRightMouseDown sets the ActiveItem to null, which then triggers the OnPropertyChanged handler.
I'd change SetInventoryCursor to reset the default cursor when null is passed and the active inventory is null. This would help regarding the exception, but also allow the programmer to change back the active inventory programmatically. This is needed when I use the active inventory item on a hotspot and this results in me losing the inventory item.
Should be fixed now (still same branch).

Another issue: You might want to check if the previous cursor should really be changed. Otherwise, there will be weird issues when setting two active items after each other without returning to the default cursor in between.
Consider renaming _previousCursor to _defaultCursor, then it will be more clear. You could also provide a method SetDefaultCursor. This way you can safely change the default cursor, no matter if there is currently an inventory active or not.
Right, I was doing copypasta from the rotating cursors scheme... :-[
Changed it now (there's a default cursor you can pass in the constructor, and also a DefaultCursor property you can set on the scheme afterwards).

Works, but 80% seems a bit too much. Maybe 70% is enough? (But this might be because of my setup with the stage frame around it.)
Ok, I don't have any preference myself, so I changed it to 70%.

Btw, is it on purpose that the text wraps left-aligned instead of centered? It doesn't look that nice, especially when there is only a word or two in the second line.
Not on purpose, but a bit more complicated to get right for all text rendering scenarios, I'm working on it and will update.

cat

  • Mittens Baronet
  • AGS Baker
  • Saving Christmas
    • cat worked on a game that was nominated for an AGS Award!
      cat worked on a game that won an AGS Award!
Re: Porting game to MonoAGS
« Reply #81 on: 12 Nov 2018, 19:54 »
It works except for one thing: I set the default cursor via the constructor, but it is only applied after changing to the inventory cursor and back. Of course I could set the cursor myself, but actually I'd expect this to happen automatically when TwoButtonsInputScheme.Start() is called. The same applies for the setter of the DefaultCursor property.

tzachs

  • Local Moderator
  • AGS Baker
  • Mittens Vassal
  • Parking Goat- games that goats like!
    • I can help with translating
    •  
    • tzachs worked on a game that was nominated for an AGS Award!
Re: Porting game to MonoAGS
« Reply #82 on: 13 Nov 2018, 05:06 »
It works except for one thing: I set the default cursor via the constructor, but it is only applied after changing to the inventory cursor and back. Of course I could set the cursor myself, but actually I'd expect this to happen automatically when TwoButtonsInputScheme.Start() is called. The same applies for the setter of the DefaultCursor property.
Done.

Btw, is it on purpose that the text wraps left-aligned instead of centered? It doesn't look that nice, especially when there is only a word or two in the second line.
I'm still not finished with this, but I pushed just enough so it should work for you as you expect, I hope.

cat

  • Mittens Baronet
  • AGS Baker
  • Saving Christmas
    • cat worked on a game that was nominated for an AGS Award!
      cat worked on a game that won an AGS Award!
Re: Porting game to MonoAGS
« Reply #83 on: 13 Nov 2018, 19:47 »
It works nicely! The cursor is now correct and the text centred nicely. Thanks :)

cat

  • Mittens Baronet
  • AGS Baker
  • Saving Christmas
    • cat worked on a game that was nominated for an AGS Award!
      cat worked on a game that won an AGS Award!
Re: Porting game to MonoAGS
« Reply #84 on: 14 Nov 2018, 20:26 »
Next topic: following a character. I now realize that Cornelius Cat uses quite a lot of different features for such a short game :)

In the original AGS game I use the setting
Code: Adventure Game Studio
  1. cMouse.FollowCharacter(cCat, 150, 0);
This results in the mouse somewhat following the cat, but mostly running around, even when the cat is standing. How do I have to set the values in AGSFollowSettings to achieve the same?

Edit: Btw, there seems to be a problem when un-following a character with Follow(null):
System.NullReferenceException
  HResult=0x80004003
  Message=Object reference not set to an instance of an object.
  Source=AGS.Engine
  StackTrace:
   at AGS.Engine.FollowTag.AddTag(IObject target, IEntity follower) line 23
« Last Edit: 14 Nov 2018, 20:34 by cat »

tzachs

  • Local Moderator
  • AGS Baker
  • Mittens Vassal
  • Parking Goat- games that goats like!
    • I can help with translating
    •  
    • tzachs worked on a game that was nominated for an AGS Award!
Re: Porting game to MonoAGS
« Reply #85 on: 15 Nov 2018, 04:22 »
Next topic: following a character. I now realize that Cornelius Cat uses quite a lot of different features for such a short game :)

In the original AGS game I use the setting
Code: Adventure Game Studio
  1. cMouse.FollowCharacter(cCat, 150, 0);
This results in the mouse somewhat following the cat, but mostly running around, even when the cat is standing. How do I have to set the values in AGSFollowSettings to achieve the same?
So looking at the manual, the first parameter is the distance the follower will stand from its target, and 150 means "about" 150 pixels. I don't know what "about" means exactly, haven't looked at the code, but let's assume that it's give-or-take 10 pixels.
In MonoAGS there are four parameters to control the distance: MinXOffset, MaxXOffset, MinYOffset and MaxYOffset. This gives you better control over the entire square you want to allow the follower. So to kind of mimic what AGS does (assuming that "about" is 10 pixels), I would give something like MinXOffset = 140, MaxXOffset = 160, MinYOffset = 140, MaxYOffset = 160. It's not going to be exactly the same, as AGS gives you one value so I'm guessing it forms a circle, where in MonoAGS it's a square. But this shouldn't make that much of a difference in practice, I think.

As for the second parameter, the eagerness. From looking in the manual it says that setting it to 0 will make the follower to always be on the move and that it will wander around the target like an energetic dog. It doesn't sound like that is what it actually does, from what you're describing, though.
Anyway, the first part, how often it moves, is controlled from MonoAGS by MinWaitBetweenWalks and MaxWaitBetweenWalks. To make it always on the move, set both to 0. The second part per your description, that it will be mostly running around and not actually following the cat, is something that you can control with WanderOffPercentage. If for example you set it to 50, there's a 50% chance for each walk to be to a completely random place, as opposed to the configured square. So for mostly running around to unrelated places, I guess you can set it to 80?
Let me know if it doesn't work out, maybe we need more parameters for better control.

Btw, I plan at some point to add presets to the follow settings with defaults to match common scenarios, so you'll be able to write something like:
Code: C#
  1. mouse.Follow(cornelius, AGSFollowSettings.Companion());
  2.  
  3. //It will also allow you to override specific settings, for example:
  4. mouse.Follow(cornelius, AGSFollowSettings.Companion(wanderOffPercentage: 0));
  5.  

Edit: Btw, there seems to be a problem when un-following a character with Follow(null):
System.NullReferenceException
  HResult=0x80004003
  Message=Object reference not set to an instance of an object.
  Source=AGS.Engine
  StackTrace:
   at AGS.Engine.FollowTag.AddTag(IObject target, IEntity follower) line 23

Should be fixed now (in your branch).

cat

  • Mittens Baronet
  • AGS Baker
  • Saving Christmas
    • cat worked on a game that was nominated for an AGS Award!
      cat worked on a game that won an AGS Award!
Re: Porting game to MonoAGS
« Reply #86 on: 15 Nov 2018, 19:05 »
There still seems to be an issue with stopping the follow.
After fade in, I do
Characters.Mortimer.Follow(Characters.Cornelius);

Later, when using the mouse item on the gate, I have the following cutscene (not finished yet):
Code: Adventure Game Studio
  1. _game.State.Cutscene.Start();
  2.  
  3. Characters.Cornelius.Inventory.ActiveItem = null;
  4. await Characters.Cornelius.WalkAsync((2479f, 0f));
  5. await Characters.Cornelius.SayAsync("Mortimer, come here!");
  6. Characters.Mortimer.Follow(null);
  7. await Characters.Mortimer.WalkAsync((2035, 0f));
  8. Characters.Mortimer.FaceDirection(Characters.Cornelius);
  9. await Characters.Cornelius.SayAsync("I need you to help me with the gate.");
  10. await Characters.Cornelius.SayAsync("You are small. Try to squeeze through it to the other side and open it for me.");
  11. await Characters.Mortimer.SayAsync("* squeak *");
  12.  
  13. // TODO follow cat again
  14.  
  15. _game.State.Cutscene.End();
  16.  
However, when it comes to the line Characters.Mortimer.Follow(null); the game freezes. I cannot even move the mouse cursor anymore.


On a different note: I tried the setting
Characters.Mortimer.Follow(Characters.Cornelius, new AGSFollowSettings(true, 80, 0, 10, 140, 160, 0, 10));
This works almost as desired, but the character will wander off till the end of the walkable area (much farer away than 160 pixel), is it possible to limit this somehow?
« Last Edit: 15 Nov 2018, 19:16 by cat »

tzachs

  • Local Moderator
  • AGS Baker
  • Mittens Vassal
  • Parking Goat- games that goats like!
    • I can help with translating
    •  
    • tzachs worked on a game that was nominated for an AGS Award!
Re: Porting game to MonoAGS
« Reply #87 on: 16 Nov 2018, 19:45 »
However, when it comes to the line Characters.Mortimer.Follow(null); the game freezes. I cannot even move the mouse cursor anymore.
Should be fixed now, and also:
1. Follow(null) followed by walk is problematic, as when you stop following the stop walking action will only be called on the next tick after you fired your walk, so it will stop your walk.
So I added a StopFollowingAsync to be used instead, so await it before walking.
2. I removed the blocking versions of FaceDirection because I'm concerned about their safety, so also replace it with await FaceDirectionAsync.

On a different note: I tried the setting
Characters.Mortimer.Follow(Characters.Cornelius, new AGSFollowSettings(true, 80, 0, 10, 140, 160, 0, 10));
This works almost as desired, but the character will wander off till the end of the walkable area (much farer away than 160 pixel), is it possible to limit this somehow?
Ah, so if you want to stay in the vicinity of the cat, then you don't want to wander off at all, so I'll put it at 0. Wandering off is basically going wherever in the room without care for where the target is.
And btw, you can use named parameters which will make the constructor more readable:
Code: C#
  1. new AGSFollowSettings(wanderOffPercentage: 0,
  2.         minWaitBetweenWalks: 0, maxWaitBetweenWalks: 10,
  3.         minXOffset: 140, maxXOffset: 160,
  4.         minYOffset: 0);

I also added more parameters for tuning the follow behaviour (I don't think you care too much about those parameters for your scenario, but just in case):
1. Be able to have more control over the "wander off" if you want, so it's MinXOffsetForWanderOff etc, same as MinXOffset only just for the wander off phase (if you do want it).
2. Stay put percentage- if the follower is already in valid range of the target, what's the probability to keep moving to a new point anyway? It sounds like you want to always be on the move, so you can leave this at 0 which is the default.
3. Minimum walking distance- I noticed that it looks a little funny when the characters are moving just a few pixels, so this is to enforce a minimum distance for consecutive movements. This will be 10 pixels by default.
4. Stay on the same side percentage (one for x and one for y)- i.e if the follower is on the right of the target, what's the probability for it to stay to the right of the target on the next walk. This is 70% by default, so leaning a bit towards staying in the same side.

cat

  • Mittens Baronet
  • AGS Baker
  • Saving Christmas
    • cat worked on a game that was nominated for an AGS Award!
      cat worked on a game that won an AGS Award!
Re: Porting game to MonoAGS
« Reply #88 on: 17 Nov 2018, 16:18 »
Thanks! I changed the values and it looks quite good already. I might fiddle with it more a bit later, when I have the final walking speed etc.
Code: Adventure Game Studio
  1. Characters.Mortimer.Follow(Characters.Cornelius, new AGSFollowSettings(wanderOffPercentage: 0,
  2. minWaitBetweenWalks: 0, maxWaitBetweenWalks: 100,
  3. minXOffset: 10, maxXOffset: 260,
  4. minYOffset: 0, maxYOffset: 10));

However, stopping still freezes the application (during await Characters.Mortimer.StopFollowingAsync();)

This is what my code looks like now:
Code: Adventure Game Studio
  1. _game.State.Cutscene.Start();
  2.  
  3. Characters.Cornelius.Inventory.ActiveItem = null;
  4. await Characters.Cornelius.WalkAsync((2479f, 0f));
  5. await Characters.Cornelius.SayAsync("Mortimer, come here!");
  6. await Characters.Mortimer.StopFollowingAsync();
  7. await Characters.Mortimer.WalkAsync((2035, 0f));
  8. await Characters.Mortimer.FaceDirectionAsync(Characters.Cornelius);
  9. await Characters.Cornelius.SayAsync("I need you to help me with the gate.");
  10. await Characters.Cornelius.SayAsync("You are small. Try to squeeze through it to the other side and open it for me.");
  11. await Characters.Mortimer.SayAsync("* squeak *");
  12.  
  13. // TODO follow cat again
  14.  
  15. _game.State.Cutscene.End();
When I click the pause button in VS while the game is stuck, it seems to be stuck in AGSGameWindow line 74 with call stack (not very helpful, I guess)
Add spoiler tag for Hidden:
>   AGS.Engine.Desktop.dll!AGS.Engine.Desktop.AGSGameWindow.SwapBu ffers() Line 74   C#
    AGS.Engine.dll!AGS.Engine.AGSGame.onRenderFrame(object sender, AGS.Engine.FrameEventArgs e) Line 225   C#
    AGS.Engine.Desktop.dll!AGS.Engine.Desktop.AGSGameWindow.onRend erFrame(object sender, OpenTK.FrameEventArgs args) Line 87   C#
    [External Code]   
    AGS.Engine.Desktop.dll!AGS.Engine.Desktop.AGSGameWindow.Run(double updateRate) Line 73   C#
    AGS.Engine.dll!AGS.Engine.AGSGame.Start() Line 150   C#
    CorneliusCat.Desktop.exe!CorneliusCat.GameStarter.Run() Line 19   C#
    CorneliusCat.Desktop.exe!CorneliusCat.Desktop.Program.Main(string[] args) Line 10   C#

Another question: if follow(null) can cause problems, wouldn't it be better to remove this synchronous call completely?

Crimson Wizard

  • AGS Project Tracker Admins
    • Best Innovation Award Winner 2013, for spearheading the AGS 3.3.0 project
    •  
    • Lifetime Achievement Award Winner
    •  
    • Crimson Wizard worked on a game that was nominated for an AGS Award!
      Crimson Wizard worked on a game that won an AGS Award!
Re: Porting game to MonoAGS
« Reply #89 on: 17 Nov 2018, 16:25 »
When I click the pause button in VS while the game is stuck, it seems to be stuck in AGSGameWindow line 74 with call stack (not very helpful, I guess)

Not following all the story, but sometimes you may try switching to other threads in "Debug->Windows->Threads" and see if any of available thread stacks has any visible relation to the recent command you are stuck at.

cat

  • Mittens Baronet
  • AGS Baker
  • Saving Christmas
    • cat worked on a game that was nominated for an AGS Award!
      cat worked on a game that won an AGS Award!
Re: Porting game to MonoAGS
« Reply #90 on: 17 Nov 2018, 19:39 »
Good idea. Sadly, I didn't find anything that seems more helpful.

tzachs

  • Local Moderator
  • AGS Baker
  • Mittens Vassal
  • Parking Goat- games that goats like!
    • I can help with translating
    •  
    • tzachs worked on a game that was nominated for an AGS Award!
Re: Porting game to MonoAGS
« Reply #91 on: 17 Nov 2018, 21:11 »
Ok, I think I really fixed it this time, can you try again?
Sorry.. :-[

Another question: if follow(null) can cause problems, wouldn't it be better to remove this synchronous call completely?
Yeah, I'm not really sure what's the best way to handle it yet.
Here's the thing, the follow method just sets the follow target, and then on each game tick it manages its "state machine" to see what's the next move to perform (and if it's stop following, then it will want to stop the existing walk).
So it kind-of follows the same behavior of ChangeRoom in AGS where the script you write after ChangeRoom will actually happen before the room is changed (not a problem in MonoAGS, btw, that's why it's ChangeRoomAsync). And StopFollowingAsync basically calls Follow(null) with an additional task that you can hang onto to wait until the StopWalking happens in the next tick.

Now, I can't really disallow Follow(null) in compile-time yet (though it will be possible when c# 8 is released). I can make it throw an exception in run-time, though the only problem with Follow(null) is the scenario in which you follow(null) and then walk immediately after it (it might ignore that walk) -> in all other scenarios it will work fine, so I'm not too keen on throwing an exception if you pass null to it.
So here's the possible directions I thought I can take this (let me know what you think):
1. I can make Follow into FollowAsync (and remove StopFollowingAsync) and always return a task, even though it's completely not needed if you don't pass null. And also, it might be confusing for the user, as making it async hints that it will await the entire follow until done following, which is not correct. So I'm not in favor of this approach.
2. I can keep things the way they are for now, and when c# 8 is released to disallow nulls to Follow in compile time.
3. I can change it so it won't stop the current walk when you stop following with Follow(null). I'm not sure what AGS does in that scenario, actually (does anybody know?). But I could just let the character complete its last walk as a follower and then just not do any more walks. And I can make StopFollowingAsync to call Follow(null) and then call StopWalkingAsync, so if you do want to stop walking you'll call StopFollowingAsync and if you don't care you can call Follow(null).
4. I can add an option for StopWalking to accept a specific walking task. Then in the follow component I'll call stop walking on "my" specific walk, so there can't be any confusion, the follow component will never stop a walk issued by somebody else (and I can delete StopFollowingAsync completely). I'm not sure how complicated this is to pull off, but this option might be useful in other future scenarios as well.

cat

  • Mittens Baronet
  • AGS Baker
  • Saving Christmas
    • cat worked on a game that was nominated for an AGS Award!
      cat worked on a game that won an AGS Award!
Re: Porting game to MonoAGS
« Reply #92 on: 18 Nov 2018, 19:38 »
It works now :)

Ah, I am so used to Javascript with Closure compiler type annotations, I completely forgot it is not possible to have non-nullable types in C#.

I prefer option 3. I tried it in AGS and there the current walk is not stopped. The mouse will continue walking until it reaches the cat and then stop. StopFollowingAsync sounds like a good add-on. I think it's much easier to explain this way.

tzachs

  • Local Moderator
  • AGS Baker
  • Mittens Vassal
  • Parking Goat- games that goats like!
    • I can help with translating
    •  
    • tzachs worked on a game that was nominated for an AGS Award!
Re: Porting game to MonoAGS
« Reply #93 on: 18 Nov 2018, 19:58 »
Ok, done in your branch, so you can choose if you want Follow(null) or StopFollowingAsync depending if you want to stop the current walk or not.

cat

  • Mittens Baronet
  • AGS Baker
  • Saving Christmas
    • cat worked on a game that was nominated for an AGS Award!
      cat worked on a game that won an AGS Award!
Re: Porting game to MonoAGS
« Reply #94 on: 18 Nov 2018, 20:03 »
Great! I stick to StopFollowingAsync, since I want to walk directly afterwards.