2 Questions dealing with screen size

Monkey Forums/Monkey Beginners/2 Questions dealing with screen size

odaniv(Posted 2014) [#1]
1. How can I have Z number of players or "units" along the x-axis equally spaced out with respect to each other and with equal spacing from the first and last players to the borders of the screen? How can the algorithm be as broad as possible? So that I can later change screen width, or number of players, or width of players, and it still work?

Currently, I am using the code below, but it only works for this specific case where:

Const SCREEN_WIDTH:Int = 640
Const SCREEN_HEIGHT:Int =480

Const PLAYER_WIDTH:Int = 64
Const PLAYER_HEIGHT:Int = 64

Const AMOUNT_PLAYER:Int = 6

For Local i: = 0 Until AMOUNT_PLAYER
DrawRect((PLAYER_WIDTH)*i + (PLAYER_WIDTH/2)*i+(PLAYER_WIDTH/2)+(PLAYER_WIDTH/4),SCREEN_HEIGHT-(SCREEN_HEIGHT/PLAYER_HEIGHT)- PLAYER_HEIGHT,PLAYER_WIDTH,PLAYER_HEIGHT)

End



Here, AMOUNT_PLAYER is number of players, or rectangles created. Ideally I would like to use images as players, not rectangles.

2. How can I change screen size? I've changed it in CONFIG.MONKEY but I see no change, there was another similar question asked on the forums a while back but I didn't really understand the answers. I am compiling to "desktop game".


thank you


StoneFaceEXE(Posted 2014) [#2]
2. Use this within your code
#GLFW_WINDOW_WIDTH=640
#GLFW_WINDOW_HEIGHT=480

I do believe it won't make much difference though, because 640x480 is default resolution of desktop target (as long as I remember)

I guess it will also be better to asign DeviceWidth() to DW and DeviceHeight() to DH instead of using contants, because those constants are just numbers you know while DeviceWidth() gives you actual X resolution on any target.

For other targets the method is different


Gerry Quinn(Posted 2014) [#3]
Something like this?



Output:
88 (player width)
22 (standard gap between them)

0 (left side of each player)
111
222
332
442
552

width can be set to DeviceWidth(), or to the width of whatever area of the screen you want to put your players.

Of course you can tweak this method in different ways depending on exactly what you want to control.


odaniv(Posted 2014) [#4]
Thanks for the help and suggestions!

This is great. I would however like to implement some space between the borders and the first and last players. Is there a simple way of doing this? I've been messing with it, but I am only able to accomplish for one side.


Gerry Quinn(Posted 2014) [#5]
Yes. If you're using code like what I posted above, first call DeviceWidth() to find out how wide the screen is. Then decide how big the border is (a fraction of screen width, a fixed value, or whatever).

Now in my code, set width to DeviceWidth() - 2 * border and do the calculations. Then add border to each calculated player position. Done!


odaniv(Posted 2014) [#6]
Sorry for delay in response. I've been messing with it, and this is what I have so far:

 
Const nPlayers:Int = 6												
Const gapParam:Float = 0.2											
Const borderParam:Float = .1 * screenWidth
Const width:Int = 	screenWidth - borderParam


Method Draw(img:Image)
		
				Local playerWidth:Int = Int( width / ( nPlayers * ( 1.0 + gapParam ) ) ) 
				Local gap:Int = ( width - nPlayers * playerWidth ) / ( nPlayers - 1 )
				Local extra:Int = width - playerWidth * nPlayers - gap * ( nPlayers - 1 ) + borderParam
				Local positions:Int[] = New Int[ nPlayers ]
				positions[ 0 ] = 0  + borderParam
					For Local i:Int = 1 Until nPlayers
						positions[ i ] = positions[ i - 1 ] + playerWidth + gap 
	
					If extra > 0 
					positions[ i ] += 1 
					extra -= 1
					End
					
					End

					For Local i:Int = 0 Until nPlayers
					DrawImage(img,positions[i],screenHeight-(screenHeight/playerHeight)- playerHeight,0,.1,.1,0)
					End

 



It works pretty well, but I've realized that having so many factors effect playerWidth actually makes things a little difficult, since it is hard to get the exact same border length on both the left and right side of the screen. I've realized that I'm probably making things difficult for myself, and that I might not understand something about the porting-to-target process.

My hope had been to make this an easy way to 1) configure the initial set up of units in order to flush out game mechanics, and 2) account for the varying sizes of phones and tablets out in the market already, and adjust the visuals accordingly. So, my question would be, how do others usually handle this problem?

Side but possibly related note: When I try to set a "float" or "int" constant = DeviceWidth(), I get an error stating that the Function DeviceWidth() cannot be statically evaluated.


PhillipK(Posted 2014) [#7]
The thing is, that "const" are constant values.
Its just a help for you to change some values in "one point". Constants just look like variables, but the compiler replace every "width" for example with the result of "screenWidth - borderParam" while compiling (edit: And screenWidth and borderParam must be consts, too - or plain values.) . That means, that actually a value is compiled in, not a "lookup".
DeviceWidth() is a function that returns a value on Runtime, the compiler cant know what the result would be - thats why you cant assign a function return to a constant.

Imagine this:
Const DIR_LEFT:int = 1
Const DIR_RIGHT:int = 2
Const DIR_UP:int = 3
Const DIR_DOWN:int = 4

*some other code*

Function Move:Void()
      Select player.GetFacing()
            Case DIR_LEFT
                   self.x -= 1
            Case DIR_RIGHT
                    self.x += 1
            Case DIR_UP
                    self.y -=1
             Case DIR_DOWN
                     self.y += 1
        end
end

A stupid example, but it may give you an idea, what consts are made for: They help you while coding. If you see just "Case 1, Case 2" etc here and look this code up in two month, you may be unable to know what case value 1 means. Using a const for "naming" a value is more understandable :)

Most of the time, you will need Global or local. Especially for resolution depending calculations.


odaniv(Posted 2014) [#8]
Silly of me to try to declare it a constant. Makes perfect sense what you explained.

I did however, set up the code like this:

 Global screenWidth:Int = DeviceWidth() 


I'm getting the error: "Memory Access Violation"


Danilo(Posted 2014) [#9]
You can't access DeviceWidth() before everything is initialized.
Set it in OnCreate():
Global screenWidth:Int

Method OnCreate:Int()
    screenWidth = DeviceWidth()



Gerry Quinn(Posted 2014) [#10]
I generally handle it with code of a similar kind to what I posted. If you're targeting Android in particular, you have to accept that the screen size can be just about anything. And you have to take into account your strategy:
- you might have fixed size graphics and spread them out by selecting an appropriate graphic size and then calculating the spacing between them
- you might have one set of graphics that gets scaled to fit the screen (easier, but you will still have to deal with aspect ratio)
- you might have a mixture of both strategies (e.g. include fixed size graphics, but fall back to scaling if screen size is outside the expected range)

The particular code is intended as an example of the sort of thing I would do to generate evenly sized spaces and borders etc. It's kind of the same principles as justifying text by dividing up spare space into the gaps between characters.

Generally I write a SetMetrics( rectangle ) method for every window class, and all the decisions get bundled in there. It sets sizes and positions for everything, and gets called if the window size changes or if the contents of the window change (e.g. a new game with a different number of players).


odaniv(Posted 2014) [#11]
Danilo, I've set it up as such and I'm still receiving the same error:

Class  MainBlah Extends App
		
		Global screenWidth:Int
		Global screenHeight:Int

	Method OnCreate()
	screenWidth = DeviceWidth()
	screenHeight = DeviceHeight()


Then I call screenWidth and screenHeight in a different file

Gerry, thanks for the input, I want to make sure I understand. With the first strategy, or dash, are you saying that the many-sized devices would each play the game with the same, and what I'm assuming to be a small, screen size?

Could you explain as if to a five year old that last paragraph again? Specifically, what is meant as "window class"


Thanks again


Raph(Posted 2014) [#12]
You have a scope issue, then. You made screenWidth and screenHeight Global to just MainBlah. If you want another file to be aware of them, you can put them outside everything else, or use a fully qualified name (since they are a member of MainBlah).


Pseudocode:



Gerry Quinn(Posted 2014) [#13]
Hi Odaniv.

With the first strategy I meant that you have one or more sets of fixed size graphics, and you calculate how they are spaced out depending on screen size. Obviously if there will be a wide range of screen sizes, you will have to include several sets of graphics. But if you want to avoid scaling (maybe scaling doesn't suit the sort of graphics you are using) this is one way to do it.

For example, say you have some nice buttons that are 60 x 60 pixels and you want a row of 5 of them. With appropriate gaps and borders, that would fill about 420 pixels of screen real estate, but you could reduce or increase the gaps, or otherwise change the layout, to fit into the space you have, so long as that is not *too* far from the right size. That might give nicer results than blurred 55 x 55 or 67 x 67 buttons, say.

It's a technique best used when you're a better programmer than an artist, I suspect, so your mileage may vary.

As for the last paragraph, I just meant a class representing a window or menu or even a button, instances of which get typically created by a parent window, take mouse input and draw on screen.