Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Newcomers DBPro Corner / tile engine scrolling problem

Author
Message
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 12th Aug 2011 20:46
I'm trying to make an Ultima 1 style tile game map where your character stays in the middle and the map basically moves underneath him.

I want the character to move one tile at time, not smoothly scroll. It is supposed to be like very early PC games.

I know that you are supposed to have a 2D "peephole" (viewport, camera, whatever you want to call it) that only draws the tiles that the player can see. That makes sense as you don't want to have to draw the entire map every cycle.

That is also the part I don't understand how to do. I can't figure out the logic behind it even though I have seen examples. I think I am making things too hard.

Please help, but explain what you did so I can understand it. I don't want to just build off of somebody else's code if I can't understand it.

I included a big map that loads correctly as far as I know. The fps are limited to slow things down. If it's too slow just change the sync rate. I know that is not the correct method. It's just a temporary kludge.

The graphics are temps.

Thanks.

Attachments

Login to view attachments
Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 12th Aug 2011 23:22
Hopefully this example can help you out. I commented best I could but just let me know if something didn't make sense.



Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 13th Aug 2011 00:07
Thanks so much! I am going to have a look at this just as soon as I run some errands. I'll post an update on my progress in this thread.

Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 13th Aug 2011 06:34
Okay, I was able to update my code so that it does at least work.

My update is below. It is an example of a rudimentary tile engine with images and it shows how to load a simple map. You can scroll along and there are boundary checks to prevent the user from going outside the map array. Timer movement hasn't been implemented in my version so it'll really zip around.

I will work on tile collision over the weekend and see how far I get. That will be a good test of whether I understand what you wrote. I think I may have confused myself with the way I named variables.

As an aside, I am not sure I understand 100% the difference between paste sprite and paste image. They both seem to do the same thing?


Grog Grueslayer
Valued Member
19
Years of Service
User Offline
Joined: 30th May 2005
Playing: Green Hell
Posted: 13th Aug 2011 08:43
Quote: "As an aside, I am not sure I understand 100% the difference between paste sprite and paste image. They both seem to do the same thing?"


The difference is that PASTE IMAGE will always stay the same but PASTE SPRITE will change if you change the sprite itself. Like if you used SCALE SPRITE, STRETCH SPRITE, SET SPRITE DIFFUSE, SET SPRITE ALPHA, ROTATE SPRITE, or the other sprite commands that change the way the sprite looks the changes will be seen with PASTE SPRITE.



And it's ok to use FOR/NEXT loops for loading images and setting up sprites.



Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 13th Aug 2011 18:13
Hmm..

Since sprites can do more, why not make everything a sprite? In testing pasting all my terrain as sprites vs. images didn't seem to affect FPS. Is there a downside?

I'll look at your code a little later today and see if I understand it. I have some more errands to run. Oy!

Thanks everyone!
Grog Grueslayer
Valued Member
19
Years of Service
User Offline
Joined: 30th May 2005
Playing: Green Hell
Posted: 13th Aug 2011 21:22
I forgot to mention in that last message that I liked what you've done so far. Keep up the good work.

It's bad to make everything a sprite... things like grass tiles and anything else that isn't going to move shouldn't be sprites. You really only want to use sprites for weird effects and/or characters/bullets that'll use the sprite collision commands.

DVader
20
Years of Service
User Offline
Joined: 28th Jan 2004
Location:
Posted: 14th Aug 2011 05:14 Edited at: 14th Aug 2011 05:17
I don't think it makes any difference if you use paste image or paste sprite in all honesty. If you just use sprite it would make a difference of course, as it is constantly updating each one.

Strangely enough I have been working on a Shining force/Zelda style game myself over the last few days, albeit with smooth scrolling (in the game, in the editor it scrolls grid style as you were asking for. It is actually easier to do than the smooth scroll, as you don't need to step through inbetween grid tiles).

As far as using sprites in the game I will be using them for characters, effects and some scenery items. Some scenery is best handled in the map of course, say fences or bushes etc. I would mainly use sprites for things that can change, such as a hidden cave or a bush you can interact with etc. Anything that is static, try to get into your bacground image(unless you need any fake 3d depth, if so sprites are more useful).

The main problem I have had so far is the sheer number of sprite frames required for my needs. I have 2 characters in with a basic walk and run anim. Because it has 8 possible directions, I needed 5 sets of anim data for the walk anim, each between 18 and 30 frames long. One for each possible angle, and mirroring the ones I can get away with for the other 3 directions. The same again for the run anim. The result, 470 frames of animation for 2 anims, and 2 characters.

A lot of work you will agree I am sure. It makes you appreciate 3D, and the fact two objects could do the same job with far less code. Still I appreciate my Flashback style (sort of ) sprite anims far more than doing it in simple 3D.

Good luck with your project, mine will probably amount to nothing more than a demo, as this does need so many graphics, and I hate having to do much graphics work!

Edit - Oh by the way my game is full screen, you don't need a border of any kind. You just place the tiles that are updating, one tile beyond the screens edge.

http://s6.bitefight.org/c.php?uid=103081
Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 14th Aug 2011 06:00
I started a zelda-clone awhile back, original NES version. Fortunately for me, it was only 4 directions and only 2-3 frames for each direction.

Ashingda 27
16
Years of Service
User Offline
Joined: 15th Feb 2008
Location:
Posted: 14th Aug 2011 08:15 Edited at: 14th Aug 2011 08:42
@Lost Dragon
The most efficient way to use the sprite statement is to only use one sprite and only to actually draw it's image pointer to the screen. Having a lot of sprites slows down the program greatly. The difference between paste sprite and paste image is that paste image does not cause a slow down no matter how many images are loaded into memory but the usage of alot of sprites will slow down your program greatly.

The solution to this problem is to only use one sprite to draw all your images.



The reason of using this method in the first place is for the sole purpose of using the sprite modification command that comes with it. Here are some of the useful ones with example.




***************************************************

I dont know if you care for optimization yet but here's a very quick example of using bitmap to greatly speed up the fps rate on your last working posted codes. This is only a small part of the optimization but still creates a big difference. This portion of the speed boost works best when there isn't much going on with the background map.




The three changes made are here so you dont have to go digging for it.

Directly above the MainLoop:


The Player's added "DrawMapFlag = 0" to the keys:


Bitmap commands added to the drawmap() function:




Attachments

Login to view attachments
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 14th Aug 2011 18:54
Thanks everyone. I am reading the thread with much interest. I will post my results in a few days - hopefully with some simple tile collision.

I will check out the optimizations too. The difference in FPS between the two techniques is certainly significant!

The differences between "paste sprite" and "paste image" are also a little more clear now.

I admit that 2D is a lot of work on the graphics side. I actually already have over 400 tiles drawn for this project (no joke). It's easier for me to draw tiles than it is for me to program, so when I get stuck I draw tiles. I get stuck a lot.

I want the program to work though, so I'm going to keep plugging away at it.
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 19th Aug 2011 21:05 Edited at: 19th Aug 2011 21:06
Sorry for the delay. I had to build another computer and get it all set up. Now it's working and I'm back to this.

Okay, I also had to play a lot of Team Fortress 2 to make sure the new video card was working properly. Testing is important. Yeah..

Anyway...

My simple tile collision:



It took me a while to figure out how to get the tile value from underneath the player. I kept wanting to use the screen's center value without taking into consideration the offset.

Player_X/Player_Y have now been renamed to Center_X and Center_Y to better describe what they really are.

I'm using the code above to handle simple collision. It checks to see if the player went on a "blocked" tile (any tile with a higher number than 7) and if so it moves the player back where he was. Now the map is more navigable and we're a little closer to old-school tile map flavor.

Oddities occur when the player reaches a map boundary. The player can still see more map, but since he is at the array's boundary the map won't scroll farther and so the player can't move to the edge. I can either design the map to take this into account or I can set up special cases in the code where the player can move all the way to the edge if he is near a boundary. It would probably be better to do the latter as I want the game to support several screen resolutions.

So that is something for me to work on. My collision method may change too if I decide to go to Ashingda 27's method for the huge speed increase. I was trying to keep it simple while I learn, hoping that things could be rewritten as I understood them later.

Since I can tell what tile a player is over I can do other special events besides collision - like teleporting, sound effects, and etc. A long string of "if tile=59 then hurt_player" style code sounds unwieldy though so there must be a better way to handle it. I don't want to have to keep a big list of tile numbers and have to remember things like "tile 59 is lava". That isn't intuitive.

I may be getting a little ahead of myself there though. Next I should probably look at figuring out a better way to slow the game down than what I'm doing now, which is a kludge.
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 19th Aug 2011 23:20 Edited at: 19th Aug 2011 23:20
I'm sort of using this thread as a development blog. Maybe I shouldn't do that. Someone tell me if that's frowned on.

I was able to solve the "it's too fast" movement problem by searching the forum for "timer based movement".

It seems to work okay.

I declared this:



Then this is now in my do loop



The 80 value is an arbitrary number I came up with after experimentation. I guess I could change it to player_speed and then alter it based on what kind of terrain the player was passing over at the time (maybe mud slows the player down for instance).

My goal with this was to get something that would make the game run at the same speed on many computer speeds. I hoped that I could do something simple since all of my characters move one tile at a time.

Aside:

I'm not sure I understand when you would use TIMER vs. PERFTIMER. The help file does not say very much about it.
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 21st Aug 2011 07:39 Edited at: 21st Aug 2011 07:41
In hindsight probably should have left player_x as player_x instead of center_x.

With the current scrolling method the player is restricted from reaching the edge of the map because that would make the viewport go out of bounds.

To get around that I made code that allows the player to "free move" when he reaches a map's edge.

I'm happy that I got it to work but I wonder if my solution is overly complex.



In this code revision I also a renamed MAP_Start_X to Viewport_X. The same was done for the Y variant of the variable.

I really dislike how the obstacle tiles are hard-coded to be anything above tile # 7.
Ashingda 27
16
Years of Service
User Offline
Joined: 15th Feb 2008
Location:
Posted: 21st Aug 2011 20:07
Quote: "I'm sort of using this thread as a development blog. Maybe I shouldn't do that. Someone tell me if that's frowned on."

I see no problem with it.


Quote: "I'm happy that I got it to work but I wonder if my solution is overly complex."

It can be simplified a little more but if it works that's all that matters. Personally I like to allow the showing of the map edges.

Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 22nd Aug 2011 02:26 Edited at: 22nd Aug 2011 02:28
This is all the code I have so far. If you want to compile it you'll have to download the zip at the start of this post since it has the graphics and a map file. I have renamed a lot of variables to hopefully more accurately describe what they really are.



This tile engine can display a tile map and scroll it. It handles different screen resolutions by showing more or less tiles.

Anything above tile #7 is considered an obstacle (eg: mountain) and the player cannot go through it. I have also prevented the player from leaving the map array.

When the engine's viewport reaches its boundary the player goes into "free move" mode where he can walk around without the viewport moving. This lets the player reach the edge of the map without the viewport going out of bounds.

Bugs:

At line 297, I'm not sure why I had to subtract 2 to make it come out right.

I have also noted that line 268 makes the player stop at tile 1 according to my debug text.

I had to subtract 2 at line 209 and I'm not sure why there either.

Comments:

I think somewhere I must have messed up in how the map is drawn or how it is loaded. I know arrays start at 0 so a map array of 128 would go from 0 to 127. I may have compensated for that too many times somewhere. I'm not sure what I did but if you see it please clue me in.

I mean, it works, but I don't like mysteries in my own code. Feel free to play around.

If you hum Ultima music and pretend the tank is an 8 bit knight then you'll be transported back to 1989 too.
Ashingda 27
16
Years of Service
User Offline
Joined: 15th Feb 2008
Location:
Posted: 23rd Aug 2011 01:54
It seems to work correctly for me. You plan to experiment with smooth scrolling?

Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 23rd Aug 2011 03:52
Quote: "I know arrays start at 0 so a map array of 128 would go from 0 to 127"

In most languages yes, but DB is a little weird. It would go 1 to 128, but you could use the 0 index as well.

Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 23rd Aug 2011 05:36
Arrays start at 1 in DarkBasic Pro? Oh! That may explain a problem I had with going out of bounds that I fixed with a "magic number". I'll look at that.

I might experiment with smooth scrolling. Is step movement too retro? I was sort of going for a rogue-like or Ultima kind of look but I don't want it to be so retro that nobody plays. It might look better when I put a HUD on.

I looked over my movement code some more and noticed that there was a condition where the player sprite would actually move double. I pondered my logic and hacked in a variable that keeps track of whether the player has already moved and if so the second move is discarded. This prevents the double move, but it's probably not elegant.

I also rearranged the boundary check so that it is done first before any moves are even considered.

I am interested in using types to control whether a map tile is blocked or not. My current method is very inflexible.

Ashingda 27
16
Years of Service
User Offline
Joined: 15th Feb 2008
Location:
Posted: 23rd Aug 2011 05:57
Arrays dont start at 1, what I think Phaelax mean is that when you Dim(28) you get 0~28 instead of 0~27. So in DBPro if you want to dimension the array correctly you have to Dim(28-1). I use -1 as an example because 28 may be a variable.

Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 23rd Aug 2011 10:14 Edited at: 23rd Aug 2011 10:16
Ahh..

Okay thanks to both of you for explaining how DIM works a little more. Because of that I was able to track down another bug. Due to my misunderstanding of DIM I was not actually drawing the last column or row of the map! I fixed it and now the player can roam the entire map from lowly 0 all the way to mighty 127.

Now I can start adding more features!
Phaelax
DBPro Master
21
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 23rd Aug 2011 10:55
I say they start at 1 because even though Dim thing(28) will technically create 29 items (0-28), it will return a size of only 28.

Thing() will return -1 in size. Thing2(0), while initialized with a size of 0 and will return a size of 0, technically has a "real" size of 1, which is index 0.



And when you add items to the array like so:


It will be inserting the value of '42' at index 1.


Basically what I'm trying to say is, yes DB technically starts at 0 but when you factor in the returned size of the array it makes sense to think it skips 0. (although you can just as easily argue that it skips the last index and simply goes 0 to N-1)

Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 23rd Aug 2011 21:21
I just noticed that the map that was being displayed and the map in the map file didn't mesh up. It was rotated!

I fixed it by rearranging col and row in the map loading subroutine.

Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 23rd Aug 2011 22:52
Ashingda 27, I decided to look at and use your optimization.

I went from 600 FPS to about 6000.

From what I understand you are drawing a screen's worth of tiles to a bitmap and then copying that to the screen - but only when a player moves.

I guess the lesson here is that drawing one big picture is ten times faster than drawing a bunch of tiny ones.

That ought to give me FPS to burn.
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 24th Aug 2011 02:17 Edited at: 24th Aug 2011 02:18
I decided to experiment with line of sight / field of vision functions. I'm using this code snippet for now since it is a port of a line of sight routine from a rogue-like forum and my game is supposed to look retro.

http://forum.thegamecreators.com/?m=forum_view&t=178579&b=6

I've attached a demo of my current build. I think the line of sight routine is pretty neat but I think I should make it prettier. Right now I just draw a black tile when the area can't be seen. That covers up a lot of tiles which kind of makes having tiles pointless when you can't see most of them.

In the demo you can tell that I need a better way of gathering information about tiles than just what # they are. I need a way to say that a tile is walkable or not and transparent or not. In the demo some trees are see-through and some aren't.

I thought it was cool enough to show anyway. I'm not sure what would look best. I need to play some more old games and see what they did.

Attachments

Login to view attachments
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 24th Aug 2011 20:09 Edited at: 24th Aug 2011 20:22
I have decided to use a user defined type to hold values for terrain.

Currently I have



So later in the code (eg: collision) I can say:



And when I go to check line of sight / field of vision I can use .transparent

This beats my previous method, but now I wonder what the best way to stuff all the data into the type is.

If there are 5 or 6 tiles then it's not that much but what if there are 500 kinds of tiles?

Currently I do this when the map loads:



It just seems like that is going to get unwieldy as I add more properties to the type. Maybe that is normal?
IanM
Retired Moderator
22
Years of Service
User Offline
Joined: 11th Sep 2002
Location: In my moon base
Posted: 24th Aug 2011 21:58
One thing I can see almost immediately is that tiles with a common graphic will have common properties, so most of your properties can be stored in a separate and much smaller array containing one entry per tile type. Then your map will simply refer to that tile type rather than hold all of the common info too.

Then you can use your map to hold information that is specific to the tile, and not to the tile type. For example, record whether there's an object there, and what its object id is ... and the object details can be held in a different object array too.

Quote: "That covers up a lot of tiles which kind of makes having tiles pointless when you can't see most of them."

So show them, but hide what they contain - the though behind this is that you know what the terrain looks like, as you've seen it, but you don't know whether there is still an object or monster on that tile. You would simply flag the tile as 'seen' using your LOS algorithm.

Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 25th Aug 2011 00:38 Edited at: 25th Aug 2011 00:40
Based on IanM's advice I added a "discovered" property to tiles. All tiles are initially "undiscovered" but once a tile has been "discovered" (by being within the LOS of the player) then it is always drawn.

This gives the player a graphic representation of where they have yet to explore. It makes me want to wander around just to uncover all the "undiscovered" squares.

I should be able to easily adapt this to draw objects based on whether they are within the player's line of sight. I don't have any objects yet so I'll do that in a bit.

I'll have to think about what you said about common properties and arrays. I didn't "get" it at first glance.
IanM
Retired Moderator
22
Years of Service
User Offline
Joined: 11th Sep 2002
Location: In my moon base
Posted: 25th Aug 2011 00:56
Here's some type definitions that hopefully show what I mean:


Obviously you'd need to flesh this out quite a bit...

Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 25th Aug 2011 08:31
Oh, ok. Now I see what you're talking about.

That method would make it easy to have a big list of tiletype properties (object types, NPCs, etc.) and keep it neatly formatted and easy to change later.

I can flesh that out. Thanks.
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 26th Aug 2011 20:43 Edited at: 26th Aug 2011 20:56
Ok, I fought with that a little bit and then got it to work.

I set up some user defined types.



I set up some arrays.



I have a subroutine called Tile_Data_Setup that loads up all the tile properties to be used later.



So later I can do things like...



That's pretty cool!
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 27th Aug 2011 02:18
Oh. No. I did it incorrectly. I just thought it worked because I failed to REM out some old code that was over-riding the new stuff.

Back to the drawing board.
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 27th Aug 2011 06:09
I made some changes and got it to work like I thought it was supposed to work, but I don't know that I'm doing it "right".

Setup user defined types



Declare arrays..



Setup the tile property data..



Load the map..



Example in use..



I didn't really understand why I had to do ...



I thought that map_array().transparent and tile().transparent would always be the same because they are... "Linked"... ?

I'm confused on that point.
IanM
Retired Moderator
22
Years of Service
User Offline
Joined: 11th Sep 2002
Location: In my moon base
Posted: 27th Aug 2011 17:11
Quote: "I thought that map_array().transparent and tile().transparent would always be the same because they are... "Linked"... ?"

Why would you think that? They are entirely separate arrays.

Let me add one more section to the code I posted previously, that should make clear how you 'link' the arrays (or rather, how YOU can link the arrays):


Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 27th Aug 2011 19:39
Newcomers think all kinds of things.

I'll look at it and see if it makes anything clearer.

I'm actually doing pretty well here. This is farther than I've ever made it before.
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 27th Aug 2011 23:43
I wrote a small sample program because I didn't get it. Now I think I do.

Is this how this is supposed to work?



It gets the right values and I think that is what I was shooting for..
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 29th Aug 2011 01:23
I hoped my types were okay and moved forward. Someone tell me if the example above is bone-headed. I have a book and tutorials to look this stuff up with but that doesn't always mean I end up doing it the right way.

Anyway, here's a compiled version of what I've done so far.

New in this release is the ability to read from an ini file. Now I can store the user's choice of screen resolution, among other data.

The map file format got slight changes too.

All of the variables I had hard coded now reside in either the ini file or the map file format itself.

I will make another data file for terrain types.

I am thinking of leaving all data as text so people can edit things themselves. I'm not sure if that will cause a slow down later.

You can change the resolution in the ini file if you want. Note that the collision routine does not properly handle what happens if the player starts out on an impassable tile. If you change the screen resolution and it makes the player start on an impassable tile then movement controls will go crazy. I will fix that next time.

Thanks all.

Next week I will go back over all the code, clean it up, fix the collision error, make better remarks, and then move on to loading terrain properties from a file. Maybe I will set up some way to put comments in the ini file too.

Onward, upwards..

Attachments

Login to view attachments
Lost Dragon
14
Years of Service
User Offline
Joined: 22nd Aug 2010
Location:
Posted: 30th Aug 2011 04:19
I remembered that .INI is a preexisting file type so I renamed my config file .cfg

I removed the tile properties data from the program and added them to an external file that loads into the tiles() array.

I can easily edit tile properties with any text editor, but the work is exacting so it seems like it would be better to have an input form and let the program output the file as well. DBPro doesn't seem to have a form editor so I guess I have to make my own GUI for this.

I added basic error checking for map loading. If a tile number of 0 is found then an error message is displayed and the tile is changed to grass. It's not perfect but better than a crash with no explanation.

I should probably make another thread in the Work in Progress section since this is sort of turning into a work log. I'll do that a little later in the week and make a link to it from this thread for future forum viewers.

Login to post a reply

Server time is: 2024-11-22 16:41:16
Your offset time is: 2024-11-22 16:41:16