Skip to content

Play UNO! Card Game in Neptune with Redis - GitHub Project Available

Blog Banner

Overview

I love playing card games, one of them is Uno! and this month I tried to replicate it in Neptune just using UI5 objects, JavaScript, Redis and CSS.

Today I want to share the project available for everyone on my personal GitHub! At the end of the blog you will also find a full play demo.

A big thank you to my wife that gave me the idea.

Neptune Uno Card Game - Small GIF

Prerequisites

  • Planet 9 (Open Edition DXP 23 or higher)
  • Redis installed / configured in the cockpit settings (you can follow my Getting Started)

Installation

  • Open your Planet 9 instance and go inside the Development Package section
  • Select the Import > Git option
Import project from GitHub repository
  • In Remote Repository URL paste my GitHub repository
https://github.com/fabriziopace/neptune-uno-card-game.git
  • Click now on the OK button, this will import all artifacts used in this project
Import project from GitHub repository
  • You will find a new tile in the Neptune Cockpit > Entertainment section
New tile in Neptune Cockpit - Entertainment section
  • Have fun!

The room creation

When the user access the first time to the application can create a new room.

Room creation

Join in the room

In order to join in the room the host will send the link got from the share button in the header menu to other user. Example:

http://localhost:8080/app/uno_card_game?room=NeptuneCommunity
Waiting room

Then the user can enter the username and join.

User join in the room

Game interface

  • In the header bar we have the room / opponent user data and the button to exit from the room
  • In the body two cards hands are rendered once the game starts, in addition of the deck and the pile
  • Below we have a footer containing three action buttons (getting a new card, skip the turn or calling uno), your user data and the current color
  • A crown will be visible near the user when he will get his turn and only playable cards will be enabled
Game interface

How it works

In the App Designer I created four sap.m.List elements containing the opponent and personal hands, the deck and the pile.

App designer structure

When the game starts all cards are built in the startGame function, where for each of them an id is generated (to move a specific card from a list to another when needed).

The deck is shuffled and each user gets seven cards.

On any user action like getting a new card or skipping the turn the data is sent using Neptune Events to the other user.

Game data sent via Neptune Events - Redis

Rules

The game tries to follow the official rules and is composed of 108 cards in total (excluding one "Wild Shuffle Hands" and three "Wild Customizable").

The first user to get rid of all personal hand cards wins the game.

All game cards

What's next

  • Allow to invite more users to play the game (currently maximum 2 per room)
  • The game interface can be improved with smoother animations
  • JavaScript code can be adapted for further logics like having more rounds and counting user points
  • Cards data can be moved to a Planet 9 table

What I learned

I had a lot of fun and improved my skills using SCSS. For example nesting CSS selectors, writing variables and mixin to reuse a group of properties in many places or even looping list items to apply an incremental rotation and z-index on cards hands / pile.

$rotateMyCardDeg: -10;
$rotateOppCardDeg: 10;
 
@for $i from 1 through 100 {
    $rotateMyCardDeg: $rotateMyCardDeg + 1;
 
    .listMyCards li:nth-child(#{$i}) {
        z-index: $i;
        rotate: $rotateMyCardDeg + deg;
    }
 
    $rotateOppCardDeg: $rotateOppCardDeg - 1;
 
    .listOppCards li:nth-child(#{$i}) {
        z-index: $i;
        rotate: $rotateOppCardDeg + deg;
    }
}

Was challenging building all UNO! cards assigning custom data to each list item:

// based on value property style the card
let cardValue = "";
 
if (
    value !== "skip" &&
    value !== "reverse" &&
    value !== "drawtwo" &&
    value !== "wild" &&
    value !== "wilddrawfour"
) {
    cardValue = value;
}
 
this.data("value", value, true);
return cardValue;

And then using SCSS to apply colors and UI5 icons:

Wild draw four card built with CSS
// mixin for common styles
@mixin wildIcon($sapIcon: "") {
    content: $sapIcon;
    font-family: SAP-icons;
    font-style: normal;
    font-weight: normal;
    background: linear-gradient(to right, $redColor 0%, $redColor 50%, $blueColor 50%, $blueColor 100%), linear-gradient(to right, $yellowColor 0%, $yellowColor 50%, $greenColor 50%, $greenColor 100%);
    background-size: 100% 50%;
     background-position: center top, center bottom;
    background-repeat: no-repeat;
     -webkit-background-clip: text;
    background-clip: text;
     -webkit-text-fill-color: transparent;
}
 
// wild cards
[data-value="wild"].textCardStyle:after {
    @include wildIcon($sapIcon: '\e145');
}
 
// wild draw four cards
[data-value="wilddrawfour"].textCardHeader:after,
[data-value="wilddrawfour"].textCardFooter:after {
    content: '+4';
    fill: $whiteColor;
}
 
[data-value="wilddrawfour"].textCardBody:after {
    @include wildIcon($sapIcon: '\e0bc');
}

Demo

I created a GIF (it may require some time to load):

Uno card game in Neptune - full play demo

Redis involved blogs

UI5 icons usage by CSS content property

SCSS tutorials

My motto: always make sure to have fun to unlock your limits!

Wish you all to reach and make your dreams real.

Happy coding and remember to call UNO! :)