News:

Building a 3D Ray Tracer  By stevmjon

Main Menu

Long shot: Mario clone

Started by LemonWizard, April 08, 2011, 06:50:16 AM

Previous topic - Next topic

LemonWizard

Well, I decided after a few years of really wanting to put together something that could at the very least stand up to the nes games...

In my insane quest to rebuild a version of mario world (If anyone remembers for the snes?)

I've analyzed alot of the mario world stuff but have yet to understand how it all ticks internally.
That said I have more expertise in nes games and how they work (mappers and all) and a little bit of assembly in nes code.

So...

Obviously we have better tools at our disposal. AKA Playbasic.
Lately I've been tinkering around with editors and various GUI stuff. You might have seen a few of my other recent posts.
So here it is. A screenshot. DER Yay!!! Basically it's a screenshot of what's to come and the WIP.
I'm not distributing the code at the moment but right now it is not playable it is in the editor status.

The plan:


To revamp the entire code once I have a base down, optimize etc.
To create a sprite/layer system and a map system that isn't so primitive and then go about creating a functional object system which can handle all the in game objects and sprites.
Of course, along with the map system I need a decent collision system. One that can handle slopes (And believe me that will come)

Uh.. the reason I'm doing this is mostly for learning purposes (OH THAT AND IM DETERMINED TO GET WAY BETTER AT THIS!!)
And now that I have the time..you know.. temptations rise. Curious minds flow.. hehe

So HERE IT IS!!!


And a little tidbit

Once the tile system and engine is done it will feature two or three layers :

FG-able to scroll independently on a vertical and horizontal axis and still handle collision detection with sprites and other tiles
BG- same as FG only allows player to walk on it.
BG2-scrolling, without collision or alternatively second BG layer.. it will be expandable though.

For now btw.. i will share one tidbit of code.
This is the function that handles the map drawing (Dynamically) so that any tileset and map system (including layers) can be used
I currently have the function hardcoded to only handle two map layers.
It's quite large but if anyone has any suggestions on how it could be improved let me know (Please note the Hscroll and Vscroll are taken into account)


PlayBASIC Code: [Select]
function draw_level(layer, width, height, tilelist(), maparray(), tileheight, tilewidth, vscroll, hscroll)

for tempx=1 to width
for tempy=1 to height

size=getarrayelements(tilelist(), 1 )

imagenumber=maparray(layer, tempx, tempy)
if imagenumber>0 ;don't try to access the tile if the image doesn't exist
if imagenumber<990
mask=getimagemaskcolour(tilelist(imagenumber) )
W=(tempx-1)*tilewidth
H=(tempy-1)*tileheight
W=W+hscroll ;horizontal scroll
H=H+vscroll ;vertical scroll
if mask<> rgb(0, 0, 0)

drawimage tilelist(imagenumber), W, H, 0
else
DrawAlphaImage tilelist(imagenumber), W, H, 0.75, 0
endif
endif
endif
next tempy
next tempx

endfunction





LemonWizard

Ok so just a few things I've started on a GUI system, after expanding the tile selection system
Now there are two modes. Mode 1 is editing the map. Mode 2 is editing tile properties.
All that's left is to expand the tile properties options IE : slide collision, breakable, ice physics, etc...

Well here's the screenshot of the improvement. It's not much but it is some nice eye candy I guess. might need a better GUI system later on but I plan on organizing the editor into neat little pages you can maximize and minimize.


kevin

#2
 The map draw routine is ok, but there's a lot of redundant code inside the inner loop.   For routines with high repetition such as this,  it's well worth culling any unnecessary calcs out of those inner loops.    

PlayBASIC Code: [Select]
function draw_level(layer, width, height, tilelist(), maparray(), tileheight, tilewidth, vscroll, hscroll)

// query size outside of loop
size=getarrayelements(tilelist(), 1 )

// Plot rows by columns
for tempy=1 to height

; Calc the Y offset here, since it's the same across the row
H=(tempy-1)*tileheight
H=H+vscroll ;vertical scroll

W=hscroll

// Move in along X axis
for tempx=1 to width

imagenumber=maparray(layer, tempx, tempy)

if imagenumber>0 ;don't try to access the tile if the image doesn't exist
if imagenumber<990

; you can get rid of this access by using a look up array.
mask=getimagemaskcolour(tilelist(imagenumber) )
if mask ;<> rgb(0, 0, 0) don't need the <> compare here
Drawimage tilelist(imagenumber), W, H, 0
else
DrawAlphaImage tilelist(imagenumber), W, H, 0.75, 0
endif

endif
endif

; Bump the X coord
W+=tilewidth
next tempx
next tempy
endfunction



 You could most likely make some extra gains by removing the call the get the image mask for each tile and replacing it with an array look up table,  as I suspect the array would be quicker than the function call.   The same probably goes for with the drawImage/DrawIMageAlpha selection.  Rather than poll the MASK and react according to the Mask value.  You can pre-calc this in a look up array.    

 Some the inner draw could look like this.

PlayBASIC Code: [Select]
  ThisImage=tilelist(imagenumber) 

DrawAlphaImage ThisIMage, W, H, ImageAlphaLevels#(ThisIMage), 0




The array ImageAlphaLevels would be make something like this (assuming the tile blocks are image numbers 1 through to 100 say)

PlayBASIC Code: [Select]
  Dim ImageAlphaLevels#(100)
For lp=1 to 100
Mask =GetImageMaskColour(lp)
if Mask <> rgb(0,0,0)
Alpha#=1
else
Alpha#=0.75
endif

ImageAlphaLevels(lp)=Alpha#

next




I'm not too sure why you're emulating the scrolling registers though.   It's far easier to build everything in world space and let the camera do the work.  The mapping stuff could be drawn with PB's built in maps.. but anyway.  
 

For stuff like the collisions, there's often only a few block types required for such games.  Solid block, 45 degree left, 45 degree right.  For the 45 degrees types the Y coord is basically a reflection of the X cord over the block.


PlayBASIC Code: [Select]
   Setfps 100

// ---------------------------------------------------------------------
// ----------------->> CREATE COLLISION MAP TILES <<-------------------
// ---------------------------------------------------------------------

global TileWidth =64
global TileHeight =64


Cls 0
Tri 0,TileHeight,TileWidth,0,TileWidth,TileHeight
getimage 1,0,0,tilewidth,tileheight

Cls 0
box 0,0,tilewidth,tileheight,true
getimage 2,0,0,tilewidth,tileheight

Cls 0
Tri 0,0,TileWidth,TileHeight,0,TileHeight
getimage 3,0,0,tilewidth,tileheight

for lp=1 to 3
preparefximage lp
next


// A row of collision map
Row$="0001222230000"

Xpos=100
CenterY=getScreenHeight()/2
Do
cls


c1=$337799
c2=$554422
Shadebox 0,CenterY,GetScreenWidth(),GEtScreenHeight(),c1,c1,c2,c2

DrawRow(Row$,0,CenterY-TileHeight)

// Calc the Ypos of the Play as it's current X coord

Ypos=CenterY-TileHeight
TileX=Xpos/TileWidth
// grabg the tile from the string
CollisionMapTile=Mid(Row$,TileX+1)-asc("0")

Select CollisionMapTile
case 0
; Blank tile
Ypos+=TileHeight

case 1
; 45 degree slope from RIGHT up to LEFT
Xoffset=((TileX+1)*TileWidth)-Xpos
Ypos+=Xoffset

case 2
; solid tile

case 3
; 45 degree slope from LEFT down to right
Xoffset=Xpos-(TileX*TileWidth)
Ypos+=Xoffset

endselect


// Draw PLayer as line
Linec Xpos,Ypos,Xpos,Ypos-TileHeight,$00ff0000

Speed#=2

if LeftKey() and Xpos>0
Xpos+=-Speed#
endif

if RightKey() and Xpos<GetScreenWidth()
Xpos+=Speed#
endif

Sync
loop



Function DrawRow(s$,Xpos,Ypos)

For lp=1 to Len(S$)
ThisIMage=Mid(s$,lp)-asc("0")
if ThisIMage
drawimage ThisIMage,Xpos,Ypos,0
endif
Xpos+=TileWidth
next
EndFunction





 

LemonWizard

Thanks for the tips kevin. :P Always appreciated.

I cleaned up the code a bit as well. Now I have another surprise.
Just to show that the engine itself will later be able to import any tileset, and set properties up.

I made a nice looking map using zelda tiles in the editor.
Here's showing off :P

kevin

 Nice enough... You're running this on V1.64K2 ? - How very 2010 :)

LemonWizard

Yeah, I don't know if I have the update for this.
speaking of which uhh do I have to buy a new update for playbasic or can I just have the update since I payed for the full version already? Just wondering. I know this is totally un related.

kevin


LemonWizard

Well, nothing new coded yet and that's because I realized if i want this to be a success I need a few rips.

Uhh unfortunately every single spritesheet I look at is a mess and can't be loaded in on a grid since NOTHING is grid aligned.
I cleaned up some sprites from a sprite sheet, this took me almost 3 hours... of which time was heavily dedicated to sprite alignment perfection.

Initial sprite offset: 1 pixel X, Y
Initial offset after every sprite: 2 pixels X and Y
Notes:

Sizes are
16*16
19*16
21*16



And here, is the current complete spritesheet of normal mario. I haven't included his swimming animations yet.

If anyone at all has any ideas on good methods to be used for coding the input with sprite animation and movement then please contribute. I need all the help I can get with this project.



kevin


Animations go hand in hand with the character state or mode if like, so the characters have states and animation sequences that go with each state.   

So when we press left to walk, we move the character left and play the Left sequence of walking frames.  To play them we're just stepping through the sequence, and cycling back to first when it hits the end. 

While not really related to animation, there's a couple of other Mario demos on the boards.  Another Mario Demo  - Which as it turns out is in the top five most downloaded examples on PlayBasic.com