|
Post by johnno56 on Oct 31, 2019 15:25:18 GMT -6
Hi n00b, Carrying on from your tutorial.... The attached example is a slightly modified version. As the current "map file" stands, I could only add up to 9 sprites, without having a weirdly formatted map file... lol Changes made: Changed the viewport from 320x200 to 480x224 Increased the map size to 224 x 14 tiles (3136 tiles) Added "sky" Added "large hills" only* Added a 'fake' player - reference only. Removal of "down" control Temp removal of "up" control Note: Even with the extra "if...then" loops there does not seem to be any noticeable reduction in performance. But, this could change... Advice and or thoughts would be appreciated. sidescroller.zip (13.93 KB) * current "map" format only allows for "single digit" number of sprites (0 to 9). Just the Hills, bushes and pipes will require about 30 individual sprites... At the moment, using single digits, the map is 448 characters long (224 space separated) I will try to use upper and lower case characters in the map file (that will give me an extaa 52 sprites)
|
|
|
Post by johnno56 on Nov 1, 2019 3:58:22 GMT -6
Update:
Switched reading the map file from numeric to string without a separating space. This should extend the number of sprites from 9 to 90. Two rows of 'ground', two sizes of 'hills', 3 sizes of pipes and 3 sizes of bushes, level size of 224 x 15 tiles... So far all by using 17 sprites... Long way to go before the level layout is finished. I'm hoping that 90 tiles will be enough...
I will update the above link when the layout is finished... I need more coffee...
|
|
|
Post by n00b on Nov 1, 2019 7:51:55 GMT -6
Hey Johnno, I just looked at it. It looks pretty good. I have a few tips that might be useful. For the video tutorial I used that simple format to make it easier to understand. Its not really ideal for a full game because it is only using a single digit. If you want to continue using it then I would suggest atleast modifying it to be able to use as large of a number as you want.
Changing the for loop to something like this would allow you to have as big a number as you want for tiles:
for i = 0 to Length(mario_map_line$) - 1 if Mid(mario_map_line$, i, 1) = " " then x = x + 1 else spc = InStr(mid(mario_map_line$, i, length(mario_map_line)), " ") If spc < 0 Then mario_map[x,y] = val( mid(mario_map_line, i, length(mario_map_line) )) i = length(mario_map_line) Else mario_map[x, y] = val( mid(mario_map_line$, i, spc)) i = i + (spc-1) End If end if next
Also, I should be able to post a video going over tilesheets today. Because I don't have to explain tiles or scrolling it should only be about 5 minutes.
|
|
|
Post by johnno56 on Nov 1, 2019 8:54:17 GMT -6
I had thought of using numbers with up to 3 digits but I couldn't figure out how to do it. So I went with lines of 224 characters. I know strings are not overly efficient, but when using one character per tile, it made for a neater looking map. Made it easier to figure out where everything fits... I will check out your suggested modification... but in the meantime... I have just finished setting up the level display. So far 37 individual tiles were needed. The program showed no sign of lagging... in fact, I had to slow the camera speed down to 1 pixel. (this version the speed is quicker so as to get to the end of the level...) I have also included (in the img folder) a complete level layout... It has an 'underground' section for collecting coins - not brave enough to tackle that one yet, lol) sidescroller4.zip (35.75 KB) ps: Versions 2 and 3 are on 'the cutting room floor'....
|
|
|
Post by johnno56 on Nov 3, 2019 3:14:33 GMT -6
"Can't wait to try it out once you add some collision and a jump button." lol... Me too...
I had my doubts about too many 'if...then's gumming up the works. So far it performs ok
If there is a question of 'treading on copyright toes' the graphics can be easily switched out for "free" images... Well, maybe not 'easily'... lol
I think, with tiles being only 16x16, AABB collision should be enough.. cough, cough, splutter... I'll start out with the basic four direction collision - I may have to consider adding a diagonal jump left and right collision as well - *gulp*
I am still rebuilding my machine at the moment... but RC is fully up to date and functional - ha. gotta love the priorities, right? Just finished installing Geany (with themes) - now to remember how to set it up for RC... lol
|
|
|
Post by n00b on Nov 7, 2019 12:59:18 GMT -6
Hey Johnno I added collision to your code. I tried not to not touch most of what you had but just add on to it. I also made lots of comments and outlined where my changes start and end. This has lots of room for improvement but it shows you how to go about tile-based collision. My changes start at line 158.
viewport_width_inPixels = 480 viewport_height_inPixels = 240
WindowOpen(0, "Mario - Demo", WINDOWPOS_CENTERED, WINDOWPOS_CENTERED, 640, 480, 1) CanvasOpen(0, viewport_width_inPixels, viewport_height_inPixels, 80, 120, viewport_width_inPixels, viewport_height_inPixels, 0)
Dim mario_map$[225, 15] Dim x Dim y Dim screen_x Dim screen_y
player_x = 48
ground = 1 loadImage(1,"img/ground.png") hill_large_1 = 2 loadImage(2,"img/hill_large/hill_large_1.png") hill_large_2 = 3 loadImage(3,"img/hill_large/hill_large_2.png") hill_large_3 = 4 loadImage(4,"img/hill_large/hill_large_3.png") hill_large_4 = 5 loadImage(5,"img/hill_large/hill_large_4.png") hill_large_5 = 6 loadImage(6,"img/hill_large/hill_large_5.png") hill_small_1 = 7 loadImage(7,"img/hill_small/hill_small_1.png") hill_small_2 = 8 loadImage(8,"img/hill_small/hill_small_2.png") hill_small_3 = 9 loadImage(9,"img/hill_small/hill_small_3.png") hill_small_4 = 10 loadImage(10,"img/hill_small/hill_small_4.png") bush_1 = 11 loadImage(11,"img/bush/bush_1.png") bush_2 = 12 loadImage(12,"img/bush/bush_2.png") bush_3 = 13 loadImage(13,"img/bush/bush_3.png") pipe_1 = 14 loadImage(14,"img/pipe/pipe_1.png") pipe_2 = 15 loadImage(15,"img/pipe/pipe_2.png") pipe_3 = 16 loadImage(16,"img/pipe/pipe_3.png") pipe_4 = 17 loadImage(17,"img/pipe/pipe_4.png") cloud_1 = 18 loadImage(18,"img/cloud/cloud_1.png") cloud_2 = 19 loadImage(19,"img/cloud/cloud_2.png") cloud_3 = 20 loadImage(20,"img/cloud/cloud_3.png") cloud_4 = 21 loadImage(21,"img/cloud/cloud_4.png") cloud_5 = 22 loadImage(22,"img/cloud/cloud_5.png") cloud_6 = 23 loadImage(23,"img/cloud/cloud_6.png") block = 24 loadImage(24,"img/block.png") castle_1 = 25 loadImage(25,"img/castle/castle_1.png") castle_2 = 26 loadImage(26,"img/castle/castle_2.png") castle_3 = 27 loadImage(27,"img/castle/castle_3.png") castle_4 = 28 loadImage(28,"img/castle/castle_4.png") castle_5 = 29 loadImage(29,"img/castle/castle_5.png") castle_6 = 30 loadImage(30,"img/castle/castle_6.png") castle_7 = 31 loadImage(31,"img/castle/castle_7.png") pole = 32 loadImage(32,"img/flagpole/pole.png") poleball = 33 loadImage(33,"img/flagpole/poleball.png") flag_1 = 34 loadImage(34,"img/flagpole/flag_1.png") flag_2 = 35 loadImage(35,"img/flagpole/flag_2.png") question = 36 loadImage(36,"img/question.png") platform = 37 loadImage(37,"img/platform.png") player_stand = 38 loadImage(38,"img/player/player_stand.png") player_left = 39 loadImage(39,"img/player/player_left.png") player_right = 40 loadImage(40,"img/player/player_right.png") player_up = 41 loadImage(41,"img/player/player_up.png") player_down = 42 loadImage(42,"img/player/player_down.png")
arcade20 = 1 loadFont(1,"fonts/arcade.ttf",20)
' Clear array for y = 0 to 14 for x = 0 to 223 mario_map$[x, y] = "" next next
' read map file - I hope f = freeFile FileOpen(f, "mario_map4.txt", TEXT_INPUT)
tst_map_line$ = "" y = 1 While y < 16 mario_map_line$ = Trim(ReadLine(f)) 'print left$(mario_map_line$, 60) x = 0 ' if mario_map_line$ = "" then ' Exit While ' End If for x = 1 to Length(mario_map_line$) mario_map$[x-1, y-1] = mid(mario_map_line$, x, 1) next y = y + 1 wend
map_width_inTiles = 224 map_height_inTiles = 14
tile_width_inPixels = 16 tile_height_inPixels = 16
viewport_width_inPixels = 480 viewport_height_inPixels = 240
viewport_width_inTiles = viewport_width_inPixels / tile_width_inPixels viewport_height_inTiles = viewport_height_inPixels / tile_height_inPixels
map_width_inPixels = map_width_inTiles * tile_width_inPixels map_height_inPixels = map_height_inTiles * tile_height_inPixels
camera_x_inPixels = 0 camera_y_inPixels = 0 camera_speed = 2
player = player_stand moving_left = False moving_right = False moving_up = False
'----------------CHANGES FROM ORIGINAL START HERE ----------------------------------------------------------------------------------
'---PLAYER COLLISION Player_World_X = 20 'This will be the x-coordinate of the player in the level Player_World_Y = 192 'This will be the y-coordinate of the player in the level
Function Check_Player_Collision(new_x, new_y) 'This function will take the player position and check if it collided with a pipe player_width = 16 player_height = 16 'The tile position of the top left corner of the player player_tile_x1 = new_x / tile_width_inPixels player_tile_y1 = new_y / tile_height_inPixels 'The tile position of the top right corner of the player player_tile_x2 = (new_x + player_width) / tile_width_inPixels player_tile_y2 = new_y / tile_height_inPixels 'The tile position of the bottom left corner of the player player_tile_x3 = new_x / tile_width_inPixels player_tile_y3 = (new_y + player_height) / tile_height_inPixels 'The tile position of the bottom right corner of the player player_tile_x4 = (new_x + player_width) / tile_width_inPixels player_tile_y4 = (new_y + player_height) / tile_height_inPixels 'The pipes are currently these characters: (, ), [, ] 'We will just check if the tile at the player tile position is any of these Select Case mario_map$[player_tile_x1, player_tile_y1] Case "(", ")", "[", "]" Return True End Select Select Case mario_map$[player_tile_x2, player_tile_y2] Case "(", ")", "[", "]" Return True End Select Select Case mario_map$[player_tile_x3, player_tile_y3] Case "(", ")", "[", "]" Return True End Select Select Case mario_map$[player_tile_x4, player_tile_y4] Case "(", ")", "[", "]" Return True End Select Return False End Function
sub render_player() if key(k_right) and (camera_x_inPixels + 1) < (map_width_inPixels - viewport_width_inPixels) - 16 then 'Check if the Player_World_X + camera_speed results in a collision If Check_Player_Collision(Player_World_X + camera_speed, Player_World_Y) Then 'There was a collision so we won't move the camera Else camera_x_inPixels = camera_x_inPixels + camera_speed Player_World_X = Player_World_X + camera_speed End If player = player_right elseif key(k_left) and camera_x_inPixels > 0 then 'Check if the Player_World_X - camera_speed results in a collision If Check_Player_Collision(Player_World_X - camera_speed, Player_World_Y) Then 'There was a collision so we won't move the camera Else camera_x_inPixels = camera_x_inPixels - camera_speed Player_World_X = Player_World_X - camera_speed End If player = player_left elseif key(k_up) then player = player_up elseif key(k_down) then player = player_down elseif not key(k_left) and not key(k_right) and not key(k_up) and not key(k_down) then player = player_stand end if '----------- These variables are pulled directly from the render_map function ----------------------- start_tile_x = int(camera_x_inPixels / tile_width_inPixels) start_tile_y = int(camera_y_inPixels / tile_height_inPixels)
start_tile_offset_x = camera_x_inPixels mod tile_width_inPixels start_tile_offset_y = camera_y_inPixels mod tile_height_inPixels '---------------------------------------------------------------------------------------------------- 'Calculating player_tile_x and player_tile_y based off what the Player_World_X and Player_World_Y is player_tile_x = Player_World_X / tile_width_inPixels player_tile_y = Player_World_Y / tile_height_inPixels 'This is pulled directly from the for loop in the render_map function 'x and y are replaced with the player_tile_x and player_tile_y screen_x = (player_tile_x - start_tile_x) * tile_width_inPixels - start_tile_offset_x screen_y = (player_tile_y - start_tile_y) * tile_height_inPixels - start_tile_offset_y DrawImage(player, screen_x, screen_y)
' if key(k_down) and (camera_y_inPixels + 2) < (map_height_inPixels - viewport_height_inPixels) then ' camera_y_inPixels = camera_y_inPixels + 2 ' elseif key(k_up) and camera_y_inPixels >= 0 then ' camera_y_inPixels = camera_y_inPixels - 2 ' end if end sub
'----------------CHANGES END HERE-----------------------------------------------------------------------------------
sub render_map() start_tile_x = int(camera_x_inPixels / tile_width_inPixels) start_tile_y = int(camera_y_inPixels / tile_height_inPixels)
start_tile_offset_x = camera_x_inPixels mod tile_width_inPixels start_tile_offset_y = camera_y_inPixels mod tile_height_inPixels for y = start_tile_y to (start_tile_y + viewport_height_inTiles) for x = start_tile_x to (start_tile_x + viewport_width_inTiles) screen_x = (x - start_tile_x) * tile_width_inPixels - start_tile_offset_x screen_y = (y - start_tile_y) * tile_height_inPixels - start_tile_offset_y
if mario_map$[x, y] = "1" then DrawImage(ground, screen_x, screen_y) elseif mario_map$[x, y] = "2" then DrawImage(hill_large_1, screen_x, screen_y) elseif mario_map$[x, y] = "3" then DrawImage(hill_large_2, screen_x, screen_y) elseif mario_map$[x, y] = "4" then DrawImage(hill_large_3, screen_x, screen_y) elseif mario_map$[x, y] = "5" then DrawImage(hill_large_4, screen_x, screen_y) elseif mario_map$[x, y] = "6" then DrawImage(hill_large_5, screen_x, screen_y) elseif mario_map$[x, y] = "7" then DrawImage(hill_small_1, screen_x, screen_y) elseif mario_map$[x, y] = "8" then DrawImage(hill_small_2, screen_x, screen_y) elseif mario_map$[x, y] = "9" then DrawImage(hill_small_3, screen_x, screen_y) elseif mario_map$[x, y] = "a" then DrawImage(hill_small_4, screen_x, screen_y) elseif mario_map$[x, y] = "b" then DrawImage(bush_1, screen_x, screen_y) elseif mario_map$[x, y] = "c" then DrawImage(bush_2, screen_x, screen_y) elseif mario_map$[x, y] = "d" then DrawImage(bush_3, screen_x, screen_y) elseif mario_map$[x, y] = "(" then DrawImage(pipe_1, screen_x, screen_y) elseif mario_map$[x, y] = ")" then DrawImage(pipe_2, screen_x, screen_y) elseif mario_map$[x, y] = "]" then DrawImage(pipe_3, screen_x, screen_y) elseif mario_map$[x, y] = "[" then DrawImage(pipe_4, screen_x, screen_y) elseif mario_map$[x, y] = "e" then DrawImage(cloud_1, screen_x, screen_y) elseif mario_map$[x, y] = "f" then DrawImage(cloud_2, screen_x, screen_y) elseif mario_map$[x, y] = "g" then DrawImage(cloud_3, screen_x, screen_y) elseif mario_map$[x, y] = "h" then DrawImage(cloud_4, screen_x, screen_y) elseif mario_map$[x, y] = "i" then DrawImage(cloud_5, screen_x, screen_y) elseif mario_map$[x, y] = "j" then DrawImage(cloud_6, screen_x, screen_y) elseif mario_map$[x, y] = "k" then DrawImage(block, screen_x, screen_y) elseif mario_map$[x, y] = "l" then DrawImage(castle_1, screen_x, screen_y) elseif mario_map$[x, y] = "m" then DrawImage(castle_2, screen_x, screen_y) elseif mario_map$[x, y] = "n" then DrawImage(castle_3, screen_x, screen_y) elseif mario_map$[x, y] = "o" then DrawImage(castle_4, screen_x, screen_y) elseif mario_map$[x, y] = "p" then DrawImage(castle_5, screen_x, screen_y) elseif mario_map$[x, y] = "q" then DrawImage(castle_6, screen_x, screen_y) elseif mario_map$[x, y] = "r" then DrawImage(castle_7, screen_x, screen_y) elseif mario_map$[x, y] = "s" then DrawImage(pole, screen_x, screen_y) elseif mario_map$[x, y] = "t" then DrawImage(poleball, screen_x, screen_y) elseif mario_map$[x, y] = "u" then DrawImage(flag_1, screen_x, screen_y) elseif mario_map$[x, y] = "v" then DrawImage(flag_2, screen_x, screen_y) elseif mario_map$[x, y] = "?" then DrawImage(question, screen_x, screen_y) elseif mario_map$[x, y] = "#" then DrawImage(platform, screen_x, screen_y) end if next next ' camera_x setcolor(rgb(255,255,255)) font(arcade20) DrawText(str(int(camera_x_inPixels / 16) + 16),0,0)
end sub
while not key(k_escape) ClearCanvas ' Draw Sky and or clouds first.... setColor(rgb(92,148,252)) RectFill(0,0,479,239) render_map render_player ' Viewport Border setColor(rgb(255,255,255)) Rect(0, 0, 479, 239)
update wend
|
|
|
Post by johnno56 on Nov 7, 2019 14:38:20 GMT -6
Wow! That is SO cool...
Initial analysis (in a nutshell) is: You have converted a graphical 'hitbox' around the player and translated that to its 'map' equivalent?
To add extra "obstacles", all I would have to do, is modify the "characters" in 'Check_Player_Collision() function'?
Of course, the collision works as it should... My incentive now is, if I want to 'see' the rest of the map, I had better get cracking on the 'jump' and 'gravity'... lol
You have done a brilliant job in solving my problem! Much appreciated...
|
|
|
Post by johnno56 on Nov 9, 2019 13:41:45 GMT -6
Ok. Where do I begin?
I found a simple, well - not so simple, 'simple' in operation... A jump routine created by Marcus from Naalaa...
I only checked it out because it looked more 'natural' than the standard 'leap up and drop' routine... Enough of the description... That is not my point...
It uses, the equivalent of getPixel(), to detect the "floor" beneath the player... Remember. Only checking it out. May not use it... lol... In a nutshell - it didn't work... I allowed for the increasing downward velocity; included the height of the player; I even created a "single coloured" floor to land on... But, every time, the player fell through the floor....
Solution was found!
Simulating the same way the game is displayed - within a viewport - using just 'sky' and 'ground' I eventually found a problem in my calculations. When using a viewport, and wanting to DrawText() in the upper left corner of the 'port', - DrawText(string,0,0) did the job... as it should... But, when you want to use getPixel(), to use for collision, the detection's "origin" is the '0,0' of the actual main canvas... Oh, this little gem took me some hours and several coffee's to figure out 'that' one....
Don't panic. I don't think I will use the getPixel() method... I just wanted to point out that getPixel() does not seem to conform to viewports like DrawText() and DrawImage()... Oh, n00b, your 'detection system tracks the 4 coordinates of the player's hitbox corners with no apparent effect on performance... I was expecting getPixel() to 'slow things down', as it is not the most efficient method, but it didn't. Either my game, at present, is not "busy" enough for getPixel() to impact or machines have enough 'grunt' to overcome that problem... just a thought...
I am still researching a jump method but won't have much time today to check it out... Will try again tomorrow...
ps: I still have the original sdlbasic conversion of Marcus's jump. If you want to check it out, let me know and I'll post it, but it will require some conversion to RC...
|
|
|
Post by johnno56 on Nov 13, 2019 14:18:21 GMT -6
Just finished watching the video. Mathematics and I have 'never' been on good speaking terms... but, never the less, I watched it to completion. When all those formulae popped up on the screen I was sorely tempted to 'fast forward' but resisted the urge and pressed on... lol
To me, the double jump, made no sense. A normal jump has an initial velocity. Vertical motion occurs because the base on which the player is standing is of sufficient mass to either absorb or deflect the force the player is exerting. Part way through the initial jump, a second jump is initiated, and the player is projected even higher. In what universe does 'open air' have sufficient mass to allow the player to exert the same, or slightly more force, so as to project the player to a new height? ('Slightly more' because the player has already begun to be effected by gravity to a point that the downward velocity of the player is increasing. More force would be need to overcome the motion.)
The code at the end looked interesting. The first 'standard' code is what I am used to, mainly because until recently, TBird had implemented a 'delta time' function. I'm still trying to get my head around that one... but it works quite well. I must see if I can use the second method, compare the two, then choose based on results...
Many thanks for the link. I found it interesting. Scary, but interesting... lol
|
|