|
Post by Rod on Mar 21, 2021 19:59:44 GMT
I have been playing after Enzo got me interested in tile based RPG. I started with Cundo's idea of merging sprites but found that too limiting. I found that you can remove and replace the sprite image very quickly. So this displays a 640x640 screen and uses 11x11, 64x64 sprites. they overlap by 32 pixels to allow pixel by pixel movement. once they exceed the screen limits they are repositioned to the opposite side and the image is changed to whatever that map image is. I can use a huge map and many many tile images. The problem is that it is tedious to create a huge map. However it is possible and it moves well. Only 121 sprites are ever in play for the background. I only use a handfull of tile images to create this demo but hundreds of images could be used. It moves ok, i don't plan to do any more unless there is specific interest in improving the engine or adding additional functionality. It is just a display engine, the adventure code remains to be written! Rogue Tile Based Engine
|
|
andya
New Member
Posts: 14
|
Post by andya on Mar 22, 2021 16:27:44 GMT
Tile map is looking good so far, tiles are visually appealing and appear to be placed in a seamless fashion.
Just a quick question about the 'map.dat'. Is that like a 'directory' of the sprite tiles, and what is the format?
The other thing that I didn't see was the use of any sprite collisions. I'm guessing that's another function of the 'map.dat'. The reason I ask is because the player sprite can move up and down at will, but moving left to right will stop at vertical walls. So, how do you perform collision checking?
|
|
|
Post by tsh73 on Mar 22, 2021 16:39:53 GMT
Yaw cool. Let's look on a map...
open "map.dat" for binary as #map a$=input$(#map, lof(#map)) close #map
'print len(a$) w=30 'print w, w*w
dim k(255) l$=""
for i = 1 to len(a$) c$=mid$(a$,i,1) c=asc(c$) k(c)=k(c)+1 if c>9 then c$=chr$(asc("A")+c-10) else c$=chr$(asc("0")+c) end if 'now for some pseudographics src$="0H4312" dst$=" .|!=-" p=instr(src$, c$) if p then c$=mid$(dst$,p,1) else c$="*" 'everything else is corners end if l$=l$+c$ if len(l$)>=w then print l$:l$="" next
end 'these are freaquences just to see what's in the file for i = 0 to 255 if k(i) then print i, k(i) next '0..17
dummy$=input$(1)
|
|
|
Post by Rod on Mar 22, 2021 20:25:42 GMT
Well getting the tiles drawn was the first task. Collision will need improved. Currently if stella's sprite overlaps any sprite other than grass or pathway she stops. You can push her forwards with the up key till she is free. If she sits within grass or pathway she just keeps going. The map is just a X,Y map, square. It just contains the sprite number in the correct location. The sprites are named dun for dungeon then w wall c corner i internal corner followed by n,s,e,w or ne nw se sw for corners and finally path. They get loaded and given the map number in this order. loadbmp "i0","grass.bmp" loadbmp "i1","dunwn.bmp" loadbmp "i2","dunws.bmp" loadbmp "i3","dunwe.bmp" loadbmp "i4","dunww.bmp" loadbmp "i9","duncnw.bmp" loadbmp "i10","duncne.bmp" loadbmp "i11","duncsw.bmp" loadbmp "i12","duncse.bmp" loadbmp "i13","duninw.bmp" loadbmp "i14","dunine.bmp" loadbmp "i15","dunisw.bmp" loadbmp "i16","dunise.bmp" loadbmp "i17","dunpath.bmp" I am drawing some space ship tiles for a better demo. But it may take a while. Collisions, gameplay all still to be thought through. Any advice welcome. Any ideas welcome.
|
|
|
Post by Rod on Mar 22, 2021 21:08:06 GMT
Actually, I did start out trying to draw isometric tiles but got myself tied in knots with the graphics. I will eventually try isometric but I probably need to hunt out a tutorial or two. There is a demo in the files archive to study as well.
|
|
andya
New Member
Posts: 14
|
Post by andya on Mar 23, 2021 16:48:27 GMT
The map and movement look very well thought out and implemented, not to mention that you're a good artist or have good taste in picking out nice tiles.
The main reason I asked about the collision system is because, I am a proponent of using polygons to define boundary areas. Using those boundaries for the collision detection, takes about five calls to 'point in polygon' function. And if I recall correctly, that should take about 1/10,000th of a second.
Let me know if you are amenable to using polygons to define your tile boundaries. If so, I can knock up a simple demo using your tiles and Stella's sprite.
|
|
|
Post by Rod on Mar 23, 2021 20:36:59 GMT
Yes polygon collision is of interest. I have not thought it through just yet or tried any experiments. I am simplistically thinking 64x64 block collisions.
The problem, currently the map does not contain any data other than the image number. All of the data used for movement is contained in the spr(11x11) array, it is fed the image number as it is repositioned.
Stella only ever collides with the eight sprites surrounding her but that could be any sprite in play. No doubt she will collide with several sprites at once.
|
|
andya
New Member
Posts: 14
|
Post by andya on Mar 23, 2021 22:06:24 GMT
Well the good thing about polygon boundaries is that all you need is the sprite tile x/y coords (upper left corner) to check whether Stella has collided with the sprite boundary polygon. It sounds like a lot of work for very little benefit. However, after checking how fast JB can test for a point in polygon event, you can check 1,000 tiles per second for Stella collision.
I uploaded some jigsaw puzzles on the JB Archive site. They check every single jigsaw puzzle piece for the mouse position. In JB the practical limit is about 500 'point in polygon' checks per second for jigsaw pieces. The jigsaw piece polygons had on average about 40-60 vertices per polygon. I think that's going to be more than enough speed for the 132 tiles of lower vertex count polygons to check per frame update.
I'll see if I can work up a little sample version to show you that's it's not as bad as it sounds. Oh, I forgot to mention, that with the polygon boundary system you can have nearly any shape you want to check for collisions bypassing the 'Spritecollides' command entirely.
|
|
andya
New Member
Posts: 14
|
Post by andya on Mar 24, 2021 1:40:57 GMT
Here are the beginning steps of what's required to make this into a full polygon boundary system. 1) I made copies of 4 sprites without the masks, otherwise it would throw off the coordinates recorded by the 'Polygon Editor. Which makes defining all of the different polygons for your existing sprites a lot easier. 2) I made a small demo showing the polygons recorded by Polygon Editor on top of the 4 mask stripped .bmp's (dunine, duninw, dunise, dunisw). I imaginatively called the mask stripped .bmp's 'dunine_.bmp, duninw_.bmp, dunise_.bmp, and dunisw_.bmp (oh, well). Which you'll need to run the simple demo. [Note:] Currently displaying polygons in the sample, in the actual game these will not be shown, unless you want to show for debugging purposes. If after looking at the currently work flow, you're still game, there's more to do. Because, all of the hard work is making the polygons for your .bmp's (not really too bad, but time consuming if you have more than 121 different sprites to trace). The next step will be to devise a coding method that works for you. I usually number the polygons, 1 - 121 example, and store the poly information in arrays. This is the hardest part to design, but once done, you're nearly ready to start using the 'point in polygon' function to check for collisions with Stella and the game display. Here's the sample code: NoMainWin Global sw, sh scr = 3 Select Case scr Case 1: sw = 640: sh = 480 Case 2: sw = 800: sh = 600 Case 3: sw = 960: sh = 720 Case 4: sw = 1024: sh = 768 Case 5: sw = 1280: sh = 840 End Select WindowWidth =sw+8 WindowHeight=sh +32 UpperLeftX = (DisplayWidth-WindowWidth)/2 UpperLeftY = (DisplayHeight-WindowHeight)/2
Open "Sample polygons for rogue" For Graphics_nsb_nf As #g #g "Down; Fill black; TrapClose [xit]" d2r=Acs(-1)/180.0
Dim a(100,2),topx(4),topy(4), botx(4), boty(4)
LoadBMP "dne", "dunine_.bmp" LoadBMP "dnw", "duninw_.bmp" LoadBMP "dse", "dunise_.bmp" LoadBMP "dsw", "dunisw_.bmp"
'Draw some simple buttons to click on Gosub [makeButtons]
[repeat]
'=========================================================================== #g "SetFocus; when leftButtonDown [checkRects]" Wait '===========================================================================
#g "when leftButtonDown [xit]" Wait
[checkRects] mx = MouseX : my = MouseY 'loop through all rectangles in topx() and topy() arrays
'These are the offsets used to display the different bmp's and polys 'In actual use, they will be the same as your sprite x/y positions ox = 400 : oy = 400
For i = 1 To 4 'is the mouse in one of the rectangles? If pnr(mx, my, topx(i), topy(i), 100, 30) = 1 Then #g "Color black;Place ";ox;" ";oy;";BoxFilled ";ox+100;" ";oy+100 Select Case i Case 1: Restore [dunine] : #g "DrawBmp dne ";ox;" ";oy Case 2: Restore [duninw] : #g "DrawBmp dnw ";ox;" ";oy Case 3: Restore [dunise] : #g "DrawBmp dse ";ox;" ";oy Case 4: Restore [dunisw] : #g "DrawBmp dsw ";ox;" ";oy End Select Read numPoints Read varx, vary Read w,h For i = 0 to numPoints-1 Read x,y a(i,1) = x a(i,2) = y Next #g "Color yellow" k = numPoints-1
For j = 0 To numPoints-1 #g "Line ";a(j,1) + ox;" ";a(j,2)+oy;" ";a(k,1)+ox;" ";a(k,2)+oy k = j Next Exit For End If Next Goto [repeat]
[xit] Close #g UnloadBmp "dne" UnloadBmp "dnw" UnloadBmp "dse" UnloadBmp "dsw" End
[makeButtons] #g "BackColor 192 192 192" For i = 200 To 560 Step 120 #g "Color 80 80 80" #g "Place ";i;" ";50;"; BoxFilled ";i+100;" ";80 count = count + 1 topx(count) = i topy(count) = 50 Select case count Case 1: nam$ = "dunine" Case 2: nam$ = "duninw" Case 3: nam$ = "dunise" Case 4: nam$ = "dunisw" End Select #g "Color black" #g "Place ";i+30;" ";70;";\";nam$ Next #g "BackColor black" Return
Function pnr(px, py, rx, ry, rw, rh) '==================================================================================== ' Function "Point In Rectangle" '==================================================================================== ' This function checks to see if the point (px,py) is within the specified rectangle. ' ' If the point is inside the rectangle a value of 1 is returned. ' ' If the point is not inside the rectangle a value of 0 (zero) is returned. '==================================================================================== ' px = the X coord of the point in question ' py = the Y coord of the point in question ' rx = upper left X coord of rectangle ' ry = upper left Y coord of rectangle ' rw = width of rectangle ' rh = height of rectangle '==================================================================================== pnr = ((px>=ax) And (px<=(rx+rw-1)) And (py>=ry) And (py<=(ry+rh-1))) End Function
[dunine] '========================================================== 'Number of points used to define this polygon Data 18 '========================================================== 'x & y offsets to place polygon anywhere on screen Data 0, 0 'change to appropriate on screen coords '========================================================== 'width & height of the polygon's bounding box Data 64, 64 '========================================================== 'The 18 coordinate pairs are: Data 0,0,0,63,63,63,63,54,53,56,42,56,26,49,26,45,24,43,17,42 Data 11,38,8,31,10,27,7,22,6,16,7,8,8,7,8,0
[duninw] '========================================================== 'Number of points used to define this polygon Data 22 '========================================================== 'x & y offsets to place polygon anywhere on screen Data 0, 0 'change to appropriate on screen coords '========================================================== 'width & height of the polygon's bounding box Data 64, 64 '========================================================== 'The 22 coordinate pairs are: Data 63,0,63,63,0,63,0,55,9,55,20,57,21,55,28,54,33,51,37,49 Data 37,45,39,43,46,42,51,39,54,35,54,30,53,28,53,25,57,22 Data 57,9,55,7,55,0
[dunise] '========================================================== 'Number of points used to define this polygon Data 21 '========================================================== 'x & y offsets to place polygon anywhere on screen Data 0, 0 'change to appropriate on screen coords '========================================================== 'width & height of the polygon's bounding box Data 64, 64 '========================================================== 'The 21 coordinate pairs are: Data 0,63,0,0,63,0,63,8,54,7,48,6,41,8,33,9,30,12,26,13 Data 25,19,22,20,16,21,10,27,8,33,10,34,10,38,6,42,6,54 Data 8,55,8,63
[dunisw] '========================================================== 'Number of points used to define this polygon Data 21 '========================================================== 'x & y offsets to place polygon anywhere on screen Data 0, 0 'change to appropriate on screen coords '========================================================== 'width & height of the polygon's bounding box Data 64, 64 '========================================================== 'The 21 coordinate pairs are: Data 0,0,63,0,63,63,55,63,55,56,56,52,56,41,53,38,53,34,54,31 Data 52,25,46,21,38,20,37,18,36,13,33,12,28,8,21,8,16,6 Data 9,8,0,8 Here's the 'Polygon Editor' in use. Polygon Editor in use
sprite 1sprite 2sprite 3sprite 4
|
|
|
Post by Rod on Mar 24, 2021 9:25:18 GMT
Thank you, I have had a look. I can see that I could easily hold the polygon data for each object as part of the current 11x11 array, only adding new info from the file when a new image is loaded.
The question I have in my head right now is how do we go from point in polygon to polygon hits polygon? Obviously Stella is not a point, she would be a polygon too? Perhaps I am overthinking it. Stella's mid point would be the point? Or each direction has its own collision point for Stella?
Right now Stella will walk to a wall and stop. Left Right works ok, up works ok because she stops slightly into the wall which is ok from a perspective view. Down she goes too far into the wall to be believable. This is just 64x64 sprite to sprite boundary checking.
I can see that polygon checking of the sprite she is hitting will improve things. So find the sprite she is currently colliding with, get its polygon, get her directional point, then using point in polygon see if we have collided yet. So her directional point for up may be shoulder height, her directional point for down may be at her feet. Left and right just the edge of her body.
Interesting stuff.
|
|
andya
New Member
Posts: 14
|
Post by andya on Mar 24, 2021 15:37:21 GMT
Well, I'm glad you brought up the point (no pun intended) about Stella collision checking.
It turns out that if you define Stella as a five vertex polygon (just like the terrain sprites), you can avoid the polygon to polygon collision detection by using the same five points use to define her polygon as five single points, you can use the point in polygon function five separate times. This is actually faster than checking for poly-to-poly collisions.
So the five points are 1) apex of Stella's head 2) one point for each shoulder 3) one point for left and right outermost sides of her feet. Since you will have already defined her polygon in the 'Polygon Editor', you can read the five coordinate pairs from the data and Voila!, everything is set to go (well, for the terrain at least). As for small objects (coins, keys, knife, etc...), you can check the points defining the small object and use point in polygon to check for the points of the small object colliding with Stella's polygon (already defined).
The main question I have is; will you define polygons for the entire map (fewer number of polygons to define) or for each of the individual tiles (as I had assumed at first)?
The advantage of defining polygons for the entire map is that you will have fewer polygons to define and iterate through for collision checking.
The advantage for individual tile polygons is that you'll be able to re-use those polygons whether it's a static map or if you have a map editor for the user to make their own levels, at the expense of coding/data structure complexity.
It's just something you'll want to consider.
|
|
|
Post by Rod on Mar 24, 2021 18:32:08 GMT
In this implementation the tile drives everything. Each tile is autonomous even though they move in sync. So I am thinking tile based polygons and even then only a few tiles will need polygons as some will be complete no go areas, perhaps a square polygon?
I need (am building) a visual map editor because it is simply too tedious to hand craft a large map. There will be a bank of tile images that can be added to the map. The map still only needs to contain the image number for each location. In the engine I will need to read in the image and the polygon data to an expanded spr() array, so i need an array of polygon data that matches the available images.
The polygon data will then follow the tile as it remains in play. So again only 11x11 data in the array at any one time.
So the map may be 500x500, the images no more than 200 (could be a lot less with flip and mirror), polygons perhaps 100 but at any one time the game only ever has 11x11, 121 array elements to cycle through.
Working on my map editor and still drawing the first rough out of the spacestation tiles. Then on to collisions proper.
|
|
|
Post by Rod on Mar 24, 2021 19:12:00 GMT
This is where I am headed, click on the right window to select a tile then click in the left window to snap to grid. Eventually the map will page. You can draw 10x10 tile set quickly and it is easy to overwrite correct. If I had the time 1000x1000 tiles maps become possible!
|
|
|
Post by Enzo on Mar 26, 2021 20:55:04 GMT
I find it; certainly intriguing, that you can "blit" spritevisable render graphics faster then a image change, I believe, a long time ago I found this to work, however, just as you've done sprite images cannot be large, however this is the 20s folks! Computers are much faster.
May I suggest a very simple animation function? Static and moving?
|
|