ID:2688372
 
(See the best response by Ter13.)
I currently have my game setup to have the view port scale based on window size. Looks great and everything, but people who have higher resolutions obviously have to display much more information and take a performance hit. Additionally, higher resolution players will have an advantage over lower resolution players.

Does Byond have any way to resolve this issue short of just making a static view port size of like 768x768? I'd realllyyy prefer to keep the scaling, but if possible make it so the view port only scales up to a certain point.

At 1920x1080, client.view gets set to 43x31. Is there a "golden ratio" in which we wouldn't see too much of a performance issue?
You need to increase zoom once the screen gets over a certain threshold.

Use LEFT,BOTTOM,TOP,RIGHT screen_loc anchors to adjust the UI such that it doesn't care what size the viewport is.

You generally wanna keep < 1200 tiles in the view, but you can go bigger the fewer players you have.
I reduced the size of the view port, and it's now 39x31 (which is 1,209 tiles in the view port).

Should I still be expecting performance issues with these dimensions if I had 50+ players on a server?

I've got the UI anchors done already, just trying to figure out how much I need to reduce the view port size so players don't have stuttering
Should I still be expecting performance issues with these dimensions if I had 50+ players on a server?

That really depends on the client's machine, the machine the server is hosted on, how busy your map is, what your appearance count is, how fast appearances are churning, how many objects are present in the viewports of online players, etc. Too many unknown variables for me to give you a meaningful answer.

Honestly, this is a topic that BYOND sort of teaches you to think about wrong.

Your viewport size should always be inferred from the screen size, not a fixed value.

I'm gonna prep an update to one of my snippet sundays that should help you with some of the new stuff that BYOND has done to help make viewport setup easier. Be back in a few hours.
Right on, I'm always happy to learn, and this has been a giant pain in the butt to attempt to get right
Best response
Alright, I'm back.

I threw together a quick example project for you. I'll document the code here.

//definitions:

//set these to your icon size for your project
#define TILE_WIDTH 32
#define TILE_HEIGHT 32

//set these to your desired limitations for your project. 1#INF means that your project has no limit on this axis.
//TILES is view_width * view_height, or the viewport area.

#define MAXIMUM_VIEW_TILES 1200
#define MAXIMUM_VIEW_WIDTH 1#INF
#define MAXIMUM_VIEW_HEIGHT 1#INF
#define MINIMUM_VIEW_WIDTH 1
#define MINIMUM_VIEW_HEIGHT 1

//These add extra tiles to all four sides of the viewport.
//These are useful for if you need to use effects like screen shake.
#define EXTRA_VIEW_WIDTH 0
#define EXTRA_VIEW_HEIGHT 0

//rounds up
#define ceil(x) (-(round(-x))


Next, let's go over some new client variables that we're adding to make handling dynamic view sizes a little more convenient:

client
var
map_width //width of the map in pixels
map_height //height of the map in pixels

view_width //width of the viewport in tiles
view_height //height of the viewport in tiles
view_zoom //stores the current zoom size of the default map.



With all of this set up, we're ready to add one verb and one proc to the client.

client
verb
//This proc is called automatically on client login and should be called by :map.on-resize in your dmf file.

onMapResize(map as text, default as num, width as num, height as num, zoom as num)
set instant = 1, hidden = 1

if(default)
//update the client map metrics
map_width = width
map_height = height
view_zoom = 0

//attempt to find the first zoom level that obeys our screen limitations
do
//increase zoom level by 1
++view_zoom

//divide the map width by the zoomed tile size to get the number of tiles that fit on the screen. We round up because empty space is bad.
view_width = ceil(map_width / (TILE_WIDTH * view_zoom))

//if the tile width is even, add one tile to make it odd so the map is centered properly
if(view_width%2==0)
++view_width

//now do the same thing for the height.
view_height = ceil(map_height / (TILE_HEIGHT * view_zoom))
if(view_height%2==0)
++view_height

while(view_width>MAXIMUM_VIEW_WIDTH || view_height> MAXIMUM_VIEW_HEIGHT || view_width*view_height>MAXIMUM_VIEW_TILES)

//now that we've found a view size that works, we add the extra width and height, and apply the minimum limits.
view_width = max(MINIMUM_VIEW_WIDTH,view_width)+EXTRA_VIEW_WIDTH*2
view_height = max(MINIMUM_VIEW_HEIGHT,view_height)+EXTRA_VIEW_HEIGHT*2

//And then update the client's view size
view = "[view_width]x[view_height]"

//and if the zoom level changed, we tell the client to update it
if(zoom!=view_zoom)
winset(src,map,"zoom=[view_zoom]")


Because BYOND doesn't call on-resize or on-show when the interface is first created, we need to get the size of the map when the player first logs in and update their viewport accordingly. It's a short, simple proc call.

client
proc
//call on client creation, or when changing the default map. It's set waitfor 0 so that the calling proc doesn't wait around on the winget() to finish before continuing.
updateMapSize()
set waitfor = 0
//get the parameters from the default map element that our resize function expects.
var/list/params = params2list(winget(src,":map","id;size.x;size.y;zoom"))

//now call the resize verb manually using this data.
onMapResize(params["id"],1,text2num(params["size.x"]),text2num(params["size.y"]),text2num(params["zoom"]))

New()
. = ..()
updateMapSize()



Alright, all of the code to make a configurable dynamic resizing viewport is done. We do need to do a little bit of work in your UI.

Open up your DMF file and edit your default map element.

1) Make sure your default map element has anchors if you want it to be resizable along with your window.

2) In the events tab, we're gonna edit the on-size event.




We're going to be using something called embedded wingets. These are something that Lummox implemented a little bit at a time for a few years until I requested that they be expanded into a fully-featured embedded interface querying system that allows us to minimize the number of times we need to talk back and forth between the client and server to do complex tasks.

Don't worry too hard about understanding them, just read up on embedded wingets in the reference. There's some cool stuff in there.

We're going to copy/paste a command string into the on-size-change event:

onMapResize [[id]] [[is-default]] [[width as escaped]] [[height as escaped]] [[zoom as escaped]]


What this does, is call the onMapResize verb when the event happens. It will send the name of the map element as text, whether it's the default element as a number (0 or 1), the width of the map in pixels as a number, and zoom as an integer.

If you are interested in seeing my little demo project, feel free:

Project included in library format for easy inclusion and in demo format if you just wanna poke around in the guts

Also, I really don't recommend allowing users to change the size of the main window at will. I really recommend putting your project in borderless full screen mode and building a menu for changing the window size to the desired resolution if they want to kick into windowed mode. But that's work, and we're all allergic to it here.
Awesome, that's a ton of good info. Thanks so much for taking the time to write that up and explain it to me