Digital Arts Foundation—Final Project: Week 8 (Production)

For week 8, I started making walls to obstruct the enemy and add more detail to the scene. Thinking back to the plan, I also wanted the player to be safe while in ‘white mode’, so I constructed a white wall, where no enemies could pass. This white wall would be a vertical inner wall, while the outer walls would be magenta, to distinguish them from the Green, Red and Blue enemies. The background or outer floor was a dark grey, while the inner floor was a bit lighter with magenta mixed in.

Figure 1: An approximate recreation of my initial level design in Unity.

As for the ability of the white character to move through white walls (both of which actually look grey), I googled and looked into disabling the sprite renderer of the wall while entering its collider, and re-enabling it while exiting its collider. It took a lot of figuring out for what to do next, but eventually I settled for turning the player collider trigger on when going through the same coloured walls. I found an example of the correct code on the Unity forums. This behaviour would be same for the enemies too.

So to summarize the mechanics, the sprite renderer of the wall gets turned off in the OnCollisionEnter2D event, and gets turned on in the OnTriggerExit2D event. The opposite happens with the collider triggers for the objects entering/exiting the walls, as they get turned on when entering and get turned off when exiting.

private SpriteRenderer render;
private GameObject player;
private PolygonCollider2D playerCollider;

    void Start()
    {
        render = GetComponent<SpriteRenderer>();
        player = GameObject.FindWithTag("Player");
        playerCollider = player.GetComponent<PolygonCollider2D>();
    }

void OnCollisionEnter2D(Collision2D collision)
    {
        if (gameObject.layer == LayerMask.NameToLayer("White Wall") && collision.gameObject.layer == LayerMask.NameToLayer("IgnorePlayer"))
        {
            render.enabled = false;
            playerCollider.isTrigger = true;
        }
    }
void OnTriggerExit2D(Collider2D other)
    {
        if (gameObject.layer == LayerMask.NameToLayer("White Wall") && other.gameObject.layer == LayerMask.NameToLayer("IgnorePlayer"))
        {
            render.enabled = true;
            playerCollider.isTrigger = false;
        }
    }

Figure 2: Pass through walls code.

I also updated the player sprite in preparation for when I implement shooting, my chosen type of attack.

Figure 3: Passing through walls in my project in Unity.

For the next stage, I wanted to pass instructions to the player on how to play the game. I spent hours trying to work out how I could overlay additional text on the screen like I did with Game Over but while actually playing the game. I couldn’t figure it out, so I settled for a decent alternative: I would save images with the text on them and seemlessly add them onto the walls as separate game objects that I can gradually enable on the screen.

Figure 4: The starting message for my project in Unity.

The other main ability I wanted the player to have was teleporting. Reflecting on the mechanics, I wanted a script to find a teleport location within camera view that corresponded to the player colour. It was relatively simple to get working in its most basic form, since you just reassign the value for the position attribute of the player object on pressing the trigger button (T in this case). It gets a bit complicated when you add in the checks, such as finding a teleporter object in camera view, which requires looping through all teleporters and then checking the co-ordinates don’t exceed the camera area.

I also wanted one side of the teleporter to be visible and the other side not. A bug quickly arose where it would cycle through on-off, off-on, off-off, on-on states. I had to think through making a check that always treated the teleporter objects in pairs, so if one was on, the other one was off. It was an interesting challenge.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TeleportScript : MonoBehaviour
{
    // Declare variables.

    public Camera mainCamera;
    private GameObject player;
    private PlayerScript playerScript;
    [SerializeField] private GameObject bigGreenEnemy;
    private bool hasSpawned = false;

    // Assign variables.

    void Start ()
    {
        player = GameObject.Find("Player");
        playerScript = player.GetComponent<PlayerScript>();
    }

    void Update ()
    {

        // Upon pressing down T, finds the nearest visible teleport point, and teleports to it. After, it disables the forward teleport circle and reveals the backward one.

        if (Input.GetKeyDown(KeyCode.T))
        {
            GameObject[] teleporters = GameObject.FindGameObjectsWithTag("Teleporter");
            SpriteRenderer spriteRenderer1 = null;
            SpriteRenderer spriteRenderer2 = null;
            Vector3 teleporterLocation = new Vector3(0,0,0);

            foreach (GameObject teleporter in teleporters)
            {
                bool whiteCheck = player.layer == LayerMask.NameToLayer("IgnorePlayer") && teleporter.layer == LayerMask.NameToLayer("White Teleporter");
                bool greenCheck = player.layer == LayerMask.NameToLayer("Player") && teleporter.layer == LayerMask.NameToLayer("Green Teleporter") && playerScript.hasAbility["GreenTeleport"];
                if (whiteCheck || greenCheck)
                {
                    Vector3 targetPosition = mainCamera.WorldToViewportPoint(teleporter.transform.position);

                    if (targetPosition.x >= 0 && targetPosition.x <= 1 && targetPosition.y >= 0 && targetPosition.y <= 1)
                    {

                        SpriteRenderer spriteRenderer = teleporter.GetComponent<SpriteRenderer>();

                        if (spriteRenderer.enabled)
                        {
                            teleporterLocation = teleporter.transform.position;
                            spriteRenderer1 = spriteRenderer;
                        }
                        else
                        {
                            spriteRenderer2 = spriteRenderer;
                        }
                    }
                }
            }
            if (spriteRenderer1 != null && spriteRenderer2 != null && !teleporterLocation.Equals(default))
            {
                transform.position = teleporterLocation;
                spriteRenderer1.enabled = false;
                spriteRenderer2.enabled = true;
            }
            else
            {
                StartCoroutine(playerScript.Flicker(player));
            }
        }
    }
}

Figure 5: Teleport Script.

I added a dictionary to the player script that would maintain the abilities the player has, such as the teleport ability, and also made the player flicker when the teleport ability was unable to be used. At the same time, I did this for the case of when a player isn’t allowed to change colour while moving through walls.

Figure 6: Teleporting demonstration in my Unity project.

The final feature this week I was thinking about was how the mechanic of collecting abilities would work. I settled on having game objects that would rotate through the y-axis and once the player collided with them, the objects would essentially disappear and the player would now possess the ability. I also had lots of thoughts back and forth on the logic of where things should be positioned.

private float rotationSpeed = 200f;

void Update()
{
    transform.Rotate(0f, rotationSpeed * Time.deltaTime, 0f);
}

Figure 7: Rotation code for the Collectible script.

The outcome of my thoughts was that the player would start in the safe, white mode, where enemies couldn’t hurt it, then pick up the green move-through-wall ability to the left, which would then make the player go into the green mode. When in the green mode, the player could attack and be attacked. Upon defeating a big green enemy, it could collect the green teleport ability, which would then allow it to teleport to the second part of the level.

void OnCollisionEnter2D(Collision2D collision)
{
    // Player upgrade events (via collectibles).

    if (collision.gameObject.CompareTag("Collectible"))
    {
        if (collision.gameObject == greenWallAbility)
        {
            Destroy(greenWallAbility);
            hasAbility["GreenWall"] = true;
            colorChange = new Dictionary<Color, Color>
            {
                { colorWhite, colorGreen },
                { colorGreen, colorWhite },
            };
            activeColor = colorGreen;
            render.color = colorGreen;
            gameObject.layer = LayerMask.NameToLayer("Player");
            runSpeed = 6f;
            typeR.SetActive(true);
            typeSpace.SetActive(true);
            whiteSafe.SetActive(true);
            return;
        }
    }
}    

Figure 8: Collectible ability code in the Player script.

My plan would be that you always collect the move-through-wall ability before collecting the teleport ability.

Figure 9: Collecting Abilities demonstration in my Unity project.

Next week, I will go over implementing shooting and damage mechanics, making some custom methods to make the code look cleaner, and finally, summarising my production so far.

Digital Arts Foundation—Final Project: Week 7 (Production)

In Week 7, I started looking for an example of an enemy script. I struggled a little on what to search for. Luckily, our Lecturer suggested a couple of phrases for me to try out. In his second suggested search, I found an ideal enemy tutorial:

Figure 1: Unity simple 2D Enemy AI Follow Tutorial (MoreBBlakeyyy 2022)

It took a while to get working, but eventually the enemies were moving towards the player, just like in the tutorial. It was then a case of implementing my idea of having different speeds for different colours. I was surprised at quickly I got this to work; due to the script being attached to each enemy, all I had to do was find the colour of the enemy, and change a single variable in the enemy movement code. The result was that different coloured enemies were moving at different speeds.

Figure 2: Enemies Approaching the Player in my Unity Project.

The hardest thing to do was to actually come up with a tidy calculation that would determine the speed based on the RGB values of the enemy. Fortunately, I found a simple solution. The RGB values had either Green, Red, or Blue set to 1, so all I had to do was a simple scalar product to assign them to the correct speeds. I wasn’t sure what the product would look like, so I did some testing on notepad first.

After some trial and error, I realised [3, 2, 1] worked if I just floored all the RGB values within the colours first.

My colours were [1, 0.25, 0.25], [0.25, 1, 0.25] and [0.25, 0.25, 1] for Red, Green and Blue, respectively.

0.25 floors to 0, and 1 floors to 1, so the resulting vectors are [1,0,0], [0,1,0] and [0,0,1].

For each of the resulting vectors, we then cross-multiply with [3, 2, 1] and sum the results, obtaining 3 for Red, 2 for Green and 1 for Blue. It’s then just a case of pairing the correct speeds with those outputs.

I also made sure the enemy stops moving towards a player that is white.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyScript : MonoBehaviour
{
    // Declare Enemy Physics/Movement Variables

    public GameObject Player;
    private Color enemyColor;
    private float calcColor;
    private float runSpeed;
    private Dictionary<float, float> enemyID = new Dictionary<float, float>();
    private float distance;
    private PlayerScript playerScript;

    void Start()
    {
        playerScript = FindObjectOfType<PlayerScript>();
        enemyColor = gameObject.GetComponent<SpriteRenderer>().color;
        calcColor = 3 * Mathf.Floor(enemyColor.r) + 2 * Mathf.Floor(enemyColor.g) + 1 * Mathf.Floor(enemyColor.b);
        enemyID = new Dictionary<float, float>
        {
            { 3, 3f },
            { 2, 2f },
            { 1, 4f },
        };
        enemyID.TryGetValue(calcColor, out runSpeed);
    }

    void Update()
    {
        if (playerScript.activeColor != playerScript.colorWhite)
        {
            distance = Vector2.Distance(transform.position, Player.transform.position);
            Vector2 direction = Player.transform.position - transform.position;

            transform.position = Vector2.MoveTowards(this.transform.position, Player.transform.position, runSpeed * Time.deltaTime);
        }
    }
}

Figure 3: Enemy Script

Next, I needed to make a collision event so I could trigger code (such as game over) when the player and enemy collide. I found it quite difficult to get it working. I needed to add colliders to both players and enemies, and add OnCollisionEnter2D(Collision2D collision) events. I added them in both player and enemy scripts. It still wouldn’t work.

void OnCollisionEnter2D(Collision2D collision)
{
    if (collision.gameObject.CompareTag("Enemy"))
    {

        // Game Over Event
        gameObject.SetActive(false);
        FindObjectOfType<GameManager>().GameOver();
    }
}

Figure 4: On Collision Event triggering Game Over.

One issue was I forgot the 2D part in the event, but the other thing was collision layers, which I eventually learned after googling. I found the Unity documentation on the subject; and then made sure the enemies were assigned with the enemy layer, and the player was assigned to the player layer.

Figure 4: Collision Layers

I made another layer for when it was white, which would not collide with the enemy, and adapted the player colour switching code to take that into account.

Figure 5: Collision with the Enemy triggering Game Over in my Unity Project.

Next week, I will look at implementing teleporting and conditionally moving through walls.

Digital Arts Foundation—Final Project: Week 6 (Production)

For week 6, the lecturer provided me with a useful tutorial from the DEV community to set up a basic game in Unity.

I ignored the player movement part, since that part was already done.

I followed the camera part of tutorial, and then googled various sites in order to adapt their script to 2D top-down. I eventually got the camera working with lots of testing.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraScript : MonoBehaviour

   // Making a public variable for Player.

{
    public GameObject playerDiamond; 

    private Vector3 offset;

    // Start is called before the first frame update.

    void Start()
    {
        offset = transform.position - playerDiamond.transform.position;
    }

    // Update is called once per frame.

    void LateUpdate()
    {
        // Make Camera match player's transform position.

        transform.position = playerDiamond.transform.position + offset;

    }
}

Figure 1: Camera Script that follows the player from overhead.

I changed playercube to playerDiamond, since it’s actually a diamond in my game, not a cube like in the tutorial’s. I also wasn’t sure if Vector2 should be used instead, but I think with my experimenting, keeping Vector3 made the code simpler.

Figure 2: Camera tracking the player in my Unity project.

The next stage in the tutorial was concerned with creating a game over screen. There were 3 steps involved: creating “Game Over” text that filled the screen; deactivating all the game objects for that screen; and constructing a way to reload the game.

There were numerous problems at every stage, but gradually I found solutions to the problems that came up. I think the tutorial was also slightly wrong, since it assigned a variable true, checked if it was true, and then assigned it to be true again inside the check. I could not see any other script that interacted with it, so I changed the first assignment to be false and then the check to look for false. The theory behind this is that it won’t execute more than once, which could possibly cause errors or slow down the execution depending on what code executed following the success of the check.

The tutorial showed me to put all the code inside a Game Manager script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

 public class GameManager : MonoBehaviour
{
    bool gamehasEnded = false;

    public GameObject Floor;
    public GameObject GameOverPanel;
    public GameObject Player;

    public void GameOver()
    {
        if (!gamehasEnded)
        {
            gamehasEnded = true;

            foreach (GameObject enemy in enemies)
            {
                enemy.SetActive(false);
            }
            Floor.SetActive(false);
            GameOverPanel.SetActive(true);
        }
    }

    void Restart()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
          Restart();
        }
    }
}

Figure 3: Game Manager Script.

I made the pressing down of the spacebar trigger restart, which just reloads the scene.

Figure 4: Game Over Screen in my Unity Project.

Next week, I’ll look at adding enemies and collision.

Digital Arts Foundation—Final Project: Week 5 (Production)

In week 5, I looked at a couple of in-program tutorials. The first was the Karting microgame. It helped familiarise me with the basic tools in Unity and how to publish a game. I also looked at the FPS microgame. It was also useful, this time teaching me more about moving the camera around in the scene view. While these tutorials were useful, they still didn’t really give me a good place to start.

Figure 1: Karting Microgame Preview (Unity 2023)

I asked a classmate where he started and he said he did player movement first, so I searched and found this tutorial (Stuart’s Pixel Games) on how to do simple 2D Top-Down movement. I copied the following code into a player script:

Rigidbody2D body;

float horizontal;
float vertical;

public float runSpeed = 20.0f;

void Start ()
{
   body = GetComponent<Rigidbody2D>(); 
}

void Update ()
{
   horizontal = Input.GetAxisRaw("Horizontal");
   vertical = Input.GetAxisRaw("Vertical"); 
}

private void FixedUpdate()
{  
   body.velocity = new Vector2(horizontal * runSpeed, vertical * runSpeed);
}

Figure 2: Player Movement Code (Stuart’s Pixel Games n.d.)

Once I put it in and attached it to a player game object with a rigid body, I noticed the player was drifting downwards. I simply had to zero the gravity value from the RigidBody2D and I now had basic movement.

Figure 3: Player Movement in my Project on Unity

For the final task this week, I decided to implement a feature that looked easy to do: changing colours with a key press. This is essentially broken down to a key press event, and then switching between multiple predetermined values. The two common ways to do the latter are either using a switch statement or going with a hash table approach, such as using key value pairs to determine the next value to switch to. I chose to do the latter as it looks tidier in my opinion and is something I’m more familiar with.

The Unity scripting reference API was useful in finding the information out. The pages GetKeyDown Event and Colors provide the information to create the function, while TutorialsTeacher provided information on C# dictionaries, which help with the organization.

    public Color activeColor;
    private SpriteRenderer render;
    private Dictionary<Color, Color> colorChange = new Dictionary<Color, Color>();
    public Color colorWhite = new Color(1f, 1f, 1f);
    private Color colorGreen = new Color(0.25f, 1f, 0.25f);
    private Color colorRed = new Color(1f, 0.25f, 0.25f);
    private Color colorBlue = new Color(0.25f, 0.25f, 1f);

 void Start()
    {
        ColorChangeSetUp();
    }


  void ColorChangeSetUp()
    {
        colorWhite.a = 0.75f;
        activeColor = colorWhite;
        render = GetComponent<SpriteRenderer>();
        colorChange = new Dictionary<Color, Color>
        {
            { colorWhite, colorGreen },
            { colorGreen, colorRed },
            { colorRed, colorBlue },
            { colorBlue, colorWhite }
        };
    }
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.R))
        {
            if (colorChange.TryGetValue(activeColor, out Color newColor))
            {
                activeColor = newColor;
                render.color = newColor;
            }
        }
     }

Figure 4: Player Colour Switching Code

The tricky parts were trying to get the right colours to display. It took me a while to learn how to generate custom colours using the “new Color” constructor.

Figure 5: Player Color Switching in my Unity project.

Next week, I will look at making a very basic working game.

Digital Arts Foundation—Final Project: Week 4 (Pre-Production)

For this week, our lecturer tasked us with summarising our pre-production by producing a milestone video. I thought about what I wanted to show: my plan document and the flowcharts. I also wanted to talk about the languages I explored in Week 2 and also my inspirations. I came up with the following document:

Figure 1: Finalized Plan of Final Project

It outlines my inspirations, as well as the game mechanics. I neglected to mention the blue/red/green rank concept was inspired by Mario Bros. , the arcade game featuring Mario and Luigi, where they bump enemies from below, and the spin-off of the Donkey Kong arcade game.

I’m big into Pokemon and I’ve played a battle mod where your inherit other abilities from the previous Pokemon you sent out. This led me to adapt the brief to something incorporating inheritance. I settled for gaining abilities of defeated enemies. As mentioned, I was also interested in getting past walls that you wouldn’t normally be able to get past, which features in many 2D games, including Mighty Switch Force and Mutant Mudds. The brief also strongly reminded me of The Legend Zelda on the NES.

Along with this document, I also wanted to present the flowcharts that I’d produced on Lucid Chart and link to an article that showed the benefit of making a 2D game on Unity as opposed to Unreal Engine. I found a comparison article here.

My final page of flow charts looked like this:

Figure 2: Page of Flow Charts

Once I had all these elements in place, I recorded my screen and did a commentary on my pre-production. I wrote a quick script that I could read from, and kept re-recording until I produced something of 2 minutes length, as per requirements, and that I was also happy with.

Figure 3: Pre-Production Milestone video

I realized after I forgot to make a proper theme and name for the game, and also summarise what the game was about. I was happy otherwise.

That concludes this week. Next week I will describe my exploration on Unity and start of my game, which will come under the first week of production.

Digital Arts Foundation—Final Project: Week 3 (Pre-Production)

For week 3, I mind-mapped my project with flowcharts, making pseudo-code that will help me once I enter production. I started out by describing the start of the game, the damage received, and the game over / restart sequence.

Figure 1: Game Start and Player Damaged on Lucid Chart (2023).

Next, I thought about all the key variables that I thought would need to be accessed in the game events to make the game flow. For instance, I planned three different types of enemies, and depending on the type, they were to be weaker or stronger; but at the same time, sharing the basic characteristics of an enemy. The variables indicate what specific code is needed execute to generate the desired differences in strength.

Figure 2: Enemy Variables on Lucid Chart (2023)

The final stage of making the flow charts was to add the events in the game. For example, I presented some approximate logic for player movement, such as changing the orientation of the player sprite, and also how the player interacted with walls. Other events included player and enemy attacking, and the points gained when defeating enemies.

Figure 3: Player Movement Function on Lucid Chart (2023)

That concludes week 3. Week 4 will look at the penultimate stage of pre-production, summarising my planning before exploring Unity in Week 5.

Digital Arts Foundation—Final Project: Week 2 (Pre-Production)

For my project in week 2, I looked into C++, which is used in Unreal Engine. I mainly went through the C++ section on W3Schools and completed the exercises where you have to complete the missing input. I found the cin and cout (C-input and C-output) concepts intriguing, as well as reference and pointer variables. I’d not come across anything similar in JavaScript, my main coding language, which I actually only script in, rather than program.

Figure 1: C++ Introduction Exercises (W3Schools 2023)

I also looked at the more complicated part, how C++ is used in conjunction with Unreal Engine. It certainly looked more intimidating, because of having to learn about its templates, its way of doing things.

Figure 2: Programming Quick Start Tutorial for Unreal Engine (Epic Games 2023)

I then went on to look at C# very briefly on W3Schools, the language used in Unity.

Figure 3: C# Tutorial (W3Schools 2023)

I found the syntax comfortable (and C++’s too), so I came to the conclusion I’d be comfortable working with either engine regardless of the language.

Due to my experience last semester and even before on gaming news websites, I knew that Unity was deemed the more natural choice for a 2D game, so I decided I would choose Unity and work with C#.

That concludes Week 2. In the next week, I will look at creating flowcharts to mind map all my code before using Unity.

Digital Arts Foundation—Final Project: Week 1 (Pre-Production)

Hi, my name is Jack Ralls.

I’m learning computer games programming in Solent University. I will be making a development log of my ‘final’ game project in the foundation year, which will detail my journey from pre-production to post-production.

In the 1st week, we were given a brief by our Lecturer. We were to make a 2D top-down hack ‘n slash computer game. The following were our requirements:

Figure 1: Final Project Brief (Solent University 2023).

I thought these requirements were a bit ambitious for a first game, but nevertheless I took on the challenge and came up with the following plan (between the first week and second week):

Level

2D-Top-Down with camera tracking the player and scrollable in every 2D direction.

Single level with a few different areas to explore some basic combinations.

Health

3 ranks of enemy: blue have 3 HP, red have 2 HP and green have 1 HP.
The player has 3 HP.

Attacks

The player has two attacks:

  1. A strong attack that deals 2 damage and activates twice as fast as the weaker one, but the player can’t move or attack following the activation/usage for a second.
  2. A weak attack that deals 1 damage with no recovery time.

The green enemy uses weak attacks.
The red enemy uses blocks and weak attacks.
The blue enemy uses blocks and strong attacks.

Movement (Translation) Speed

Player moves faster than the enemies, enemies move different speeds according to rank.

Abilities

There are 2 different types of enemy: one type can walk through walls of their colour and the other type can teleport to squares of their colour.
The player inherits their abilities by defeating them (reducing them to 0 or negative HP) and you can hold multiple abilities.
The player will able to swap between green, red and blue costumes with a key, which will tell the player which colour wall they can walk through or colour square they can teleport to.
There will be a teleport key and only one teleport square of each colour at most within the area surrounding the player, so there’s no ambiguity about which square they teleport to.
There will be icons to show that the player has acquired the ability to walk through walls or teleport.

The player has a default ability to hide (become translucent, stay in the same place, but not interact with enemies).

AI

???

Points

The Player receives 6 points for defeating a blue enemy, 3 points for defeating a red enemy and 1 point for defeating a green enemy.
If the player defeats all coloured enemies of one type, they gain 10 bonus points. If they defeat all coloured enemies of both types, they gain an additional 10 bonus points. (up to 30 bonus points)

I felt more motivated once I came up with my plan, but I recognized I had barely any programming experience in a gaming engine.

That concluded the first week. In the next week, I will continue to describe what I did in my pre-production.

Pokémon Legends Arceus: Progress #3: First 999 Research Task

Today I got my first 999 in a research task: Shadow Claw usage for Giratina.

I’ve now got 200 (24 to go) alpha species and 287 (36 to go) alpha forms; 78 shiny species and 89 shiny forms; 3 of my shinies are exclusively alpha, another I have in alpha and non-alpha.

62 of my entries are now perfected. I’m still on 35 paths of solitude completed. 19 of my species and 28 of my forms have a specimen maxed out.

If the lost and found record stats cap out easily, that will be my next post, else Giratina all 999ed, all alphas or perfect dex will be my next post.

Pokémon Legends: Arceus Progress #2: Max Research Points


Today, after 314:16 hours (pi hundred hours), I finally reached 99,999 research points. I have completed 100K’s worth of research tasks now out of 125.2K research points available, so I’m about 80% of the way through getting a perfect pokédex.

I have 190 species and 275 forms alpha; and 67 species and 75 forms shiny (legendary shinies are imported). 2 of my shinies are exclusively alpha, while another is caught both non-alpha and alpha.

54 out of 242 of my entries are perfect: all legendary/mythical. I’ve completed 35 of the paths of solitude and have 16 species and 24 forms with a specimen maxed out (level 100 and 10/10/10/10/10/10 effort levels).

The next post for this game will probably be either getting a perfect dex or collecting every alpha. See you then.