Skip to content
Tags

40. Working with playing cards – part 2

April 23, 2013

In this post, we’ll create (ie draw) an entire deck of cards from scratch.

There are several stages to doing this

  • drawing a rounded card shape
  • finding pictures for the suits and royalty cards
  • drawing the card faces
  • drawing the results to the screen face up, face down, at an angle etc

..
Drawing a basic card

Playing cards have rounded corners, so they are rounded rectangles. There has been some discussion on the Codea forums about drawing these (for dialog boxes, but the idea is the same).

There are two obvious methods –
1. draw four small circles at the corners plus a couple of rectangles
2. use a couple of thick lines with rounded ends, plus a couple of rectangles

I’ve used the first method below. There is code for the other one in this thread.

function Card:createOutline(face)
    --use standard 25/35 ratio
    self.width=math.floor(self.height*25/35+.5)
    local img=image(self.width,self.height)
    --create rounded corner on top right
    local corner=0.05 --distance from end of card as percent of height
    local c=math.floor(corner*self.height+0.5)
    setContext(img)
    pushStyle()
    strokeWidth(1)
    stroke(self.cornerColor)
    --set background colour
    if face then fill(self.faceColor) else fill(self.backColor) end
    --draw small circles at corners
    ellipse(self.width-c+1,self.height-c+1,c*2)
    ellipse(self.width-c+1,c-1,c*2)
    ellipse(c-1,self.height-c+1,c*2)
    ellipse(c-1,c-1,c*2)
    if face then stroke(self.faceColor) else stroke(self.backColor) end
    --now rectangles to fill in thre centre of the card
    rect(0,c,self.width,self.height-c*2)
    rect(c,0,self.width-c*2,self.height)
    --now a border round the card
    stroke(self.borderColor)
    line(0,c,0,self.height-c)
    line(c,0,self.width-c,0)
    line(self.width,c,self.width,self.height-c)
    line(c,self.height,self.width-c,self.height)
    --do picture on back
    if face~=true then
        sprite(self.backImg,img.width/2,img.height/2,img.width*.9)
    end
    popStyle()
    setContext()
    return img
end

Note that I only have to create one card like this, put it in an image, and after that, I can just use that image as a template for any particular card that I need.

Finding pictures for the suits and royalty cards

Note – by royalty, I mean of course the King, Queen and Jack pictures usually shown on cards.

I could have borrowed pictures from the internet, but they would have made it more difficult to share the code with you, they would not have scaled to larger or smaller sizes, and besides, I always like to write code that is self contained, with no dependencies.

So I had a look in the emoji character set that I wrote about in post 25, and I found some good pictures of the four suits in there, and some people pictures that were close enough to do for the royalty pictures. This means my code can generate all the cards completely by itself.

Drawing the card faces

This is the hardest part, because every one of the 13 cards is different, using little suit images that are all in different places, and half of them have to be drawn upside down!

I’m not going to put all of the code in here because it’s quite long (I will provide it below, of course), but essentially it does the following, given a particular card to draw

  • 1. figure out the suit and value
  • 2. set the text colour to red or black depending on the suit
  • 3. put the number in the top left corner and the suit image under it
  • 4. draw the suit images in the middle of the card that are the right way up
  • 5. rotate the card 180 degrees and repeat from step 3

.
Most of the numbers and images on the cards are mirrored, that is, if you flip the card 180 degrees they look exactly the same. However, some odd numbered cards have an extra image in the middle that doesn’t have an upside down partner, so I need “if” statements to prevent that happening.

My main problem in all of this was guessing exactly where to put all the bits on the cards, and it was definitely by trial and error.

Drawing to the screen

This is the easy part, even if you want to draw the card at an angle

--draws a card at x,y with value of card (1-52), face=true if face up, a=angle in degrees (default 0)
function Card:draw(x,y,card,face,a)
    pushMatrix()
    --reset 0,0 to be the bottom left of the card
    --for drawing purposes, to make coding easier
    translate(x+self.width/2,y-self.height/2)
    if a==nil then a=0 end --angle
    rotate(a)
    if face then --face up
        --drawDetails is the function that draws all the details
        if card>0 then self:drawDetails(card) else sprite(self.cardFace,0,0) end
    else
        sprite(self.cardBack,0,0)
    end
    popMatrix()
end

Which gives the ability (if we include the shuffling and dealing from the last post), to deal cards to a hand and display them on the screen. Here is the code.

This is very exciting, but you’ll find if you try to program a real game of cards, it can get quite tricky. For example, just basic patience requires dealing overlapping cards, managing a pack of unused cards, a waste pile of cards, four ace piles, and allowing dragging of cards from one place to other, following various rules. So I’m only about halfway through all that…

Advertisements

From → animation, Games

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: