Sign in to follow this  
vanroshr

Making a mario like game with level editor

Recommended Posts

Hello,

A complete newbie here.

 

So, I selected my project within 3 weeks as " Mario like game with level editor" for my college and can only use plain javascript and nothing else.

 

I have done some research and i  found that i have to make it on canvas.

My logic was to first create a json data and render the map from that and make it playable. Then make an editor where the user can drag and drop tiles which after finished creates a json data, from which the game can render from.

 

But, how do i start on this? Any guidance? 
How do i render the json and provide collision detection.
Also, how to let user create their own level and create the json data.

 

Help is much appreciated, Thank you! 

Share this post


Link to post
Share on other sites

There are some tough challenges there, the scope is very wooly for a college project but maybe you have plenty of time to crank it all out.

 

Learn to iterate through an array (you probably know how to do this) and use `JSON.parse` to convert your JSON into an array. In fact, I'd scrap JSON (dont worry about loading in data at this stage, its a complication you dont need, not at first anyway) and write the level data directly into your code.

 

Use a 2D array for your tile data, yes, this isnt a great use of resources and many things become a pain but it is simpler to get around first of all and you wont hit any of the problems of doing it like this.

var level = [  [ 1, 1, 1, 1 ],  [ 1, 0, 0, 1 ],  [ 1, 0, 0, 1 ],  [ 1, 1, 1, 1 ]]

This structure, as you probably know, will create a small room where 1's represent walls and 0's represent space. So, Mario can move around in the middle section but fires a collision if he tries to move to the edge tiles.

 

To render it you simply iterate over the array dimensions and render a tile (I'll use pseudo code that renders a block of colour)

var WIDTH = 4var HEIGHT = 4var BLOCK_WIDTH = 10var BLOCK_HEIGHT = 10for ( var x = 0; x < WIDTH; x++ ) {  for ( var y = 0; y < HEIGHT; y++ ) {    // x, y, width, height, colour    renderBlock( x * BLOCK_WIDTH, y * BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT, level[ x ][ y ] ? 'blue' : 'transparent' )  }}

Once you've got something like that (dont take it as gospel, there are numerous improvements or alternate ways to do it) rendering your tile map to the screen you're halfway there.

 

Add some code that also draws Mario.

 

Create a render loop that triggers regularly (SetInterval to 1000/60 will run at 60 FPS if the calcs can keep up, but using requestAnimationFrame is better) and render everything (it is likely your framework will optimise this if you use one, otherwise just render everything, unless your map is huge it probably wont cause issue).

 

Now add some code to move Mario. If you want per-tile movement then things are easy, but you'll probably want per pixel.

 

Now add collision code. If doing per-pixel then before you move Mario (before is important) then work out if he collides with any of the tiles, in the example here this involves getting each corner of the Mario sprite and test each corner against the tilemap, if it overlaps any 1 then a collision has occurred so abort the move, if its a 0 for each corner then move Mario. This could get trickier if you have to translate coordinates but thats part of the learning process—note that a framework probably has all this covered for you.

 

Now for the level editor.

 

Scrap drag-and-drop, too complicated at first. Have a list of tiles, onClick register that tile and then with each click in the tile map you'll have to do some coordinate shifting from screen space into world space and then update the `level` array with the new tile and re-render the tile map. Job done on basic level editor but maybe you'll want to save/load.

 

Converting to and from JSON is easy, you should know how to do this. Finding somewhere to save it is trickier, particularly as this is effectively out-of-scope for a front end project. But, you could really impress here. Simplest way is probably to save that data to local storage, so learn how that works. Then you'll need a system for getting levels in and out of local storage, and obviously you cant share these across browsers but it would be persistent in there across sessions. To share across browsers you really need to hit a server with POST and GET requests, this is definitely out of scope for a frontend project, but you could push it by dumping your level data to the console (or even alert) and let users copy-paste state—yes, I know this is fairly poop but 1) it works, 2) it shows you understand about creating data ready to save/load and 3) it does require additional out-of-scope services)

 

Good luck

Share this post


Link to post
Share on other sites

There are some tough challenges there, the scope is very wooly for a college project but maybe you have plenty of time to crank it all out.

 

Learn to iterate through an array (you probably know how to do this) and use `JSON.parse` to convert your JSON into an array. In fact, I'd scrap JSON (dont worry about loading in data at this stage, its a complication you dont need, not at first anyway) and write the level data directly into your code.

 

Use a 2D array for your tile data, yes, this isnt a great use of resources and many things become a pain but it is simpler to get around first of all and you wont hit any of the problems of doing it like this.

var level = [  [ 1, 1, 1, 1 ],  [ 1, 0, 0, 1 ],  [ 1, 0, 0, 1 ],  [ 1, 1, 1, 1 ]]

This structure, as you probably know, will create a small room where 1's represent walls and 0's represent space. So, Mario can move around in the middle section but fires a collision if he tries to move to the edge tiles.

 

To render it you simply iterate over the array dimensions and render a tile (I'll use pseudo code that renders a block of colour)

var WIDTH = 4var HEIGHT = 4var BLOCK_WIDTH = 10var BLOCK_HEIGHT = 10for ( var x = 0; x < WIDTH; x++ ) {  for ( var y = 0; y < HEIGHT; y++ ) {    // x, y, width, height, colour    renderBlock( x * BLOCK_WIDTH, y * BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT, level[ x ][ y ] ? 'blue' : 'transparent' )  }}

Once you've got something like that (dont take it as gospel, there are numerous improvements or alternate ways to do it) rendering your tile map to the screen you're halfway there.

 

Add some code that also draws Mario.

 

Create a render loop that triggers regularly (SetInterval to 1000/60 will run at 60 FPS if the calcs can keep up, but using requestAnimationFrame is better) and render everything (it is likely your framework will optimise this if you use one, otherwise just render everything, unless your map is huge it probably wont cause issue).

 

Now add some code to move Mario. If you want per-tile movement then things are easy, but you'll probably want per pixel.

 

Now add collision code. If doing per-pixel then before you move Mario (before is important) then work out if he collides with any of the tiles, in the example here this involves getting each corner of the Mario sprite and test each corner against the tilemap, if it overlaps any 1 then a collision has occurred so abort the move, if its a 0 for each corner then move Mario. This could get trickier if you have to translate coordinates but thats part of the learning process—note that a framework probably has all this covered for you.

 

Now for the level editor.

 

Scrap drag-and-drop, too complicated at first. Have a list of tiles, onClick register that tile and then with each click in the tile map you'll have to do some coordinate shifting from screen space into world space and then update the `level` array with the new tile and re-render the tile map. Job done on basic level editor but maybe you'll want to save/load.

 

Converting to and from JSON is easy, you should know how to do this. Finding somewhere to save it is trickier, particularly as this is effectively out-of-scope for a front end project. But, you could really impress here. Simplest way is probably to save that data to local storage, so learn how that works. Then you'll need a system for getting levels in and out of local storage, and obviously you cant share these across browsers but it would be persistent in there across sessions. To share across browsers you really need to hit a server with POST and GET requests, this is definitely out of scope for a frontend project, but you could push it by dumping your level data to the console (or even alert) and let users copy-paste state—yes, I know this is fairly poop but 1) it works, 2) it shows you understand about creating data ready to save/load and 3) it does require additional out-of-scope services)

 

Good luck

Thank you for the guidance.

I have done exactly like what you've said. Well most of it.

 

So, i first created a multidimensional array and rendered the map.

I simply made it like this,

 var map = [

                   [0,0,0,0,0,0,0],

                   [0,2,2,0,0,0,0],

                   [1,1,1,1,1,1,1],

                   .........

                   ];

1 representing platform, and 2's and 3's representing the coin and the mushroom boxes.

I made this variable global so that i can access it via any file.

 

Then , for collision detection what i did was first draw one tile then check for collision with mario.

Is this efficient or is there another way to do it?. This is where i was stuck like thinking its way too inefficient.

First Clear the canvas, 

Loop through the map array, 

draw one tile and check for collision, draw another tile and check for collision and so on.

Any thoughts on this?.

 

Then, for the level editor, instead of canvas i used table to make a grid, where every td represented a grid. Then just like u mentioned, onclick events to show the map.

I placed a generate map button, that then loops through that table and if there was something added to that cell then according to that data adds it to the array.

This array replaces the global array of the map , the above one, and then starts the game.

 

I have done till this. Now i have to implement saving the map the user created.

So, as u mentioned, do i make a json file of the generated array and save it locally ? 

If i save it in a json file, ill have to parse it again while starting the game right? .. 

 

Thank you :)  :)

Share this post


Link to post
Share on other sites

Yep, json is the way to go, technically you can actually stuff it into an ArrayBuffer (in modern browsers) and save it out as binary (this is a good use-case for doing so), but, you dont really want to get into that. More trouble than its worth here.

 

How are you proposing saving locally?

 

To turn your array (or any object) into JSON use

JSON.stringify( data )

and to switch it back from text (JSON is text) to an object (an array is an object in JS) do the inverse using

JSON.parse( data )

Some very old browsers do not support these methods, I'm guessing you're only supporting latest browsers? (its only IE6/7 that are a problem, I only mention it as a heads up).

 

If you're saving into local storage then use

localStorage.setItem( 'leveldata', JSON.stringify( data ) )

You must stringify as local storage only accepts strings (like JSON). To retrieve do the inverse

var leveldata = localStorage.getItem( 'leveldata' )

Note that again its only super old browsers that do not support local storage, but many polyfills/shim/libraries exist for working with different storage methods.

 

 

Regarding collisions,

 

I'm not exactly clear on how you're doing it but you certainly dont need to check every tile for a collision, only a local area around mario. So draw the tilemap, all of it, then draw your interactive, or sprite, layer, which is Mario, the goombas, anything that moves. This rendering is totally independent of collisions and should be in a separate game loop. When you get further down the line so that you have stuff like rendering, collisions, ai, lighting all competing for limited CPU cycles you'll be glad they are in separate loops where you might be able to get some control over how long each loop gets per frame.

 

You only ever need to check for a collision when something moves, and you'll want to stick to it because collision-detection can get expensive (a little bit at least). 

 

If we assume bounding box collision detection then things are a little easier, write yourself a function that checks each of the 4 points of the bounding box around Mario against the tilemap. If any of them are not 0's (0 is empty in your map right?) then a collision has occurred. Your function should probably return the location of the tile that Mario (or any entity) is colliding with, there are a number of implementations but you'll probably want to know where the collision occurred and between what.

 

In your case handling collisions is probably fairly simple, if Mario collided with anything then do not update his position. If your collision function returned all clear then update his position. You'll want to know what he collided with and work out what to do next, i.e. if he collided with a question mark block then you'll need to change it to a regular block and spawn a mushroom/star above it.

 

However, environment collision detection is fairly easy, particularly for a tilemap, as one part of the equation does not move. The other part  of your algorithm needs to consider entity vs entity collision, particularly when both are in motion. At its very simplest (and most inefficient, although in the case of Mario in a modern browser, even a mobile one, you're never going to get close to requiring optimisations) you'll need a function that tests for an intersection between 2 bounding boxes, then, in the case of Mario, get Mario's bounding box and loop through every other entity in your scene and check for a collision with its bounding box. The 2 simplest optimisations here are cache each entities bounding box and reduce the entity count. Note that one way of reducing entity count is to subdivide your scene into smaller regions and only test for collisions with entities in the same region as your moving entity (Mario), but, now its getting tricky.

 

Of course, you can go one step further and implement per-pixel collision detection if you like, but you'll probably want to do the cheaper bounding-box detection first anyway.

 

Also note that once you've done this once (so you understand it both practically and theoretically) there are numerous libraries to do this sort of thing for you! Or maybe you'll be able to do it better :) 

Share this post


Link to post
Share on other sites

@mattstyles

It's been almost a year since i posted this. 
I did finish that 3 weeks Mario project though. Thanks for your help. 
Here's the link if you want to check it out. 
I think it came out pretty nice :D


http://pratishshr.github.io/mario-maker/

I came back to html5gamedevs to check which framework would be good to work on a little fun side project I wanted to build.
As I searched, Phaser seems quiet nice but I think it isn't quiet good for making a native mobile game.
Also for the Multiplayer, I was thinking of hooking up a Node Server with Socket.io. 
Any thoughts? 
 Not the right thread to post this, is it? :rolleyes:

Share this post


Link to post
Share on other sites
8 hours ago, vanroshr said:

Not the right thread to post this, is it?

Ha ha, no, I think it warrants it own thread. Probably worth mentioning why you fear Phaser might not be suitable so peeps can either agree/disagree with your thoughts.

Glad you finished the project, finishing stuff up isn't easy.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.