-
Notifications
You must be signed in to change notification settings - Fork 0
Trading Cards
One of the biggest features that I wanted to add to Pokémon Manager is a easy way to send Pokémon to other people, and while theorizing it hit me. Trading Cards. The reason I wanted to create trading cards is:
- They should be easy to implement.
- It makes the process "magical" and "mysterious". I did not want the file to be just a file, I wanted it to feel like you are sending an actual Pokémon.
- Can be sent once and be multiplied. I first thought about creating an URL that others can use to download a Pokémon, but I did not have the resources to keep a server running, and I did not want users to either self host or make multiple links.
- Makes the process friendlier and easy. All that a user needs to do is press a button, save the card, and send it through any social media platform.
- It's just cool 😎
Trading card are just images. That's it. No new file type or anything. However, implementing them is the interesting part as there are a few different ways of going about it.
It's challenging due to the fact that we need convert this:
{ability:{ability:{name:overgrow, url:/api/v2/ability/65/}, is_hidden:False, slot:1}, ability_number:1, atk:82, def:83, egg_groups:[monster, plant], ev_atk:92, ev_def:23, ev_hp:45, ev_spa:51, ev_spd:15, ev_spe:102, exp:89691, form:0, gender:1, growth:medium-slow, hp:80, id:003 - Daisy - B82ABBBB6F73.pk6, iv_atk:22, iv_def:8, iv_hp:17, iv_spa:5, iv_spd:3, iv_spe:26, level:46, met_level:10, met_location:22, move1:{accuracy:0, form:2, id:80, name:petal-dance, power:120, pp:10, text:Works 2-3 turns and confuses user., typing:4}, move2:{accuracy:0, form:3, id:77, name:poison-powder, power:Null, pp:35, text:A move that may poison the foe., typing:8}, move3:{accuracy:0, form:1, id:75, name:razor-leaf, power:55, pp:25, text:Has a high criti cal hit ratio., typing:4}, move4:{accuracy:0, form:1, id:38, name:double-edge, power:120, pp:15, text:A tackle that also hurts the user., typing:1}, nickname:Daisy, ot:{game:24, gender:0, id:53109, nickname:DrRetro}, spa:100, spd:100, spe:80, species:3, species-name:venusaur, sprite:3.png, text:The plant blooms when it is absorbing solar energy. It stays on the move to seek sunlight., type1:4, type2:8}
Into this:
If you have taken a photo on modern phone, you might have noticed that you can view the date, location, and time the photo was taken. That's because the phone stored all of that information into the photo's metadata at the moment you pressed the shutter. You can imagine metadata like a photo's documents and id's (it's passport, birth certificate, social security, etc.). You can store anything into metadata, and on the surface, it seemed like the best bet due to the fact:
- It's invisible to the average user.
- I can store anything into the metadata, like Pokémon data.
- It's, relativity speaking, easy to implement.
However there are a few caveats:
- By my research, Godot 3 does not have any built-in way of editing metadata and there was not any extension that did.
- Side Note: I could have created the library myself, but I knew that I was not familiar with image storage and compression, which might lead me to accidentally writing over the image data and corrupting the image.
- "Solutions which are the first thing you'd think of and look sensible and are easy to implement are often terrible, ineffective solutions, once implemented will drag on civilization forever." - CGP Grey
- Some platforms check image metadata for extra information, and if detected, will not allow it to be uploaded. The real nail in the coffin however, is that most websites will convert the image (usually discarding extra metadata other than the date and time) or will remove the metadata by itself.
Do I need to explain a QR code? Ugh, fine.
QR Codes might be a good solution because:
- Everyone understands what they are is and how to use them.
- They can store raw data (if you want to learn more, you can check out this video by MattKC)
- Side Note: I absolutely can fit a Pokémon into a the size limits of a QR code.
- Godot probably has a QR code extension that will work.
However, I decided not to use them as:
- It's too obvious, remember that I want a solution that is invisible to the average user.
- It takes up valuable space, I cannot add too many visual details about the Pokémon contained without increasing the resolution, which might make it too big to send though discord or any other social media platform that has a strict upload size.
- Too simple, I need a challenge.
I know that AI is all the rage these days, so I know some dweeb is going to say, "Why not just use artificial intelligence? Idiot!" That's stupid and here's why.
- Error prone. It has a too high of an error rate for a consistent experience.
- It requires large amount of processing on my computer and/or users computers.
- It's bloat. I want the program to be relatively small, and does not require dependencies to run.
To tell you, we first need to talk about how computers understand colors and what binary is.
Binary, in the most simplest terms, is a numeral system that only uses two digits, 0 and 1. A base-2 system if you will. Modern computers use binary because it is the most stable way to do calculations and store data as a bit can only be on or off, so electric noise does not disrupt regular operation. Depending on the amount bits you use, the larger and more detailed the data can be. For example, an one bit pixel can either be black or white, so a 1-bit photo would look like this:
2 bits would look like this: And 4 bits looks like: As you can see, a small amount of bits does not make photos all to flattering. However, thanks to exponential growth, we only need to double 4 bits to create a decent looking photo: Credit
Side note: This is not an accurate visual of bit depth, however it gets the point across.
How can we use this? Well, the funny thing is that ALL DATA ON A COMPUTER IS BINARY. Numbers, images, audio, text documents, it's all binary.
A pixel in an image are represented as a short string of bytes (a byte is worth eight bits, which can represent 255 different values). Each byte represents the brightness of a pixel in one color channel. In a regular JPEG, there are three bytes for the red, green, and blue channels. Still with me? We are going to use PNGs as they can be uncompressed, which is vital to data stability. PNGs have a neat feature that you might be familiar to, called transparency. This adds one more byte to a pixel for a new channel called alpha. So, a PNG pixel is worth four bytes or 32 bits. Most of a Pokémon's information is in the form of a byte. There is an exception to this however, and you might already know if you have experience with editing Pokémon, Experience Points. At first, you might assume that I can just divide up the experience points into 255 chunks. I could, but it would take up a lot of room. To explain, let's look at my one of my Pokémon, Slippy. Slippy has a total of 139,980 experience points, a drop in the bucket compared to a full level Pokémon. Lets see how many 255 chunks I need to store into the image:
- 255
- 255
- 255
- 255
- 255
- 255
- 255
- 255
- 255
- 255
- 255 ... 549 BYTES!? 549 bytes would require 183 pixels, not including the alpha channel.
His experience points is going to be converted into binary at some point, so why not take out the middle man?
This is Slippy's 139,980 experience points converted into a 32 bit binary number:
00000000000000100010001011001100
Do you see the solution?
If you don't, let me show you:
00000000
|00000010
|00100010
|11001100
You can split it into four bytes. Remember how a PNG pixel is worth four bytes or 32 bits in total? That equals to 4,294,967,295 different states. So by using raw binary, we can decrease the required size down from 549 bytes to only three.