Jump to content
IGNORED

RB+ Manic Miner :)


Recommended Posts

Ran into an issue last night regarding player movement and animation.

 

The player can move left and right no problem but I utilise a 16*16 bmp with 8 frames ( 4 for left and for 4 right ) and using a global frame counter I can cycle through the frames as required.... but it's way to fast.

 

Anyway to slow this down ?

SUB Player_Update_Position
    
	LOCAL LVAR_x%, LVAR_pad%
	
    LVAR_x=rgetobj(ID_player,R_sprite_x)  			' get player's current X position
    LVAR_pad=getpad(1)                           	' get PAD1 status (from U235)

	rlocate 100,80
	print "PLAYER DIRECTION ", player_direction, 
	rlocate 100,100
	print "FRAME ", GVAR_player_frame
	
    IF LVAR_pad=PAD_LEFT THEN						' was LEFT pressed?
		
		IF player_direction = 1 THEN
			IF GVAR_player_frame < 7 THEN
				GVAR_player_frame = GVAR_player_frame + 1
			ELSEIF GVAR_player_frame = 7 THEN
				GVAR_player_frame = 4
			ENDIF
		ELSEIF player_direction = 2 THEN
			GVAR_player_frame = 0
		ENDIF
		
		player_direction = 1
        
		IF LVAR_x<>(37<<16) THEN         			 ' already at far-left position?
            LVAR_x=LVAR_x-(1<<16)      				 ' subtract 1 from X-position
        endif
    
	ELSEIF LVAR_pad=PAD_RIGHT THEN               	 ' was RIGHT pressed?
		
		IF player_direction = 2 THEN
			IF GVAR_player_frame < 3 THEN
				GVAR_player_frame = GVAR_player_frame + 1
			ELSEIF GVAR_player_frame = 3 THEN
				GVAR_player_frame = 0
			ENDIF
		ELSEIF player_direction = 1 THEN
			GVAR_player_frame = 4
		ENDIF
		
		player_direction = 2
        
		IF LVAR_x<>(300<<16) THEN         			' already at far-right position?
            LVAR_x=LVAR_x+(1<<16)       			' add 1 to X-position
        ENDIF
	
	ELSEIF LVAR_pad=PAD_A THEN 						' was JUMP pressed?
		
		rlocate 100,120
		print "JUMP PRESSED"
		GVAR_player_is_jump = 1
		GVAR_player_x = rgetobj(ID_player, R_sprite_x)
		GVAR_player_y = rgetobj(ID_player, R_sprite_y)
		
    ENDIF
	
    'rsetobj(ID_player,R_sprite_x,LVAR_x)  ' store the new x-position
	
	RSETOBJ(ID_player, R_sprite_x, LVAR_x)
    RSETOBJ(ID_player, R_sprite_gfxbase, GVAR_player_gfx_loc + (GVAR_player_gfx_size*GVAR_player_frame))
	

END SUB                                     ' exit

Link to comment
Share on other sites

Raptor does have built in animation and speed for frames.

 

But if you need to roll your own then what i do is have a separate int and +1 whilst moving. Then only update your frames when that equals 3 (for example).

 

Great minds Sporadic, just implemented that in the main loop seems to do the trick at the moment.

 

Any recomendation on capturing a video of where i'm at - I tried using VLC but got very mixed results.

 

I want to implement jumping tonight and then i can post an .abs

  • Like 1
Link to comment
Share on other sites

Thanks for the offer CJ, what do you need ? just .abs and assets or the whole project folder.

 

WARNING : if the it's the whole project then no p*ss taking over the rats nest of code i've created so far :)

 

Although there's not much to see as i've not got the jumping working yet :(

  • Like 1
Link to comment
Share on other sites

Thanks CJ - that is way slower than when i run it on this here laptop though ?

 

Am I doing something wrong ? or is it the number of frames setting on the capture software.

 

Yeah I agree about overload but I want to make a completable level this way then I can at least point to it and say that's done now let's make it better :)

Link to comment
Share on other sites

Thanks CJ - that is way slower than when i run it on this here laptop though ?

 

Am I doing something wrong ? or is it the number of frames setting on the capture software.

 

Yeah I agree about overload but I want to make a completable level this way then I can at least point to it and say that's done now let's make it better :)

The emulator is usually faster than real hardware.

 

A quick win to save the slowdown and tearing would be to reduce the size of the particle layer. This is the transparent layer that the print commands and particles use. By default it is set to 320 by 240 px. You can make this smaller to reduce the amount of overdraw the downside being you can't show a full screen of text.

 

If you look in the rapapp.s file - scroll down a little and look for raptor_particle_buffer_height . Change that to 16. This will give you about 1 lines worth of text area. Remember to change any rlocate statements to 0 on the y axis though.

 

The print command itself isn't particularly fast either, so you could try commenting the frame counter out for now.

 

If all else fails, you are probably best doing as CJ suggested and using 1 large background image, a 2d array for collisions and then just use sprites for special cases like crumbling blocks etc.

 

Using lots of 16px wide sprites with an 8px image inside, when layed out next to each other, you are basically overlapping 50% of all the objects along every scanline.

 

These are the kind of things that can crop up developing on old hardware :D Keep at it though, it's all part of the jaguar learning experience :thumbsup:

Edited by Sporadic
  • Like 4
Link to comment
Share on other sites

you could use getpixel (which is documented around these forums somewhere) to retrieve the pixel colour of points around your player, if you have specific colours for the walls and floors like it looks like you have this can be used as 'you cant go any further in that direction'

 

i have started to turn this into a platform game engine i have put this on that back burner for some time though unfortunately

Edited by omf
Link to comment
Share on other sites

you could use getpixel (which is documented around these forums somewhere) to retrieve the pixel colour of points around your player, if you have specific colours for the walls and floors like it looks like you have this can be used as 'you cant go any further in that direction'

 

i have started to turn this into a platform game engine i have put this on that back burner for some time though unfortunately

 

That is actualy were I think i'm headed, we'll see though. I'm just happy to get something on the screen reacting to commands at the moment :)

 

Again - thanks for all the help, it's appreciated.

  • Like 1
Link to comment
Share on other sites

If I've been silent so far it was because I was testing some things. So...

First of all, I can see two options to gain performance out of this:

a) Use a single big backgrop object and all the movable parts as different objects (such as crumbly walls or animated stuff). This way you get a ton of OP processing time back
b) Keep using tiles-as-objects but add branch objects

Option b is a bit more advanced so I wouldn't recommend that at all. So let's go with a. The question of course would be "how to fill such an object"? Here I could just tell you to draw each map as bmp, pack them, import them into the game and unpack them per screen. But that's again a bit advanced and hassle-y. I'd only recommend that if your graphic artist would like to go wild and draw the level as a single thing, not as tiles.

The other option is, like you did, store the map as rectangular tiles into values inside an array. Then you can draw the map easily and check for collision and stuff using this. But again the question remains, how to fill the object?

That's why I sat down and created a mini project that does exactly this. Let me paste the code over and walk through it:

set maps[1000][20] as short
{0x0A,0x10,0x47,0x83,0x25,0x0A,0x48,0x83,0x82,0x00,0x83,0x85,0x47,0x01,0x01,0x01,0x01,0x01,0x01,0x01},

... snip 998 lines...

{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x1C,0x1D,0x1E,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}

end set

loadclut(strptr(tiles_clut),0,16)

dim x as short
dim y as short
dim c as short
dim tilex as short
dim tiley as short
dim map as short
dim i as int
DIM pi!: pi=3.1415926535897932384626433832795
dim ph!

for map=0 to 49
    ' Draw map
    for y=0 to 19
        for x=0 to 19
            c=maps[map*20+y][x]
            tilex=(c % 20)
            tiley=(c/20)
            for i=0 to 7
                lpoke strptr(scrbuf)+y*(160*+x*8+i*160,lpeek(strptr(tiles)+tilex*8+tiley*(160*+i*160)
                lpoke strptr(scrbuf)+y*(160*+x*8+i*160+4,lpeek(strptr(tiles)+tilex*8+tiley*(160*+i*160+4)
            next i
        next x
    next y

    'Bring the map to screen
    for ph=0 to pi/2 step pi/90/2
        rlist[1].x=(352-sin(ph)*336)*65536
        vsync
    next i
    
    'Pause so the level can be seen
    for i=0 to 255
        vsync
    next i

    'Send the object offscreen
    for ph=pi/2 to 0 step -pi/90/2
        rlist[1].x=(352-sin(ph)*336)*65536
        vsync
    next i


next map

First of all, the map itself. As you see it's stored inside the array maps, which is 20 columns and 1000 lines. If 1000 seems too big, it's just that I stored 50 levels one after the other. So maps[0][0] to maps[19][19] has the first map, maps[20][20] to maps[20+19][20+19] the second etc. You'll also notice that each line of the map is enclosed in curly braces, that's essential so the compiler can know how the map is dimensioned. Lastly that "0x" business before each value means that the value is in hex. You don't need to do that yourself, plain decimal values are ok. I used hex because the maps were taken off a game and they came in binary format (hex looks much more tidy). FWIW the maps and tileset I used were taken from a PD ST game called Lost world (which, incidentally, is a manic miner clone :)).

The most crucial part is that of map drawing. But to explain this I have to lay down some parameters first.

  • The screen object is a 320x200 buffer in 4bpp mode
  • The tiles are stored in a completely similar object
  • The tiles are 16x8 pixels each

 

post-10979-0-24593000-1490250961_thumb.png

 

 

So if you do some number crunching then you'll see that each tile is 8 bytes in width (16 pixels * 4 bits per pixel / 8 bits per byte. So we need to copy 8 bytes horizontally times 8 times vertically per tile. For this I used lpoke which copies 4 bytes in 1 go. Which means we'll need 2 lpokes for copying 8 bytes per tile's line. The innermost loop (for i ... next i) copies a tile from the tile map at coordinates (tilex,tiley) to screen coordinates (x,y). tilex,tiley coordinates come from the map's current tile value, and converted to position inside the map. i loops for as many vertical lines per tile.

 

The x and y loops simply iterate through the whole map.

Then the rest is just bringing the map object to screen, pausing, and then sending it away. I decided to do this in order not to show the map redraws which could be ugly (plus, this is the 64 bit powerhouse, let's show some big object movement there!). But if you notice I don't pause when the object is off screen but it seems that the map is filled up pretty quick (at least on vj :P).

So anyway that's mostly it. It shouldn't be too hard to convert to 8x8 tiles, just one lpoke per line would be needed and the offset calculation will need some adjusting but I trust people will get the idea! Full project will be pushed to the repositories right after I hit "submit" here :).

drawmap.abs

Edited by ggn
  • Like 6
Link to comment
Share on other sites

GGN - that's just showing off :) and I honestly can't get my head around it yet, but will download the project and have a butchers hook.

 

I went off on another tack last night and thought about doing as everyone said and using a background image and then having items that require interaction being an separate image.

 

I fell flat on my face at the first hurdle however.

 

I lashed up an image in paint that is 320*240 @ 4bpp but I clearly am still not understanding the rapinit.s format becasue the image does not fit/fill the display.

; Backdrop Object
	dc.l	1							; (REPEAT COUNTER) 				; Create this many objects of this type (or 1 for a single object)
	dc.l	is_active						; sprite_active					; sprite active flag
	dc.w	0,0							; sprite_x					; 16.16 x value to position at
	dc.w	0,0							; sprite_y					; 16.16 y value to position at
	dc.w	0,0							; sprite_xadd					; 16.16 x addition for sprite movement
	dc.w	0,0							; sprite_yadd					; 16.16 y addition for sprite movement
	dc.l	320							; sprite_width					; width of sprite (in pixels)
	dc.l	240							; sprite_height					; height of sprite (in pixels)
	dc.l	is_normal						; sprite_flip					; flag for mirroring data left<>right
	dc.l	0							; sprite_coffx					; x offset from center for collision box center
	dc.l	0							; sprite_coffy					; y offset from center for collision box center	
	dc.l	320/2							; sprite_hbox					; width of collision box
	dc.l	240/2							; sprite_vbox					; height of collision box
	dc.l	BMP_BACKDROP					        ; sprite_gfxbase				; start of bitmap data
	dc.l	4							; (BIT DEPTH)					; bitmap depth (1/2/4/8/16/24)
	dc.l	is_RGB							; (CRY/RGB)					; bitmap GFX type
	dc.l	is_trans						; (TRANSPARENCY)				; bitmap TRANS flag
	dc.l	320*240*2						; sprite_framesz				; size per frame in bytes of sprite data
	dc.l	320*2							; sprite_bytewid				; width in bytes of one line of sprite data
	dc.l	0							; sprite_animspd				; frame delay between animation changes
	dc.l	0							; sprite_maxframe				; number of frames in animation chain
	dc.l	ani_rept						; sprite_animloop				; repeat or play once
	dc.l	edge_wrap						; sprite_wrap					; wrap on screen exit, or remove
	dc.l	spr_inf							; sprite_timer					; frames sprite is active for (or spr_inf)
	dc.l	spr_linear						; sprite_track					; use 16.16 xadd/yadd or point to 16.16 x/y table
	dc.l	0							; sprite_tracktop				; pointer to loop point in track table (if used)
	dc.l	spr_unscale						; sprite_scaled					; flag for scaleable object
	dc.l	%00100000						; sprite_scale_x				; x scale factor (if scaled)
	dc.l	%00100000						; sprite_scale_y				; y scale factor (if scaled)
	dc.l	-1							; sprite_was_hit				; initially flagged as not hit
	dc.l	no_CLUT							; sprite_CLUT					; no_CLUT (8/16/24 bit) or CLUT (1/2/4 bit)
	dc.l	cant_hit						; sprite_colchk					; if sprite can collide with another
	dc.l	cd_keep							; sprite_remhit					; flag to remove (or keep) on collision
	dc.l	single							; sprite_bboxlink				; single for normal bounding box, else pointer to table
	dc.l	1							; sprite_hitpoint				; Hitpoints before death
	dc.l	0							; sprite_damage					; Hitpoints deducted from target
	dc.l	320/2							; sprite_gwidth					; GFX width (of data)

Any idea why that is incorrect ?

Link to comment
Share on other sites

So If i understand GGN's code correctly then the maps data is the start position of each graphic in the tiles bitmap.

 

And then he's grabing each byte from that start position and pokeing it onto the blank screen placeholder ?

 

And i would gues you could do build a collison map at the same time which would be used for checking current player position against ?

 

My head hurts :)

Link to comment
Share on other sites

That looks fine - 0,0 is the very top left of the screen - you need to use a relative offset. This is what I use for the ST ports:

	dc.w	17,0		; sprite_x			; 16.16 x value to position at
	dc.w	33,0		; sprite_y			; 16.16 y value to position at
  • Like 1
Link to comment
Share on other sites

when i set the x and y origin to 0 it's as above but if i set them to 20 as below the backdrop is displayed correctly.

dc.w	20,0							; sprite_x						; 16.16 x value to position at
	dc.w	20,0						; sprite_y						; 16.16 y value to position at

I'm sorry to ask what is probably a stupid question(s) but why is 0,0 not the top left of the screen ?

Link to comment
Share on other sites

when i set the x and y origin to 0 it's as above but if i set them to 20 as below the backdrop is displayed correctly.

dc.w	20,0							; sprite_x						; 16.16 x value to position at
	dc.w	20,0						; sprite_y						; 16.16 y value to position at

I'm sorry to ask what is probably a stupid question(s) but why is 0,0 not the top left of the screen ?

 

It's not a stupid question :)

 

0,0 is the top left. The screen isn't 320x200 :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...