ArnoldSmith86 / virtualtabletop

a virtual surface in the browser on which you can play board, dice and card games
https://virtualtabletop.io
GNU General Public License v3.0
166 stars 31 forks source link

Feature request:Allow scaling and scrolling out of sync with other players #878

Open jippless3024 opened 2 years ago

jippless3024 commented 2 years ago

I want to use the holder as a wide board. Is it possible to prevent other players from syncing if the board is scaled or scrolled at that point?

Is it possible to have a holder that is displayed in initial coordinates each time I join and does not synchronize movement with other players? (The coordinates of the children in the holder are synchronized)

If that can be achieved, it will function not only as a wide board but also as a controller position adjustment for each player.

I want to realize a wide board like the one below without synchronizing https://virtualtabletop.io/xtvl

96LawDawg commented 2 years ago

I don’t know anything about the platform code, but what I do know suggests what you are asking for (disabling synch) is not easily possible.

But you might be able to accomplish this another way. Each player has there own board visible only to them through a seat widget. Can be scaled however you want. Use multiple copies of the cards or game pieces or whatever with ‘inheritFrom’. The only thing different on each piece would be the scale. So they would appear in the same relative place with the same face or whatever on everyone’s board. Some people would just see a bigger or smaller slice of the board.

Nothing like that has been done so for but I think it might be possible.

robartsd commented 2 years ago

I'd love for there to be a "table" object that is defined by the game designer with each client able to set their own view (scale, translation, rotation) of the table. There could also be a "viewport" object that a game designer could assign widgets to to cause them to be placed in a fixed location on screen regardless of the table (I picture this used for a hand).

I picture the "table" being a rectangle or circle (defaulting to the current 1600x1000). A game designer creating a card game might choose a circular table with each seat having a different default table rotation to make a game where all players sit around a table. Other games might have their tables defined to fit a particular board. The game designer should also be able to indicate the playing surface is unlimited (the size defined would still control the initial view of the table when someone joins the room or the game is loaded).

I'd prefer that the "viewport" object conform to the window of the user rather than use a fixed aspect ratio, but that would make some layouts difficult to achieve.

ArnoldSmith86 commented 2 years ago

BTW: you might want to consider joining our Discord. 😄

96LawDawg commented 2 years ago

@jippless3024 check out https://virtualtabletop.io/LawDawg. 2 seats, each with their own view of the same thing: a 'hand' with a few objects in it. Each player can independently scale the hand using the buttons in the upper right. Things that move on player 1's board move a corresponding amount on player 2's board (which is currently set at scale 0.5). The side of the checker and the value of the spinner are all controlled through 'inheritFrom.' The hand also is movable for 'scrolling' in higher scales.

Right now the only limitation I see is when moving objects on a board that isn't set to scale 1. That breaks it. I think this can be overcome with an xChangeRoutine that looks to see what the scale is and sets a new x multiplied by a proportionate amount to that scale. Do the same for y. That routine also has to check if the x or y is moving in a positive or negative direction. I have some code sort of like that somewhere, just not handy right now.

Does this get you near what you need?

96LawDawg commented 2 years ago

I'd love for there to be a "table" object that is defined by the game designer with each client able to set their own view (scale, translation, rotation) of the table. There could also be a "viewport" object that a game designer could assign widgets to to cause them to be placed in a fixed location on screen regardless of the table (I picture this used for a hand).

This sounds like the solution @bjalder26 and I have been looking for. We've tried to make it happen through JSON, but it is hard, if not impossible.

robartsd commented 2 years ago

I'd love for there to be a "table" object that is defined by the game designer with each client able to set their own view (scale, translation, rotation) of the table. There could also be a "viewport" object that a game designer could assign widgets to to cause them to be placed in a fixed location on screen regardless of the table (I picture this used for a hand).

This sounds like the solution @bjalder26 and I have been looking for. We've tried to make it happen through JSON, but it is hard, if not impossible.

It would require quite an overhaul of the mouse handling code, plus a bit of a change to the state model (including game designer access to properties of the state's _meta object to store table properties). Some of the mouse handling needed would likely also help with #877. You've made great hacks at this using game routines, but a more general solution would be very beneficial.

bjalder26 commented 2 years ago

I'd love for there to be a "table" object that is defined by the game designer with each client able to set their own view (scale, translation, rotation) of the table. There could also be a "viewport" object that a game designer could assign widgets to to cause them to be placed in a fixed location on screen regardless of the table (I picture this used for a hand).

This sounds like the solution @bjalder26 and I have been looking for. We've tried to make it happen through JSON, but it is hard, if not impossible.

It would be nice if there was some way to make the "room" infinitely large, but make our view essentially a window to view the room. Then we could make functions to shift the x, y and rotation of the "window". I have no idea how to do that or if that is possible though.

robartsd commented 2 years ago

It would be nice if there was some way to make the "room" infinitely large, but make our view essentially a window to view the room. Then we could make functions to shift the x, y and rotation of the "window". I have no idea how to do that or if that is possible though.

That's basically what I meant here:

The game designer should also be able to indicate the playing surface is unlimited (the size defined would still control the initial view of the table when someone joins the room or the game is loaded).

I'd leave it up to the game designer to turn on this feature, otherwise restrict the table to the specified area.

RaphaelAlvez commented 2 years ago

I got so confused at first. I confused table as in table top with a table of data.

New widgets require more discussion then most new features.

Here are some questions frequently asked:

Sometimes we don't actually need a new widget and can just add general features that solve the game designing problems.

jippless3024 commented 2 years ago

@96LawDawg It was a very interesting and informative demo. thank you very much. I think the concern is that it's easy to get out of sync, not bidirectional.Also, adding widgets seems difficult. It may be possible to do that with the current json editor, but I'm worried that it will manage a lot of objects and a huge amount of computation.

"table" object

I think it's very nice to add a new "table" object. Initially, I was requesting such an object. However, I think there are many changes to implement.

By comparison, it seems easier to add an option to ignore the synchronization of certain properties to the widget. When I change the widget, it seems that one client does not sends a specific value or another client does not receive a specific value. It's like a widget set by the owner. (Even if the idea is simple, it can be difficult to implement.) (However, if you want to use it as a wide board, you need to solve # 877) (Also, this idea seems difficult to support rotation.)

@ArnoldSmith86 I would like to join Discord later. I'm sorry if I had to consult there before creating the issue.

96LawDawg commented 2 years ago

I fixed the synch issue in the demo room. It will be difficult to manage lots of widgets through duplication. The only problem left right now I think is moving scaled child widgets. There is a relationship between the center of the object that is the parent and the scale that I haven't cracked yet. I was messing with that using the checker in the demo room, but it isn't working yet. The pawn and the spinner still work and you can see how I solved the synch issue in their JSON if you want.

As for Discord, there is no requirement. It is just easier to be more interactive there and sometimes problems like this can be addressed in near real-time, depending on the time of day and who is on. That doesn't mean solved if JavaScript coding is required. But if there is a solution or workaround, the #help channel is very helpful and quick.

jippless3024 commented 2 years ago

@96LawDawg I created a coordinate conversion routine in #877. It may be useful to merge it with the demo

robartsd commented 2 years ago

I got so confused at first. I confused table as in table top with a table of data.

We could call it a 'tabletop' object.

New widgets require more discussion then most new features.

I'm not sure that the 'tabletop' and 'veiwport' objects would be widgets. By default all widgets without a parent would be DOM children of the tabletop object. I think we'd want to add a new property to put widgets on the 'viewport'. As far as widgets go the 'tabletop' and 'viewport' would not be parent widgets.

Here are some questions frequently asked:

  • how does it translate to a IRL element? IRL the tabletop is the playing surface, the viewport is the user's screen.

  • why is it needed for game design? Some games need more space than can comfortably be done within a fixed screen size.

    • which functions, properties and features need to be added? We'd need to provide UI for pan, zoom, and rotate the view of the 'tabletop'. We'd need to map pointer input to the appropriate coordinates on the 'tabletop'. Move targets will have to consider both holders on the 'tabletop' and holders on the 'viewport'. We'd need to provide a property to assign widgets to the 'viewport'. We'd need to provide a way to set the 'tabletop' properties in the game state without it being a widget.

    • which other features can be added to improve the initial concept and make it flexible? Better mapping of coordinates between different reference frames is needed.

96LawDawg commented 2 years ago

@96LawDawg I created a coordinate conversion routine in #877. It may be useful to merge it with the demo

So I made progress, but math and programming (what the hell am I doing on this platform??!?) are not my strong suits. I have the green pawn using your code more or less. Big difference: to make the demo work, the child widgets must have fixedParent set to true. So enterRoutine will not work. So I created a "coordCalc" widget that is called. I think the difference is because in my room, the child widget is always remaining scaled. And in your room it is returned to scale 1 while it is moving. Can you figure out the solution in my room?

96LawDawg commented 2 years ago

@jippless3024, I got it to work, sort of. I figured out the relationship was logarithmic, so I added just one new line to calculate the log of the scale in the called routine. Voila! But it only works for scale 0.5. [shrugs]

96LawDawg commented 2 years ago

@jippless3024 Now it is fully working. Thanks to @bjalder26 for figuring out it needed a square root and not a log. You say tomato, I say tomato.

I have also optimized it so that duplication and cloning will be mostly easy. First, create all the widgets you want in "hand." For each widget, you need to add a property: "widgetMaster": "xyz" where xyz is the id of that widget. Then duplicate the widgets you created and assign their parents to "hand1." Then you have to copy and paste the changeRoutines for each of the new widgets in "hand1". You should only need a abcChangeRoutine for anything that updates like x, y, or activeFace. I think most widget types will work. A canvas may be a problem and might not work. Cards will be workable, but will be a little bit of a pain. I haven't experimented with either of those yet. I don't know where you are going with this.

That is the hardest part of the duplication and a bit of it is manual. When you want to duplicate an entire new seat for a player, you just duplicate "hand1" and change 3 properties in the new widget: linkedToSeat, onlyVisibleForSeat, and scale. Scale just has to be changed to something like 1 manually because that breaks the link with the widget it was cloned from. You should be able to do that all programatically.

I also did test trying to move the same widget at the same time on 2 different devices. I was worried that might break the link, but it didn't.

So can you build your game now? And will it be suitable for the public library? I can help.

jippless3024 commented 2 years ago

Is it still too much work to add properties like unsyncCoordinate:true and unsyncRotation:true and unsyncScale:true to the widget? Since the child widget seems to get its coordinates from the difference from the parent widget, I thought it would be useful if each player could freely move the widget with unsync set. If you have that, you can move the UI such as button placement for each player.

ArnoldSmith86 commented 2 years ago

Personally I don't like that but it shouldn't be too hard to add.

Keep in mind though that nothing one player does could ever affect the position of the widget for another play. So no button that arranges the widget for each player (except each player presses it).

ArnoldSmith86 commented 2 years ago

Maybe I could get behind something like a playerOverride property:

  "playerOverride": {
    "Arnold": {
      "x": 20,
      "y": 20
    }
  }

That would still be synced as usual.

jippless3024 commented 2 years ago

For example, I would like to synchronize only the positions of the pieces on the board, like in roll20, and change only the perspective of the board. This is why we are requesting the unsync property. For now, I don't think it is necessary to save the coordinates individually. Whenever I load the screen, it will be displayed at the original x and y coordinates that I have set.

So no button that arranges the widget for each player (except each player presses it).

I see that changing coordinates by drag and drop is treated the same as changing coordinates by set or movexy. However, this seems to be no problem if you set unsync:false, xy change, and unsync:true in the button.