top of page
Search

Its Super Mario (Clone) time!

Writer's picture: Adam HouseAdam House


Type: Private product

Genre: Platformer/ Sidescroller.

Engine: Unity.

Released: July 2nd, 2024.


Want to play this game? hers the password: SMC85 and click here https://adamh5.itch.io/supermariocloneadamsversion


Normally I prefer not making clones of games that already exist on shelves and I also prefer making something original that sets itself apart from similar games, however, it wasn't until recently that I found an online course that contains a Mario Clone tutorial by Awesometuts on Udemy.


Originally I started with the Mario Clone lecture (and some other lectures) in the course expecting to learn familiar Super Mario mechanics that are part of the norm of Sidescrollers like coyote time and responsive jumping (the longer the key it held, the higher the jump) for one of the upcoming original games I planned, unfortunately when I found out the game idea would be too complicated for this time round and the responsive jumping mechanic was nowhere in the Mario Clone lecture, I scrapped it and left it too rust in my computer and started with my other projects.


Until recently, I thought: What if the project could help me strengthen my game design, programming, and Level design skills? So I started to get back on the course and proceeded to complete the Mario Clone lecture.


After I completed the lecture, I was unsatisfied with the end result since the project had bugs, unfair difficulty, and unpolished mechanics. So I decided to take roughly more than a month to fix these issues as much as possible without making a full game with many levels since it is not a game I would make money by selling on Steam or Itch.io, that’s why I only made 1 level, used the only sounds in the package rather new sounds, and just generally focused on Quality instead of Quantity.


On the bright side: I learned a lot about managing sprites and Side scroller mechanics, It isn’t the first time I have prototyped a side-scrolling game, but it is the first time I started building the side-scroller game on my own except for the art assets are not mine and I was taught by AwesomeTuts which gave me a head start on building the game.

I was originally going to have it displayed only as a practice project which is unplayable by the public and only displayed on my Portfolio, but because I put so much work and effort into it, I thought of having it as a private product so only certain people can play my game and give me constructive criticism.


I don’t exactly know who made the original sprites and other assets, but I was provided by AwesomeTuts for the project.


WHAT WENT WELL?:

  • I managed to have little bugs in my game. Some bugs I had to let go like the player going stuck in between edges of snail shells and tree trunk edges because they weren’t too severe since this is not a full commercial game. At least the game does not crash or break mechanics to cause it to be unplayable for the Player.

  • I managed to stay organized with prefabs this time making folders with different sets of them like Lego bricks. E.g. “Ground” folder contains prefab sets “4x1 ground”, “1x1 Ground with 1 Trunk”, and “1Tree_2x1Ground_1Stump_1flower”. This made finding the exact prefabs for the level easier.

  • I successfully managed to put up a camera collider that stops the Player from going backward just like the original Mario games without the collider pushing other game objects with physics such as enemies and powerups. However, the Player's fireballs do collide with the camera collider on purpose.

  • I successfully used a public enum that I called “Item” which allows me to select which powerup the Player gets by jumping underneath the Bonusblock, by default I set it to “coin” which is self-explanatory and gives the Player coins. I figured most of the Bonus blocks in the game would give the Player coins.

  • I managed to make the Player lose the ability to throw fireballs upon enemy collision after the Player gets the Fireflower just like in the original Mario games.

  • Managed to get the game to freeze for a few seconds and play at normal speed in an instant. This is done when the Player has run out of lives and than falls off the level yet again just like in the original Mario games.

  • I set public bools such as “downfirst” and “FlipYDirection” to tell the spider to go down first and to flip its Y position sprite each direction it changes respectfully. If down first is false, it goes up first. This allows me to add character to each spider and to add challenge to the Player with its AI behavior.

  • Managed to get the spider to only die when the Player jumps on it and is also midair, so if the spider comes underneath the Player on the floating blocks, it will damage the player and still move up and down as normal.

  • I fixed a bug where if the Player hits underneath the Bonusblock and stays colliding there, multiple powerups will instantiate. Since the bug fix, only one powerup instantiates no matter how fast the Player hits the Bonusblock underneath.

  • I coded a mechanic where if the Player falls under a certain limit based on his/her Y.transform.position, the camera will stop following the Player, the Player movement script is disabled, play game over audio plays, and then restarts the level without using colliders to cover the empty pits where the Player can fall from.

  • I have made Player and Enemy scripts a bit tighter with being alive or not. If the enemy or Player is dead, they cannot respond to anything else from the code, for example when the Player dies and gets thrown back falling off the screen: he/she can not collect powerups, Though I did leave the Player accidentally falling on Beetle than bouncing off it while falling off screen because I thought it was a funny harmless glitch that didn't break the design or gameplay. Another example is birds won't drop eggs if already killed by the Player and the Player also cannot bounce off snails or beetles if already jumped on or died respectfully.

  • Creating the script for the Snail was a real challenge because it needed to execute code for not only the Snail itself, in its shell form but for the Beetle that shares the same script.


WHAT I LEARNT:

--Sprites--

  • Using the sprite editor to cut out the sprites I want and animate them in a new animation clip. While also changing samples of each animation for the player from 60 to 12 FPS to animate very similar to the 8-bit style.

  • Flipping Sprites X and Y by code (not transforms).

  • Changing Order in Layer in inspector by code (like Photoshop layers).

  • Can enable the sprite's sprite renderer on and off without turning off the Parent game object.

  • Getting the world width and height than divide them together with Main Camera Orthographic Size and divide them again with Screen height times screen width which are the screen size in screen space of the game view. Then scales the width and height of the background a little bit to match the full aspect of the camera frame.

  • Having fewer sprite sheets reduces the game's memory use.

--Player--

  • Using Yield return new WaitForSeconds inside a For loop with some public variables to make the Player flash a certain amount of times and time before the next flash every time the Player has been hit by an enemy. If the enemy attacks the Player while still flashing, the Player will not lose health unless flashing has stopped.  

  • To add velocity on the Player going upwards after jumping on the enemy's head like in the original Mario games.

  • Able to Fire fireballs from the Player by instantiating at Quaternion identity from one transform.position and set the scale.x +1 or -1 depending on which direction the player is facing.

  • Getting and Setting the Movement speed value of the fireball script to be multiplied with the PlayerShoot script on transform.localScale.x from where the fireball is instantiated.

  • Velocity is speed over time for the Player's movement since we are adding speed to the player on inputs.

  • Changing the Player's sprite facing direction based on whether the Player is moving left or right with changing the X-Axis leaving the Y-Axis on the Rigidbody untouched.

  • If storing temp variables is not done correctly for Player movement directions, you will get an error telling you to store a temp value.

  • Converting the Players anim speed with Math.abs into an int to then convert it into the rigidbody x-axis movement either left or right depending on which direction the player is facing.

--Enemy's—

  • For the Boss, using an IEnumerator to not take damage from Players' fireballs for a certain amount of time once hit by one until time is up and can be damaged once again, repeating the process again until it's dead.

  •  Can use the “SendMessage(MethodName)” method to deal damage to the target (Player) propertie of OnCollisionStay2D who collides with the Boss while still alive.

  • Can change the Player RigidBodyType into dynamic along with turning on its BoxCollider2D trigger so the Player can fall through the level when lost all his/her health.

  • Using Vector.3 up and Vector3.down for the Spider as private variables to determine where the spider climbs first depending on the direction it's set too. Also to change directions in a certain time by a public variable.

  • Creating Collider2D’s with a Pyshics2D sphere from each position, size radius, and which layer for enemies to detect player collision depending on where the position.transform is placed. For e.g 1 Collider2D on each left and right side of the snail detects and damages the Player while moving. But the collider2D collision on top of the snail is its weak spot, which if the Player jumps on it, it goes into its shell and stops moving.

  • Experimented how powerful the Layer mask detection public variable is when detecting different layers of game objects such as which enemies are affected by the Snail shell after it was kicked by the Player.

  • Able to make a Snail shell be kicked by the Player after he/she jumps on its shell all in Snail Script, just like with the Koopas in the original Mario games. This is done by rigidbody velocity.

  • Creating RaycastHit2D detection on the Snails from the front and behind the snail while also using Vector2.left  and Vector2.right respectfully detecting from a small distance and only the Players collider with the Player damage script. If The Snail is moving, it damages the Player, but if inside its shell after the Player jumps on it, it gets kicked in a direction depending on where the Player kicks it from and does not damage the Player unless the shell comes back towards the Player.

  •  Able to check if the enemy has the appropriate functions to execute certain code. For example, the Beetles share the snail script with the Snails, if the Beetle has a Beetle tag, it will execute certain code, unlike Snails that go in their shells after the Player has jumped on them, the Beetles instead get squashed and die instead when jumped on the Player. 

  • Able to get the Snails and Beetles to change opposite directions if it doesn’t detect any ground from on the edge or collides head first with walls and other enemies (Snails,Frogs and Beetles,) respectfully. These use Transform. positions each with short raycasts and bools for detection. Birds also have one raycast but it is to raycast infinity down to check if the Player is below them before dropping the egg damaging the Player if hit.

  • For the Bird, I was able to instantiate the egg from the Bird gameobject without an empty transform variable. Only instantiated – y position underneath the bird.

  • Able to get the bird to change directions with If statements if the Bird moves too far from its original position and change move direction both by Vector3’s.

  • Able to change the x.scale (-1 or +1) of the Bird depending on which direction the Bird is facing.

  • Can change the Bird rigidbodytype2D from kinematic to dynamic in code once the player jumps on Bird's head. This causes the bird to fall down.

  • The Frog is a child of its parent transform, I managed to code for the parent transform position to move to its child position to move the frog forward with every single jump it has made.

--Camera—

  • Camera options Aspect: gets the aspect ratio of the camera. Orthographic: gets half the size of the camera.

  • Able to code a camera script that determines the size of the collider for the camera and then resizes the collider for the bounds using a Vector2 for the Main camera’s aspect times the main camera OrthographicSize.

  • The variable “Bounds” represents the Axis aligned to the bounding box of the sprite background.

  • Able to get the camera following the player by first storing the Player's last transform position, then offsets the camera following the Player's current position on the Z axis.

  • Able to get the camera to not move back with a Vector3 whenever the player turns around and tries to go back rather than forward.

  • Vector3.SmoothDamp moves along the Vector3 to its end position smoothly. It takes 4 refs for player position, current position, current velocity, and camera speed.

  •  The Ref method parameter keyword is to refer to the same variable that is passed into another method. Basically, currentVelocity variable is a ref and will be changed while the camera is moving and storing it there to follow the Player. So if the Player is too far from the camera, the camera will move fast smoothly towards the Player until at its current position and continuously moves behind the Player.

  • Screen.height is the current height of the screen window in pixels while Screen.width Is the current width of the screen window in pixels. These are the actual screen sizes in the screen space of the game view.

  • World space canvas are best for 3D games, not 2D games.

  • Anchors are really important to anchor UI that will adjust to different screen sizes so Players can see the UI easily and clearly.

  • Rect transform is the UI equalivent to the Vector3 transform.

  • 100 pixels is 1 unit for the camera.

  • Screen space: The camera allows you to render in the camera view.

  • Scale With Screen Size: match width and height will closely match with the resolution with Reference Resolution.

  • Screen space Overlay: Will overly the canvas on the screen space. Used to position in UI elements.

  • The higher the number of sorting layers, the order of the game object sprites and text will be rendered first to last.

--Other/misc--

  • Calling Coroutines by public strings rather than by public function names.

  • Creating Physics2D.OverlapCircles by code to determine what position it starts at, its radius, what layers to detect to do things like damage Player, activate bonusblocks, and Player to detect if on the ground.

  • Using concatenation (converting int to string) for updating the Player score. Updating text from code like “coinTextScore.text = scoreCount;” won't work. However concatenations like “coinTextScore.text = scoreCount.ToString();” and “coinTextScore.text = "x " + scoreCount;” will work as intended.

  • The code outside of If statements will be executed regardless of If statements above are true or false.

  • Yield return new WaitForSecondsRealtime allows for the countdown to happen in real-time even when Timescale is 0 (when the game is frozen). It is independent of Timescale.

  • How I can set Bonusblocks from a start and end position to move up and back down to the start position smoothly by transform.translate, bools, and  If statements once the Player has hit underneath it without moving it by animation.

  • Able to use parameters in code to determine each OneShotAudio audio clip volume rather than relying on the Audio source volume in the inspector.

  • FixedUpdate is good for calculating physics and rigidbody code, however, there are times it may need to be executed in an Update function.

  • Fixedupdate won't be called as often as the Update function. This compares to the Update function which is called in 60 times in 60 frames per second.

  • GetAxis and GetRawAxis. - Raw means whole number like 1. - GetAxis(not Raw)takes time to get to be a whole number in decimals. - GetAxisRaw goes to 1 as soon as the input has been pressed.

  • Z axis is not used for 2D game objects, only 3D game objects.

  • Localscale is a vector 3.

  • How I can freeze 2D rigidbody constraints such as the X position by code.

  • SmoothDeltaTime: Smooths out Delta time

  • Collider components work differently between 2D and 3D, This includes their respective rigid bodies.

  • Kinematic is not affected by gravity but is affected by physics such as applying force.

  • Rigidbody and transform don't usually match up well together.

  • The list of scenes in the build is actually an array list.

  • 1 in animation speed = 100 in Unity.


WHAT WENT WRONG AND WHAT COULD I HAVE DONE BETTER?:

  • I didn’t organize the code to be cleaner and easier to read. I was full speed ahead testing different codes until one of them worked mostly for the Snail script because it was complex to act like a Koopa shell in the original Mario games, detecting edges, changing directions, dying by Players' fireballs and being hit by Snail shell including each enemy and Player in the game that respond upon collision. I need to stop at an appropriate moment, clean up code, and make comments to reduce running like a headless chook finding the right code I need to edit and make changes before I make catastrophic mistakes to the game.

  • I couldn’t add the Player Jump sound because I already programmed that you can hold the jump key to bunny hop without pressing the jump button each time you are on the ground. When you jump and the jump sound is played, the jump sound plays almost 3 times in a row each jump in a OneShotAudio which is annoying, I tried to change the input type so you not holding the jump button to keep bunny hoping and you hear the sound once each jump. Still, it leads to some unknown animation issues. I decided to let it go with no sound and hold the Jump key to bunny hop because if I changed it, I would have to redo the entire Player movement mechanic all over again. So next time when I’m making a platformer, I will start with the press once each jump with sound played mechanic.   

  • I couldn’t program a mechanic when two snail shells (after the Player kicks both of them) ram together they both die, I couldn’t figure out why it wasn’t working, but it didn’t help that I did not clean the code to read better, so I decided not to include a game moment where the player can actually collide two snail shells together. I need to stay in the habit of making comments above code, clean code to read, and not repeating the same code in different lines but only one function.

  • I had to get certain pairs of ground tiles and mid-air blocks to share one collider before I had each tile have its own collider, but for some reason, it stopped the player in its tracks despite having a physics material. If I am going to have tiles with colliders snap to each other like Lego bricks, I need to make sure it has the intended mobility for the Player without stopping him/her for no reason.

  • Regarding the lack of sounds, I could have found royalty-free sounds to fill the gaps of missing sounds like shell impact, or Player shoot fireballs, but since this project was more of a side project than a commercial one, I decided to let the sounds go and use the ones that were given to me by AwesomeTuts.

  • I tried to swap two detection transforms left and right whenever the Snail turned directions, but the detection transforms just went elsewhere and nowhere near the Snail, so I just simply left them there not to be switched around, and just simply flipped the sprite which did not affect the detection transforms.

  • I would think its best for the Frog to jump forward using velocity like how the Snails and Player use velocity to move, jump, and push away rather than using moving animations, that way I can easily control how far and high the frog jumps and if midair by the time player jumps on its head, it can just fall down midair like the bird does rather than go back to its previous landing position squashed and died.

  • I could have made one of the Bonusblocks respawn a Fireflower at the Boss area so the Player can continually fight and kill the Boss, but that ended up being very difficult to do, so I had to let it go.

  • I could have text feedback like 1Up like in the original Mario games to tell the Player they got an extra life after collecting a mushroom so they know rather than just guess what happened when they first play the game.

  • Could have had checkpoints around the level to reduce punishing difficulty for the Player, but it would have been extra work and yet again this was a practice product, not a commercial game, so I will keep that in mind next time I create a sidescroller/ platformer.


OVERALL:

  • Even though Sidescrollers and platformers are not my cup of tea and I prefer not to make clones of existing games. I’m still happy with the end result that I did the best I could to loosely replicate a Mario game from the assets given to me and taught respectfully. Someday I want to make a sidescroller runner, so this was a good start to learning Sidescroller mechanics to make a similar game in the future.

  • It was also good to warm up my level design skills, I needed to do that so I am prepared to organize prefabs of set tiles so it's easy for me to find and use them.

2 views0 comments

Recent Posts

See All

Comments


bottom of page