webfx-project / webfx-cli

The Command Line Interface for WebFX. The terminal tool for developing WebFX applications.
https://webfx.dev
Apache License 2.0
10 stars 3 forks source link

I don't quite get how this works #8

Closed armin-reichert closed 8 months ago

armin-reichert commented 1 year ago

Say I want to use webfx to build a GWT executable (and maybe others too) for an existing JavaFX application (in my case: https://github.com/armin-reichert/pacman-javafx)

Do I have to bring my Maven artifacts to some central Maven repository first to get this working, or can webfx also resolve dependencies against my local Maven repository?

armin-reichert commented 1 year ago
  1. You can now select the game version via URL query parameter game: game=pacman or game=mspacman. Of course one could also provide different URLs for these entry points.
  2. The help button is now inside the frame around the game area and not so distracting anymore.

I am satisfied so far, but maybe you want to test and evaluate too before publishing. What I am not so happy about is the blurred look of the canvas content which is caused by the upscaling. This is more visible in the browser than in the desktop window.

And now I have to rest again ;-)

salmonb commented 1 year ago

Wouah, good progress, and great job! 🥳 I will test it tonight 👍

Regarding your concern with the canvas, I think it's possible to get sharper graphics by replacing the scaling with an actual resize of the canvas (but always keep same width/height ratio). I guess this would require some adaptation of your code to manage an arbitrary canvas size height (you will need to scale your images inside the canvas). I don't know how much work that would represent, depending on how you implemented it...

Do you think it's doable, or is it too much work?

armin-reichert commented 1 year ago

I would like to let the scaling (issue) for now as is. (Will have a look at it in my main development branch) From my side, you can publish the stuff now (and spread the good news :-). You might provide two separate URLs / demo page entries, because historically, these are different games. What do you think?

salmonb commented 1 year ago

Great news! And nice idea the iPad look! 👍

I did a bit of testing and there is one little issue with my keyboard: I need to press my A key to quit (instead of my Q key) - I have an AZERTY French keyboard. Some people may have other issues with other keyboard layouts. It's a bit a hassle these keyboards...

I looked at the KeyEvent and it looks like the only property that returns the logical key (and not the physical key) is getText()(it returns 'a' and not 'q' when I press my A key). Do you think you can consider this property instead of getCode() when it's about letters (but not when it's about arrows as getText() returns a String...)? Or do we leave it as it is?

salmonb commented 1 year ago

Actually this little trick might solve the problem:

Replacing:

        KeyCode code = e.getCode();

with

                 // Trying first to convert the logical key into a key code to consider the keyboard layout
        KeyCode code = KeyCode.getKeyCode(e.getText().toUpperCase());
                 // If not found (probably not a letter), we take the physical key
        if (code == null)
            code = e.getCode();
armin-reichert commented 1 year ago

Concerning the keyboard, I now understand what you mean: The key event contains key code "KeyCode.Q" if you press "a" on your french keyboard, right? So I will have to change the code to handle that situation better. Is this the only one of the used key combinations that has this problem?

(I am already working on a fix)

salmonb commented 1 year ago

Yes you understood the problem. Yes so far this is only the key combination that doesn't work for me, but like I said, we don't know about other keyboard layouts... But I think my trick (see above as our posts crossed) should fix all issues for all keyboard layouts 🤞

armin-reichert commented 1 year ago

I pushed a fix, could you please test?

salmonb commented 1 year ago

Yes it works! 🥳

I was thinking about the 2 game variants: would you prefer to have 1 subdomain for each? https://pacman.webfx.dev https://mspacman.webfx.dev

I can easily create the second one and update the GitHub workflow to publish the game in these 2 subdomains at the same time. From your side, you would need to replace your WindowLocation.getQueryString() test with WindowLocation.getHostname() which will return either pacman.webfx.dev or mspacman.webfx.dev in the browser (but null for the desktop).

Let me know if you would like this change.

armin-reichert commented 1 year ago

Yes. I would prefer two subdomains (with exactly these names) as entry points without the URL parameter. Maybe it's easiest if you make the needed change in the code too (class GameApp:161) where the initial game variant is set.

salmonb commented 1 year ago

Ok, I will do that! 👍

In the meantime, I noticed a minor issue (it's really about finishing touches here): if I'm a new player and hover the ?, I'm getting the help which is great but maybe I don't have enough time to read it all before it fades, so I would like to make it appear again. My instinct is to click on the ? (as my mouse is already hovering it), but this doesn't work. I have to move my mouse away and return to the ?. Could you simply react to the click too?

armin-reichert commented 1 year ago

Done. The original cause for using an image view with mouse event handlers instead of a Button was that a graphic button is broken in GWT, I should have "opened a ticket" for this.

salmonb commented 1 year ago

That was quick! Yes it's working now 👍 I will have a look later at the graphic button.

I will continue after lunch for the subdomains... 🍽️

Was wondering for new players: is there a way to know the cheat keys? 😄

armin-reichert commented 1 year ago

That's the essence of cheat keys! You get this information only on dubious sites in the darknet (like this one: https://github.com/webfx-demos/webfx-demo-pacman/tree/webfx) :-)

Oh, what's also missing are the fav icons.

salmonb commented 1 year ago

Back from lunch...

Good idea the fav icons. You can put them in the resources/public folder (either in pacman-ui-fx or pacman-ui-fx-gwtmodule).

For the code changes regarding the domains, should I create a separate branch or push them directly in the webfx branch?

salmonb commented 1 year ago

I pushed the changes in the webfx-domains branch. You can merge it to webfx whenever you want.

armin-reichert commented 1 year ago

Thanks. (I was a couple of hours out of house, short trip to Luxembourg).

I merged your change and added the fav icons but my first try adding them int the GTW module's public resource folder did not work. I added the icons now to both folders, let's see if this works).

The two subdomains are working fine.

salmonb commented 1 year ago

Great for the subdomains! 😃

I think the fav icons must be named favicon.ico by default. Otherwise, the favicon path must be set in index.html.

But I realise now that you want a different icon for each domain... So this solution is too simple. Maybe the best solution would be that WebFX supports Stage.getIcons() and map that to html automatically. I will think about it...

Otherwise I noticed that the cheat keys don't work anymore! Except immunity which is activated by Alt-Shift-N instead of Alt-Shit-I on my keyboard! Is it a bug introduced by our last keyCode trick?

armin-reichert commented 1 year ago

Yes, you are right about the favicons. I think we could just use the same favicon for both domains, so renaming one of them to "facicon.ico" should be sufficient.

The cheat shortcuts work fine here (Windows 10, Goggle Chrome and Brave browser). Alt-Shit-I toggles immunity, Alt-Shift-A toggles autopilot etc.

May be a Mac keyboard (does it have an "Alt" key or is it this Mac "bathtub" key?) generates different key codes in JavaFX?

salmonb commented 1 year ago

Ok, lets keep it simple for now with the favicons 👍

I think I found the issue with the cheat shortcuts. It's a NPE with letterCode, because KeyCode.getKeyCode(letter) may return null, especially when combined with modifier keys (maybe this doesn't happen on Windows, but it does on Mac). So can you add letterCode != null && !letterCode.equals(currentEvent.getCode()) in your condition?

armin-reichert commented 1 year ago

Fix submitted.

salmonb commented 1 year ago

Fix working 👍

For the favicon, I was wrong when assuming the browser will try favicon.ico by default (it was the case in the past, but apparently the browsers don't do that anymore). So it must be explicitly present in the html file. Since index.html is generated by WebFX, you need to add this section in your webfx.xml (either in pacman-ui-fx or pacman-ui-fx-gwt module):


    <html>
        <head>
            <link rel="icon" type="image/ico" href="pacman.ico"/>
        </head>
    </html>

Change the href value with the icon you want, and then run webfx update. This should work already on your local machine.

armin-reichert commented 1 year ago

Thanks. Already after changing the icon name to "favicon.ico", the icon (black ghost) appeared in the browser tab of each game. I wanted to make it transparent (it looks transparent in my IrfanView and I stored the transparent color too) but in my browser it doesn't. But I think, the "customer" can live with that.

I will leave my desk now (and move to the sofa 4 meters away) because I have to take care of the "Montagny 1er cru" I bought this afternoon in Luxembourg.

salmonb commented 1 year ago

Right, I tried with Safari & Firefox and it works. Not in Chrome (my default browser), but maybe it's just a caching issue (will check again tomorrow).

armin-reichert commented 1 year ago

See comment above.

salmonb commented 1 year ago

hi Armin,

I didn't have the time to make a public announcement, but anyway Friday is not the best day for this, so I will do it beginning of next week if you're happy with that.

Strange but my Chrome was still not loading the favicon today. After different tries (you will see my commits) changing the format to png finally solved the issue (the ico format was working on my local machine but not on the live demo for any reason...). Then maybe you can work on that png file to fix the transparency issue you were talking about?

A last thing (because I thought otherwise you will start getting bored 😉) I was wondering if you could make it work on devices with no keyboard. I can't play it on my iPad for example. If you make it playable with a mouse, it will work also on mobiles because JavaFX automatically transforms not consumed touch events into mouse events. So basically it's about starting the game with just a mouse click, and then dragging pacman. You can see how they did that (the drag) in SpaceFX (here exactly). The principle is to put a JavaFX node (the touch area) over the character you want to control in the canvas and then react to the drag events. What do you think?

armin-reichert commented 1 year ago

Hello Bruno,

yes, I am completely fine with that. I just pushed another fav icon (no license restrictions, see https://thenounproject.com/icon/ghost-3109865/) and it is also transparent (local test was ok).

The non-keyboard steering is certainly a useful feature, but I have to first think about it: Pac-Man steering is (in my implementation) not just pressing the right key at the exact point where Pac-Man can change his direction. You can already preselect a direction before Pac-Man reaches the intersection and as soon as he can make the turn it will be done.

If you do that with a drag-gesture, you will at least need some visual indication of the preselected move direction. If I press a key I have already a clear feedback of my input but when just wiping, how can I be sure what has been recognized? But I will have a look at the SpaceFX game about how this could be done.

salmonb commented 1 year ago

Maybe you can start with a simple canvas.setOnMouseDragged(e -> {...}) and see what you can do? Maybe you can just calculate the delta between the mouse and pacman, and transform that into an equivalent arrow KeyEvent and pass it to your existing code? Just some ideas... Anyway, good luck with that 🍀

armin-reichert commented 1 year ago

What would normally be the replacement for a simple key press on a keyboard-less device like an iPad, buttons. (context) menus, gestures...?

I am sorry to ask such stupid questions but I have no idea how interaction with an iPad works in practice, even less inside a game.

salmonb commented 1 year ago

Reply: touch events, which are generated when touching the device with fingers, or with a pencil. But like I said, no need to use the JavaFX touch API, just make it work with the mouse, and it will work on touch devices as well. For example SpaceFX is playable with the mouse only, and therefore playable on touch devices.

armin-reichert commented 1 year ago

I added the following functionality (it was almost trivial):

I tested it with the mouse in the browser and in the desktop window and it looks ok to me. Could you please check if it works on your iPad too?

salmonb commented 1 year ago

I'm glad that it was not that difficult for you, and yes, I just played my first game on the iPad with a pencil!!! 👏

Here is my feedback of this first play on iPad:

I didn't make a big score as it was not the most intuitive experience for me. I instinctively tried to drag pacman and that didn't respond as I would expect. I was touching the screen with my pencil without releasing it, and that didn't work. Then I understood it was reacting to swipe events and not to drag events (more "work" for the player to make these gestures compared to just dragging). So I could play again, but then I was confused when it stopped working in the upper part. Then I read your instructions and understood... But I think most people will be a bit confused with that as well.

What's the idea of limiting the touch area to the lower part only? Is it to simulate the joystick in the original game machine? In this case maybe displaying a virtual joystick somewhere would clarify that, but it's much more work for you than just removing this limit and covering the whole canvas.

Can you also try to react to drag events, like in SpaceFX (you can see that it's not necessary to release the mouse to drag the spaceship)? I think this would lead to a much more intuitive experience. What do you think?

armin-reichert commented 1 year ago

Good morning Bruno,

as I had no touch screen device to test I used the mouse to simulate a "wipe"(?) gesture.

Using the mouse, to get a defined motion like "Move UP", I need

So I listen to a mouse press (gesture start), check if any drag event follows (not just a mouse click), and then listen to mouse release (end of gesture). Then I check the position change the mouse has made between gesture start and gesture end, and based on that decide which move direction this represents. That worked very well with the mouse, so I thought (as you mentioned) this would also translate well into touch events.

First, I only listened to drag events, and with a single gesture I got a list of these but I did not see how this list of drag events could be used to identify the gesture start/end and the user's intention.

My thought to restrict the touch pad to the lower part of the maze was that the user would not cover his sight with his hand, so wiping on the bottom should help with that.

But unfortunately this seems not to work so well with a real touchscreen :-(

Regards Armin


Von: Bruno Salmon @.*** Gesendet: Sonntag, 21. Mai 2023 10:34 An: webfx-project/webfx-cli Cc: Armin Reichert; Author Betreff: Re: [webfx-project/webfx-cli] I don't quite get how this works (Issue #8)

I'm glad that it was not that difficult for you, and yes, I just played my first game on the iPad with a pencil!!! 👏

Here is my feedback of this first play on iPad:

I didn't make a big score as it was not the most intuitive experience for me. I instinctively tried to drag pacman and that didn't respond as I would expect. I was touching the screen with my pencil without releasing it, and that didn't work. Then I understood it was reacting to swipe events and not to drag events (more "work" for the player to make these gestures compared to just dragging). So I could play again, but then I was confused when it stopped working in the upper part. Then I read your instructions and understood... But I think most people will be a bit confused with that as well.

What's the idea of limiting the touch area to the lower part only? Is it to simulate the joystick in the original game machine? In this case maybe displaying a virtual joystick somewhere would clarify that, but it's much more work for you than just removing this limit and covering the whole canvas.

Can you also try to react to drag events, like in SpaceFX (you can see that it's not necessary to release the mouse to drag the spaceship)? I think this would lead to a much more intuitive experience. What do you think?

— Reply to this email directly, view https://github.com/webfx-project/webfx-cli/issues/8#issuecomment-1556118782 it on GitHub, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABYNHY7QHLQ5YDCPKQB6EJLXHHHQPANCNFSM6AAAAAAXRU7ETQ . You are receiving this because you authored the thread. https://github.com/notifications/beacon/ABYNHY4WYX6PEYSBDYJCKBLXHHHQPA5CNFSM6AAAAAAXRU7ETSWGG33NNVSW45C7OR4XAZNMJFZXG5LFINXW23LFNZ2KUY3PNVWWK3TUL5UWJTS4YB6P4.gif Message ID: @.***>

salmonb commented 1 year ago

I see your concern with the hand, but it's actually ok, the finger doesn't cover much the rest of the screen, and the palm is far enough from pacman. And with a pencil, it's even better.

You can actually detect the gestures in the 4 directions without the need to release the mouse/finger/pencil, just by comparing the relative position of the mouse with pacman. If I want pacman to go up, I just move my pencil above pacman. Same with other directions. Exactly like SpaceFX.

armin-reichert commented 1 year ago

Maybe I misunderstand something, but I am not convinced that Pac-Man should be steered by using the Pac-Man sprite or any point on the screen as the interaction area. I would rather use some dedicated area on the screen to similate a touchpad or mabe even better, the joystick from the original game. It would not be necessary to make it look like a joystick but rather to get the 5 joysticks states (neutral, up, down, left, right).

salmonb commented 1 year ago

Yes it's 2 different options. But like I said, the joystick option is more work for you - and a bit less intuitive in my opinion. You don't like the SpaceFX game experience (just keep your mouse pressed to steer the spaceship)?

armin-reichert commented 1 year ago

The steering of the startship is certainly adequate in that game, but I have my doubts if this makes sense for Pac-Man. Pac-Man moves automatically without user interaction and only if there is a choice for changing direction (in my version in contrast to the original, already before reaching that point), only then user-interaction is necessary. That's a real difference to the slowly moving, almost static starship.

salmonb commented 1 year ago

I agree the games are different as pcaman can't just follow the mouse like the starship, due to the walls, and he can also continue walking if I release the mouse as opposed to SpaceFX.

That said I still think you can have an intuitive drag-based steering interaction even with these additonnal constraints. In the same way that I can press the up arrow key at any time to communicate my intention to move pacman up - even if not yet possible at the moment - I can communicate this same intention with the mouse by dragging it above pacman. It will move pacman up only once possible of course. I can eventually change my mind and communicate another direction in the meantime. In summary I don't see why it's not possible to communicate our intention with the mouse like we do with the keyboard. You could even internally transform these drag events into keyboard events for your game engine.

It's just my opinion, and if you prefer the joystick option, that's fine of course.

armin-reichert commented 1 year ago

Could you please create a new branch where I can try out different approaches?

The problem I see with your proposal is that to e.g. move UP, you have to drag the mouse above Pac-Man's current position (correct?), so the interaction area becomes the complete scene and you always have to move around with your finger or pencil. I cannot judge how this feels in reality but I think it might not the best solution.

salmonb commented 1 year ago

What you describe as non-intuitive (following pacman with your mouse/finger/pencil) is exactly what I describe as the most intuitive! Different opinions... 😆

Ok, I created a new branch called webfx-drag-steering 👍

armin-reichert commented 1 year ago

I pushed a change (directly into the webfx branch) that now uses mouse drag+mouse release to steer Pac-Man. The gesture is recognized all over the game scene, not just in the lower part. Could you please check if this works on an iPad? With the mouse, it works well, in the browser and in a desktop window.

I also found an interesting blog post (from 2009): https://www.cxpartners.co.uk/our-thinking/touch_screen_gaming

salmonb commented 1 year ago

Yes, I confirm it's much better over the whole screen 👍

But you still need to constantly release the mouse (or remove your finger or pencil) each time you want to change directions. It's quite annoying. A much better user experience would happen if you keep tracking the direction in the setOnMouseDragged() method, so we can steer Pac-Man for a long time all along a single press. The direction needs to be determined by comparing the current mouse position with the Pac-Man position (and not the initial dragging point). setOnMouseDragged() is called many times (basically each time you move the mouse, finger or pencil), but you can call your direction consumer only when you detect a direction change.

I would be happy to help with the coding, but I have no idea how to get the Pac-Man position...

armin-reichert commented 1 year ago

Hi Bruno,

thanks for testing.

I don't understand why it is annoying to release the mouse (or lift the finger off the touchscreen) at the end of a gesture. Isn't this totally normal for a "swipe" gesture? Why is it better to have the finger on the screen permanently? When using the mouse, it is certainly more comfortable to release the mouse button when a gesture ends than permanently pressing the button.

But I am only an occasional user of tablets and have never played any game on a tablet. So I trust your experience. Feel free to add your code , I am perfectly ok with that.

You can get the Pac-Man position as follows (when inside a GameScene):

context.game().level().ifPresent(level -> {
  var pos = level.pac().position();

context is a data structure that stores scene-related data: a reference to the game controller and its state, the current game model, the current level object and the references to Pac-Man and the ghosts etc.

The Pac-Man position is the left-upper corner of Pac-Man's "collision box" which is one square tile large (8x8 pixel). The sprite however has a size of 16 pixels. The position is in model-coordinates (unscaled).

salmonb commented 1 year ago

Thanks for sharing the code that gets the Pac-Man position 👍

I made the change and pushed it to the webfx-drag-steering branch. To me, it's a much more enjoyable game experience, on the iPad for sure, and I think also on the desktop with the mouse. I let you try and please let me know what you think.

If you're happy with it, I let you finish the code (comment, cosmetics, etc...) as I did it quickly, and then you can push it in the webfx branch.

salmonb commented 1 year ago

hi Armin,

Just to let you know, I made a final improvement and pushed it to that webfx-drag-steering branch. The improvement is to react also to the intermediate directions (ex: you can lead Pac-Man to right-up direction with the mouse). I'm quite satisfied now with this drag steering. What do you think about it?

armin-reichert commented 1 year ago

I merged your changes, looks fine to me. Another thing: I wanted to push a workaround for the missing TinyLog logging library, but obviosuly I don't have write permission to webfx-demo-pacman-core. The change looks like this (Logger.java):

package org.tinylog;

public class Logger {

    private static void println(String message, Object... args) {
        message = message.replaceAll("\\{[^}]*\\}", "__"); // two underscores
        for (int i = 0; i < args.length; ++i) {
            message = message.replaceFirst("__", String.valueOf(args[i]));
        }
        var dateFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss SSS");
        var prefix = LocalDateTime.now().format(dateFormat) + ": ";
        System.out.println(prefix + message);
    }

    public static void trace(String message, Object... parameters) {
        println(message, parameters); }

    public static void info(String message, Object... parameters) {
        println(message, parameters);
    }

    public static void error(String message, Object... parameters) {
        println(message, parameters);
    }
}

As the Logger is used by some tests that are run during the build, I can see that the code does something useful. Could you add it if it's ok for you?

salmonb commented 1 year ago

Great, it works very well on my iPad, thank you!

I gave you write access to webfx-demo-pacman-core, so feel free to do any change you like.

FYI System.out.println() doesn't print in the browser console. If you want logs in the browser as well, you can use dev.webfx.platform.console.Console.log() instead.

salmonb commented 1 year ago

hi Armin, do you think the game is now ready to go?

armin-reichert commented 1 year ago

(Strange, I answered by mail (Thunderbird) but the reply is not appearing here.)

Yes, I am fine with the current state. If the "iPad frame" looks too silly on a real iPad oder other tablet, we can remove it later, if the application is running on a mobile.

salmonb commented 1 year ago

FYI here is a screenshot from my iPad mini, so it looks ok, no?

IMG_838EE4D1CF41-1

How should we do the public announcement? Do you first tweet about it and we retweet your tweet? (assuming you have a twitter account) Or should we do the whole tweet? What's your preference?