Need help with CurrentOrientation

Hello everyone.

I’ve been working on a class that draws a checkered board; this class is meant to work in any screen orientation.

However, you will notice that if you start the program on portrait orientation, for instance, and then switch to landscape, the squares on the last column are horizontally streched out and the line thickness (strokeWidth) is less than in portrait mode.

Similarly, if you start the program in landscape orientation and then switch to portrait, the squares on the top row are vertically streched out and the line thickness is less than in landscape mode.

Does anyone have any insight into why this is happening? Here’s the code:


-- CheckeredBoard

-- Use this function to perform your initial setup
function setup()
    displayMode(FULLSCREEN)
    board = CheckeredBoard()
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    stroke(0, 0, 0, 255)
    strokeWidth(3)

    -- Do your drawing here
    board:draw()
    fill(255, 16, 0, 255)
    
    --[[
    text("WIDTH = " .. WIDTH, WIDTH/2, HEIGHT/1.05)
    text("HEIGHT = " .. HEIGHT, WIDTH/2, HEIGHT/1.08)
    text("HEIGHT - WIDTH = " .. HEIGHT - WIDTH, WIDTH/2, HEIGHT/1.2)
    text("(HEIGHT - WIDTH) / 2 = " .. (HEIGHT - WIDTH) / 2, WIDTH/2,
    HEIGHT/1.25)
    --]]
end


CheckeredBoard = class()

function CheckeredBoard:init(cellSize)
    self.squareSizePortrait = squareSizePortrait or WIDTH/8
    self.squareSizeLandscape = squareSizeLandscape or HEIGHT/8
    --self.strokeColor = color(0, 0, 0, 255)
    self.strokeThickness = strokeThickness or 3
    -- self.color1 = color1 or
    -- self.color2 = color2 or
end

function CheckeredBoard:draw()
    rectMode(CENTER)

    if CurrentOrientation == PORTRAIT or
        CurrentOrientation == PORTRAIT_UPSIDE_DOWN 
        then

        for k = 0, 7 do
            for i = 0, 7 do
                if k % 2 == 0 then
                    if i % 2 == 0 then
                        fill(113, 91, 53, 255)
                    else
                        fill(209, 151, 72, 255)
                    end
                end
            
                if k % 2 ~= 0 then
                    if i % 2 == 0 then
                        fill(209, 151, 72, 255)
                    else
                        fill(113, 91, 53, 255)
                    end
                end
            
                rect(self.squareSizePortrait/2 + (WIDTH/8 * i),
                self.squareSizePortrait/2 + (WIDTH/8 * k) +
                (HEIGHT - WIDTH)/2, self.squareSizePortrait,
                self.squareSizePortrait)
            end
        end
    end

    if CurrentOrientation == LANDSCAPE_LEFT or
        CurrentOrientation == LANDSCAPE_RIGHT then
        
        for k = 0, 7 do
            for i = 0, 7 do
                if k % 2 == 0 then
                    if i % 2 == 0 then
                        fill(113, 91, 53, 255)
                    else
                        fill(209, 151, 72, 255)
                    end
                end
            
                if k % 2 ~= 0 then
                    if i % 2 == 0 then
                        fill(209, 151, 72, 255)
                    else
                        fill(113, 91, 53, 255)
                    end
                end
            
                rect(self.squareSizeLandscape/2 + (HEIGHT/8 * i) +
                (WIDTH - HEIGHT)/2, self.squareSizeLandscape/2 +
                (HEIGHT/8 * k) ,self.squareSizeLandscape,
                self.squareSizeLandscape)
            end
        end
    end
end

function CheckeredBoard:touched(touch)
    -- Codea does not automatically call this method
end

Can’t anyone help me? My problem would be easier to understand if you pasted the code and tried it out for yourself.

Try holding your iPad in portrait or landscape style before pressing the run button. Notice how the board looks in its initial state, and then change orientation; you will notice that the board looks different (the strokeWidth would have changed and the last row/column is distorted).

Please help.

.@the_dude try to eliminate all use of WIDTH and HEIGHT from inside your Checkerboard class. The problem is that you are saving the values of WIDTH and HEIGHT in Checkerboard:init — then WIDTH and HEIGHT change when you rotate the iPad, but the values you have saved inside init remain the same.

.@Simeon thanks for the response. What about the changing strokeWidth?

.@Simeon I didn’t have to fix strokeWidth; all I had to do was eliminate use of the variables self.squareSizePortrait and self.squareSizeLandscape. Thank you so much man. Looking forward to version 1.5!

OH, ONE MORE QUESTION!

I tried using currentOrientation == PORTRAIT_ANY and currentOrientation == LANDSCAPE_ANY, but neither work. I have to use currentOrientation == PORTRAIT or currentOrientation == PORTRAIT_UPSIDE_DOWN and currentOrientation == LANDSCAPE_LEFT or currentOrientation == LANDSCAPE_RIGHT to support all the orientations. Why?

This is because currentOrientation can only be set to one specific orientation at a given time.

currentOrientation tells you what your iPad is currently rotated as. PORTRAIT_ANY represents two possible orientations: PORTRAIT and PORTRAIT_UPSIDE_DOWN. So you can’t actually do an equality check against PORTRAIT_ANY as it does not represent a singular orientation.

I would suggest the following helper function instead:

function isPortrait(orientation)
    if orientation == PORTRAIT or
       orientation == PORTRAIT_UPSIDE_DOWN then
         return true
    end
    return false
end

-- The same for landscape...

.@Simeon Thank you so much for the clarifications. I learned so much today.

@the_dude I modified your code so it doesn’t matter if it’s portrait or landscape. Maybe this will help.


-- CheckeredBoard

function setup()
    displayMode(FULLSCREEN)
    board = CheckeredBoard()
end

function draw()
    background(40, 40, 50)
    board:draw()
end

CheckeredBoard = class()

function CheckeredBoard:init()
end

function CheckeredBoard:draw()
    rectMode(CENTER)
    stroke(0)
    strokeWidth(3)
    for x=1,8 do
        for y=1,8 do
            if x % 2 == 0 then
                if y % 2 == 0 then
                    fill(113, 91, 53, 255)
                else
                    fill(209, 151, 72, 255)
                end
            elseif y % 2 ~= 0 then
                    fill(113, 91, 53, 255)
                else
                    fill(209, 151, 72, 255)
                end
            rect(x*90,y*90,89,89)
        end
    end
end

function CheckeredBoard:touched(touch)
end

.@dave1707 Thank you for sharing. I should point out however, that I insisted on using WIDTH and HEIGHT variables when drawing the board in order for the app to work on different devices having different screen sizes.

.@the_dude Maybe this will give you an idea. I added the function minSize() that gets the minimum of width or height and uses that to calculate the square sizes. I only have an iPad, so I can’t try different screen sizes. I think it should work for any screen.


-- CheckeredBoard

function setup()
    displayMode(FULLSCREEN)
    board = CheckeredBoard()
end

function draw()
    background(40, 40, 50)
    board:draw()
end

function minSize()
    size=WIDTH
    if size>HEIGHT then
        size=HEIGHT
    end
    size=size/9  -- calculate square size to fit screen
end

CheckeredBoard = class()

function CheckeredBoard:init()
end

function CheckeredBoard:draw()
    rectMode(CENTER)
    stroke(0)
    strokeWidth(3)
    minSize()
    for x=1,8 do
        for y=1,8 do
            if x % 2 == 0 then
                if y % 2 == 0 then
                    fill(113, 91, 53, 255)
                else
                    fill(209, 151, 72, 255)
                end
            elseif y % 2 ~= 0 then
                    fill(113, 91, 53, 255)
                else
                    fill(209, 151, 72, 255)
                end
            rect(x*size,y*size,size-1,size-1)
        end
    end
end

function CheckeredBoard:touched(touch)
end

.@dave1707 Thanks, it seems that you are very active in this community. Here’s my latest code - notice that I use geometry to position the board exactly at the center of the screen in whatever orientation you choose. I am planning to start with a checkers game - initially without AI. I just got started in game development as a hobby and I have much to learn.

-- CheckeredBoard

-- Use this function to perform your initial setup
function setup()
    saveProjectInfo("Description", "Use for Chess and Checkers")
    saveProjectInfo("Author", "the_dude")
    --displayMode(FULLSCREEN)
    board = CheckeredBoard()
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    
    stroke(0, 0, 0, 255)
    strokeWidth(3)

    -- Do your drawing here
    board:draw()
    fill(255, 16, 0, 255)
    
    --[[
    text("WIDTH = " .. WIDTH, WIDTH/2, HEIGHT/1.05)
    text("HEIGHT = " .. HEIGHT, WIDTH/2, HEIGHT/1.08)
    text("HEIGHT - WIDTH = " .. HEIGHT - WIDTH, WIDTH/2, HEIGHT/1.2)
    text("(HEIGHT - WIDTH) / 2 = " .. (HEIGHT - WIDTH) / 2, WIDTH/2,
    HEIGHT/1.25)
    --]]
end


CheckeredBoard = class()

function CheckeredBoard:init()
    --self.strokeColor = color(0, 0, 0, 255)
    displayMode(FULLSCREEN)
    self.strokeThickness = strokeThickness or 3
    
    -- self.color1 = color1 or
    -- self.color2 = color2 or
end

function CheckeredBoard:draw()
    rectMode(CENTER)

    if CurrentOrientation == PORTRAIT or
        CurrentOrientation == PORTRAIT_UPSIDE_DOWN then

        for k = 0, 7 do
            for i = 0, 7 do
                if k % 2 == 0 then
                    if i % 2 == 0 then
                        fill(113, 91, 53, 255)
                    else
                        fill(209, 151, 72, 255)
                    end
                end
            
                if k % 2 ~= 0 then
                    if i % 2 == 0 then
                        fill(209, 151, 72, 255)
                    else
                        fill(113, 91, 53, 255)
                    end
                end
            
                rect((WIDTH/8)/2 + (WIDTH/8 * i),
                (WIDTH/8)/2 + (WIDTH/8 * k) +
                (HEIGHT - WIDTH)/2, WIDTH/8,
                WIDTH/8)
            end
        end

        -- The sole purpose of the following four lines is to increase the thickness of the lines on the
        -- outer edge of the board to match the thickness of the inner lines of the board.
        fill(0, 0, 0, 0)
        stroke(0, 0, 0, 255)
        strokeWidth(6)
        rect(WIDTH/2, HEIGHT/2, WIDTH, WIDTH)
    end

    if CurrentOrientation == LANDSCAPE_LEFT or
        CurrentOrientation == LANDSCAPE_RIGHT then

        for k = 0, 7 do
            for i = 0, 7 do
                if k % 2 == 0 then
                    if i % 2 == 0 then
                        fill(113, 91, 53, 255)
                    else
                        fill(209, 151, 72, 255)
                    end
                end
            
                if k % 2 ~= 0 then
                    if i % 2 == 0 then
                        fill(209, 151, 72, 255)
                    else
                        fill(113, 91, 53, 255)
                    end
                end
            
                rect((HEIGHT/8)/2 + (HEIGHT/8 * i) +
                (WIDTH - HEIGHT)/2, (HEIGHT/8)/2 +
                (HEIGHT/8 * k) ,(HEIGHT/8),
                (HEIGHT/8))
            end
        end
    end
    
    fill(0, 0, 0, 0)
    stroke(0, 0, 0, 255)
    strokeWidth(6)
    rect(WIDTH/2, HEIGHT/2, HEIGHT, HEIGHT)
end

function CheckeredBoard:touched(touch)
    -- Codea does not automatically call this method
end

Hi @the_dude,

I need a class to produce a similar board so was interested in your code. I have posted, below, my contribution so far.

I set out initially to use arrays and do all calcs in the setup() to minimise lost time in the draw routines. Also it helps in game design if you can hold your grid details and conditions in a Table/Array. I used mod to determine if the squares were odd or even and have placed a larger board in the back of the grid to provide an even and wider border. I have found by playing with the strokeWidth() and the transparency in the darker fill that you can get different finishes to the appearance of the grid (you need to use the same colors for the background box as the stroke() colour.

Anyway - have a play and enjoy - please feed back any ideas for modifying to get a proper Class() out of this - can’t seem to draw up more than one board on the screen at a time.


Board = class()

function Board:init(x,y,c,s,k)
    -- you can accept and set parameters here
    self.x = x
    self.y = y
    self.grid = {}
    self.cells = c
    self.size = s
    self.strk = k
    self.box = self.cells*self.size+3*self.strk
    self.CX = self.x - ((self.cells/2)+1)*self.size + self.size/2
    self.CY = self.y - ((self.cells/2)+1)*self.size + self.size - self.size/2
    for row = 1, self.cells do
        self.grid[row] = {}
        newY = self.CY + (self.size)*row
        for cols = 1, self.cells do
            newX = self.CX + cols*(self.size)
            self.grid[row][cols] = vec2(newX, newY)
        end
    end
end

function Board:draw()
    -- Codea does not automatically call this method
    strokeWidth(1)
    fill(63, 43, 33, 255)
    stroke(82, 61, 34, 255)
    rect(self.x, self.y, self.box, self.box)
	bx = 0
	for row = 1, self.cells do
		bx = bx + 1
		for cols = 1, self.cells do
			if isOdd(bx) then fill(177, 134, 77, 255) else fill(82, 61, 34, 255) end                      
			rect(self.grid[row][cols].x, self.grid[row][cols].y, self.size,self.size)
			bx = bx + 1
		end
	end 
end

function Board:touched(touch)
    -- Codea does not automatically call this method
end

Bri_G

:smiley:

Hi @the_dude,

Sorry - forgot the calling code neede for the main.lua.


 -- Board game constructor from Bri_G
 -- based on post from the_dude
 
function setup()
	displayMode(FULLSCREEN)
	Board:init(WIDTH/2, HEIGHT/2, 8, 80, 3)
end

function draw()
	rectMode(CENTER)
	background(112, 183, 56, 255)
	Board:draw()
end

function isOdd(var)
	if var % 2 == 0 then 
		return false 
	else 
		return true
	end
end

Mostly obvious but it also includes the isOdd() function needed that I used.

Bri_G

#-O

Some time ago there was a discussion about a checker game and how to keep the piece that was being moved on top of any other piece. Since objects are drawn in the order they’re created, some objects will be drawn on top of or below other objects. I wrote this game back then, but I don’t remember if I posted it or not. I can’t find the original discussion. So here it is again showing a working checker game with the moving piece always on top of all the other pieces. A double tap will KING a piece, and 4 taps will remove a piece. There isn’t any kind of editing so the pieces can be moved anywhere on the board. I think I got sidetracked when I wrote this and then lost interest in it. Maybe this will help with your checker game.


displayMode(FULLSCREEN)

function setup()
    rectMode(CENTER)
    green=color(0,255,0)
    blue=color(0,0,255)
    col={}
    ctab={}
    radius=35
    square=80
    boardSetup()
    circleSetup()
    current=0
    selected=false
    remove=0
end
    
function boardSetup()
    x=1
    for z=1,64 do
        if x==1 then
            col[z]=color(255,255,255)
        else
            col[z]=color(255,0,0)
        end
        x=x*-1
        if z%8 == 0 then
            x=x*-1
        end
    end
end

function circleSetup()    
    z=0
    for x=1,8,2 do
        z = z + 1
        ctab[z]=circle((x+1)*square,1*square,green)        
        ctab[4+z]=circle(x*square,2*square,green)
        ctab[8+z]=circle((x+1)*square,3*square,green)
        ctab[12+z]=circle(x*square,6*square,blue) 
        ctab[16+z]=circle((x+1)*square,7*square,blue)                
        ctab[20+z]=circle(x*square,8*square,blue)
    end  
end

function draw()
    background(40, 40, 50)
    drawBoard()
    drawCircles()
end

function drawBoard()
    z = 0
    for x=1,8 do
        for y=1,8 do
            z = z + 1
            fill(col[z])
            rect(x*square,y*square,square-1,square-1)
        end
    end
end

function drawCircles()
    for z=1,#ctab do
        ctab[z]:draw()
    end
    if current>0 then
        ctab[current]:draw()    -- keep moving piece on top of others
    end
    if remove > 0 then
        table.remove(ctab,remove)    -- remove deleted piece
        remove=0
    end  
end

function touched(t)
    for z=1,#ctab do
        ctab[z]:touched(t,z)    -- pass t and the circle number
    end
end

circle = class()

function circle:init(x,y,c)
    self.x=x
    self.y=y
    self.color=c    
    self.selected=false
    self.king=false
end

function circle:draw()
    fill(self.color)
    ellipse(self.x,self.y,radius*2,radius*2)
    if self.king then
        fill(0)
        ellipse(self.x,self.y,radius*2,5)
        ellipse(self.x,self.y,5,radius*2)
    end
end

function circle:touched(t,z)
    if (t.y-self.y)^2/radius^2+(t.x-self.x)^2/radius^2 <= 1 then
        if t.state==BEGAN then
            if t.tapCount==2 then
                self.king=not self.king    -- toggle true or false
            elseif t.tapCount==4 then
                remove=z
            elseif not selected then
                self.selected=true
                selected=true
                current=z     -- the number of the circle being moved
            end
        end
            if t.state==MOVING and self.selected then
            self.x=t.x
            self.y=t.y
        end
        if t.state==ENDED then
            self.selected=false
            current=0
            selected=false
        end
    end
end

There’s a very useful function that doesn’t get much airing but which might be of particular use to you here. That’s the orientationChanged function. It gets called whenever the orientation is changed and it takes the new orientation as its argument. So I have in my code:

function orientationChanged(o)
    ui:orientationChanged(o)
    debug:orientationChanged(o)
end

since the UI and the debugging routines need to know the current orientation as they do slightly different things in different orientations.

The only snag is that it can get called before setup is called, and thus before any objects are initialised. So actually what I have in my code is:

function _orientationChanged(o)
    ui:orientationChanged(o)
    debug:orientationChanged(o)
end

and then the last line of setup is:

orientationChanged = _orientationChanged

So you could define an orientationChanged method for your checkerboard which redefines the various parameters and positions to ensure that it is doing the right thing no matter what the orientation.

.@dave1707 I believe I was the one who initiated that discussion about keeping the piece being touched on top of all the other pieces. Kudos to you Dave! I’ve yet to read about tables in Lua. I don’t seem to have much time on my hands these days.

.@Bri_G Your board is great, but it suffers from the same problem I faced at the start of my project. Run your program and then tilt your device to change screen orientation. The board will no longer be drawn properly if you switch orientation while your program is running. This is because, as .@Simeon mentioned earlier, you used WIDTH and HEIGHT to initialize the board position. When you run the program, say in landscape mode, the WIDTH = 1024 and the HEIGHT = 768, but when you switch orientation to portrait while the program is running, the values of WIDTH and HEIGHT will switch - that is, in portrait orientation WIDTH = 768 and HEIGHT = 1024. You should account for these changing values, unless you intend your application to support only one particular orientation.

.@Andrew_Stacey This is an interesting approach. Thanks for sharing.

Hi @the_dude,

See Andrew’s code above - I use a very simple piece of code which checks the orientation by:


WmH = WIDTH - HEIGHT

if WmH > 0 then
  -- Landscape in use
  -- set up your orientation specific variables here
else
 -- Portrait in use
 -- set up your portrait specific variables here
end

Put this at the begining of your draw() function and you should get correct orientation. I’ve used it a lot - avoid putting too much calculation in the draw() function or it will slow and may even corrupt.

Have fun.

Bri_G

:wink:

.@Bri_G I should have mentioned that I’m not too good at reading other people’s code, it’s a flaw that I must live with for now. Hopefully, after reading plenty more quality material, I should be able to digest code more easily. Thanks again for your help!