Every character is a 5×8 grid
Look closely at the display: each character cell is 5 pixels wide and 8 tall. A custom character is just an array of 8 bytes, one per row, where each 1 bit is a lit pixel. Write them in binary (B00100) and the shape is visible right in the code.
lcd.createChar(n, bitmap) stores the shape in slot 0 to 7 (eight custom characters maximum). lcd.write(n) draws it at the cursor. Call createChar in setup(), before you print anything.
Placing things
lcd.setCursor(col, row) chooses where the next thing lands. Columns run 0 to 15, rows are 0 and 1. Writing the icons at columns n instead of n * 2 removes the gap between them; adding an offset (n + 3) shifts the whole row right.
The sketch defines a smiley, an empty heart and a full heart, then draws a health bar. Swap the bitmaps for a battery, an ohm sign, an arrow, whatever your project needs.