Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Scaling, supporting multiple screen resolutions

in Questions Posts: 116

Hello,
I've been attempting to make my project work not only on my iPad but all currently supported iOS-devices. I'm struggling to find a good way to run it on screen sizes different to my iPad's.
I wanted to scale everything but the UI using scale((WIDTHHEIGHT)/(originalWidthoriginalHeight)) with originalWidth/originalHeight being the WIDTH and HEIGHT values of my iPad. However, when I tried this, it rendered everything to the bottom-left corner. How can I fix this or is there a more elegant method to support other aspect ratios/screen sizes?
Thanks in advance :)

Comments

  • Posts: 1,767

    @Leon - one of the ways I do this is by using aspect. Determine aspect as aspect = WIDTH/HEIGHT and then scale by reading in the device screen width and screen height.

    However you must remember the orientation as that will significantly change what you would like to produce. So you have to build into your project the ability to change your output according to orientation. Then you use aspect to scale if you transfer from one device to another.

  • Posts: 116

    I have tried that. The issue is, that the image isn't centered anymore.
    For instance, when I put scale(0.5) before all the drawing happens and run the project, it shows the a shrunken version of the scene in the bottom left corner rather than in the center.

  • Posts: 1,767

    @Leon - could you let us have a little example code and tel us what devices and resolutions you are transferring code to and from?

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon Here's something I wrote back in March of 2017 for different screen sizes. I start with the iPad Pro and go down to the iPad watch. Tap the screen to switch sizes.

    displayMode(FULLSCREEN)
    
    function setup()  
        device={"iPad Pro","iPad Air","iPhone7 Plus","iPhone7","iPhone 5","Watch 42mm","Watch 38mm"}
        rectMode(CENTER)
        fontSize(40)
        font("Baskerville-Italic")
        x=300
        y=100
        xv=3
        yv=3
        dev=1
        if WIDTH<HEIGHT then
            tab={vec2(1024,1366),vec2(768,1024),vec2(414,736),
                    vec2(375,667),vec2(320,568),vec2(156,195),vec2(136,170)}
        else
            tab={vec2(1366,1024),vec2(1024,768),vec2(736,414),
                    vec2(667,375),vec2(568,320),vec2(195,156),vec2(170,136)}
        end 
        wm=WIDTH
        hm=HEIGHT 
    end
    
    function orientationChanged()
        setup()
    end
    
    function draw()
        background(0)
        fill(255)   
        stroke(255)
        strokeWidth(3)
    
        -- same code for all devices
        w=tab[dev].x    -- width of device from table
        h=tab[dev].y    -- height of device from table
        mw=wm     -- largest width of all devices
        mh=hm     -- largest height of all devices
        ar=(w/h)/(mw/mh)    -- aspect ratio
    
        scale(w/mw,h/mh)    -- scale of device to largest screen
    
        sprite("Planet Cute:Character Pink Girl",x,y,101,171*ar)
        sprite("Planet Cute:Character Cat Girl",100,600,101,171*ar)
    
        text("Tap screen to show different device sizes.",mw*.38,mh*.25)
        text(device[dev],mw*.2,mh*.45)
        text(tab[dev].x.."  "..tab[dev].y,mw*.2,mh*.4)
    
        noFill()
        ellipse(mw/2,mh/2,50,50*ar)
        ellipse(mw*.75,mh*.75,100,100*ar)
    
        line(mw/2,mh/2,0,mh)
        line(mw*.75,mh*.75,200,100)
    
        rect(mw/2,mh/2,mw,mh)
        rect(200,100,100,100*ar)
        -- end of same code for all devices
    
        -- calculate motion of sprite
        x=x+xv
        y=y+yv
        if x>=mw or x<=0 then
            xv=-xv
        end
        if y>=mh or y<=0 then
            yv=-yv
        end    
    end
    
    function touched(t) -- display different device size
        if t.state==BEGAN then
            dev=dev+1
            if dev>#device then
                dev=1
            end
        end
    end
    
  • Posts: 116

    Thanks for your answers :)

    I'll try to implement this in my project and test it in XCode.

  • Posts: 116

    Actually, I still have difficulty scaling my project for different screen sizes.
    Why isn't it sufficient to put scale(...) in front of everything that's supposed to be scaled? In my particular case I would use scale((width*height)/(WIDTH/HEIGHT)). When I do this, the sizes of all objects are exactly as needed. However, the objects aren't centered anymore. Instead, depending on the screen size, everything is too much on the left or too much on the right unless the aspect ratio equals 1. Why is that and what can I do to fix it?

  • @Leon, i usually define all positions as a fraction of the WIDTH and the HEIGHT, e.g. pos=VEC2(0.1*WIDTH, 0.9*HEIGHT).
  • Posts: 116

    Thanks, I tried that. But it didn't workout for me/this specific project. I'd just like to know how to get everything that's drawn centered when using scale.

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon Are you trying to do the scaling on the actual device or are you on an iPad trying to scale it there for the different sizes.

  • Posts: 116

    I've attempted both. I've used the Simulator in XCode and I tried it on the iPad using Multitasking with another App open next to Codea.

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon Did you try running my code above. That does the scaling for different sizes and everything is in the correct scaled places for the different devices.

  • Posts: 116

    Yes, I tried that. I just don't comprehend why scale(...) alone isn't enough. When do you need mh and mw for adjusting the positioning of sprites?

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon Everything is relative to the lower left corner of the screen. When you draw or write text, it's from that corner on all devices or it should be.

  • Posts: 116

    @dave1707 My issues is, that I'd like the App to scale automatically for all devices so I can potentially port it to Android using loveCodea.

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon You should be able to read the width and height values of the device and scale accordingly. All of your code placement should be based using the width and height and not hard coded.

  • Posts: 116

    @dave1707 Most of my code doesn't use width and height. Isn't it possible to use scale(...) and transform(..., ...) instead?

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon You use width and height so you know the size of the screen you're using. And you draw things using width and height so things are on the screen in the correct position no matter the screen size. If you try drawing something on the iPad Pro at position 1000,1000 it will be in the upper right corner. On the iPad Air it will be off the screen. But if you draw something at position width - 50, height - 50, it will be in the upper right corner no matter what device you use.

  • Posts: 116

    @dave1707 Thanks. I'm aware of why you should use width and height. I would just like to know whether you can use scale to shrink everything and translate to put it in the center of the screen. I couldn't get it to work.

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon Can you show a simple program of how you’re trying to center something using scale and translate. Maybe if I can see how you’re trying to do it, I might see why it doesn’t work.

  • Posts: 116

    @dave1707 Sorry for not responding earlier, I took a break from coding. I've been trying to put together an example of what I mean but for some reason I couldn't replicate my issue in another project. I'll give stripping down my current project to the bare minimum to show you, what exactly is happening. This could take a while though :#

  • Posts: 116

    Hello,
    after a longer break, I now opened up the project again and I still have the same issue. Here's what I'm trying to do:
    I have made a game, which mostly uses hardcoded positions like (800, 400) and only rarely positions relative to WIDTH and HEIGHT.

    I would now like to display the game on different screen sizes.
    For that, I would like to keep the aspect ratio, say 16:9 (like most modern monitors), and then shrink or scale the entire image to fit the screen. This way, it would keep the same aspect ratio, which prevents the image from being stretched, but it doesn't cut off stuff on smaller displays.
    So if the display has an aspect ratio different to 16:9, it chooses the largest possible size for the image to be displayed at 16:9 to keep the ratio between length and height at 16/9.

    Is there a way to do that? I've experimented with scale() and transform() but to no real effect. Since the positions of sprites and so on are already determined and this is now an afterthought, changing all positions to be relative to WIDTH or HEIGHT isn't really an option.

    Does anyone have an idea how you could achieve this?
    Thanks in advance for any suggestions :)

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon Have you tried my program above. That does text and graphics on different screen sizes keeping things similar.

  • Posts: 116

    @dave1707 Yes, I have and if I remember correctly, it worked really well. Though I had difficulty implementing this myself and wasn't sure how to adapt the coordinates and sizes of sprites :neutral:
    If I had a sprite like this: sprite("file", 200, 300, 64, 128), what would I have to change?

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon If that’s the normal size of the sprite, then you would keep that size. The value of 128 would get multiplied by the aspect ratio and the whole sprite would be scales by the scale function. Look at my code above in the draw function. The cat girl and pink girl sprites have their original sprite size of 101x171. As the screen size changes, the scale and aspect ratio values keep everything scaled correctly.

  • Posts: 116

    @dave1707 Thank you :)
    I'll give it a try right now!

  • Posts: 116

    @dave1707 Thanks again, it seems to be working :)
    I'll need to figure out how to treat touch positions now, but I hope that won't be too difficult. Thank you :)

  • Posts: 116

    @dave1707 I hope it's okay to bother you again.
    Somehow, I can't figure out how to adapt the touch controls accordingly :/

    I have a couple of buttons. The way they work is like this:
    if CurrentTouch.x < self.x + self.w/2 and CurrentTouch.x > self.x - self.w/2 and CurrentTouch.y < self.y + self.h/2 and CurrentTouch.y > self.y - self.h/2 then
    ...
    With self.x, self.y, ... being the position and size of the button.
    Do you know how I would have to change the code in order for it to work? I tried using *ar to multiply self.h/2 but this didn't work. The x-position is off also.

    If I wanted to zoom into the game, could I do that as well?

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon I never tried doing the touch on my program on different sized devices. I guess I can take my program and add a button to it and see what happens on my small iPad Air 3 and larger iPad Pro. I’ll let you know what I figure out.

  • Posts: 116

    @dave1707 Thank you, I really appreciate your help :)

  • dave1707dave1707 Mod
    Posts: 8,491

    @Leon I tried a button in my program and it looks like there’s not a whole lot to do. A button would be setup just like normal. You would have to position the button using width and height. I might need to move some code around. I want to modify my code to remove the changing size by touching the screen and have dedicated code based on the device it’s on. That way I can load a copy on my 2 different sized iPads and see how it works. I’ll let you know what happens and I can post a copy of the code with just the button code. Do you have different devices you can try it on. If not, maybe the users here with different sized devices can try it.

  • dave1707dave1707 Mod
    edited March 28 Posts: 8,491

    @Leon Here's a stripped down version. When you look over the code, you’ll see that there’s not much that changes from normal code. The major things you need to do is position everything based on WIDTH and HEIGHT. The size of everything needs to be multiplied by arX and arY to give it the correct size. arX and arY will be a ratio of the current WIDTH and current HEIGHT compared to a base WIDTH and base HEIGHT. The base WIDTH and HEIGHT will be the device you originally write the code for. The current WIDTH and HEIGHT will be the other device it runs on. Let me know how this works for you if you have different devices you can run this on.

    PS. Tap the off/on button.

    displayMode(FULLSCREEN)
    
    function setup()  
        rectMode(CENTER)
        baseW,baseH=834,1112    -- these values are my iPad Air 3 width and height
        arX=WIDTH/baseW
        arY=HEIGHT/baseH
        fontSize(40*arX)
        font("ArialRoundedMTBold")
        fill(255)   
        stroke(255)
        strokeWidth(2)
        x,y=300,100
        xv,yv=3,3
        b1=button(WIDTH/2,HEIGHT/2+200,100*arX,100*arY)
    end
    
    function draw()
        background(0)
    
        sprite(asset.builtin.Planet_Cute.Character_Pink_Girl,x,y,101*arX,171*arY)
        sprite(asset.builtin.Planet_Cute.Character_Cat_Girl,100,600,101*arX,171*arY)
    
        noFill()
        ellipse(WIDTH/2,HEIGHT/2,50*arX,50*arY)
        ellipse(WIDTH*.75,HEIGHT*.75,100*arX,100*arY)
    
        line(WIDTH/2,HEIGHT/2,0,HEIGHT)
        line(WIDTH*.75,HEIGHT*.75,WIDTH*.15,HEIGHT*.15)
    
        rect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
        rect(WIDTH*.15,HEIGHT*.15,100*arX,100*arY)
    
        x=x+xv
        y=y+yv
        if x>=WIDTH or x<=0 then
            xv=-xv
        end
        if y>=HEIGHT or y<=0 then
            yv=-yv
        end 
    
        b1:draw() 
    end
    
    function touched(t) 
        if t.state==BEGAN then
            b1:touched(t)
        end
    end
    
    button = class()
    
    function button:init(x,y,w,h)
        self.x=x
        self.y=y
        self.w=w
        self.h=h 
        self.c=false  
        self.n="off"
    end
    
    function button:draw()
        rect(self.x,self.y,self.w,self.h)
        fill(255)
        text(self.n,self.x,self.y)
    end
    
    function button:touched(t)
        if t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and
                t.y>self.y-self.h/2 and t.y<self.y+self.h/2 then
            self.c=not self.c
            if self.c then
                self.n="on"
            else
                self.n="off"
            end
        end
    end
    
  • Posts: 116

    @dave1707 After a little bit of trial and error it's working now!
    Thank you :)

Sign In or Register to comment.