Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
 Welcome to our latest new user megasoftargentina ! (Registered 2024-04-16) You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Layouting tiles for AGSP game
2019-04-09 01:25
knue

Registered: Dec 2012
Posts: 37
Layouting tiles for AGSP game

Hi all,

I'm currently trying to write an AGSP-based game engine. The thing that really inspired me on this is Mythos:
Mythos - Battle for Aivanor

Now for the question, I managed to implement the AGSP stuff, fighting the interrupts and everything but what really puzzles me: How the heck do you layout the tiles and manage the redraws???

Like Mythos, I'd like to use 3x2 sized tiles. Let's assume we always scroll 2 pixels at a time. This means you must copy 25% of the next screen in advance for one frame (double the amount if you scroll diagonally). But due to the AGSP there is also this wrap around of the buffers going and everything. How to do that without going insane is a complete mystery to me.
2019-04-09 03:58
mad
Account closed

Registered: Feb 2017
Posts: 6
Wow this Mythos Demo is unbelievable! Looks like the dream of game programmers back then :)..

One thing about wraparound.. You only have to do the wraparound if you actually cross a $100 boundary so an

tya
adc #$08
tay
bcs .wraparoundcheckandupdateincrementhibyte

is one easy way to do that. most probably there are other,tablebased?, options too. But it isn't as expensive as it first seems.. At least that's what I think to know :)..
2019-04-09 04:40
ChristopherJam

Registered: Aug 2004
Posts: 1370
Conceptually, you "just" maintain a pointer to the the top left corner of the viewport, adding one whenever you scroll a character to the right, forty for down, -1 and -40 for up and left. Keep only the low ten bits, and the wrapping takes care of itself.

You can find addresses within screen ram or colour ram by adding that value to your screen ram or colour ram base address, and the address in bitmap by first multiplying by eight.

update column 39 when you're moving right, column -1 when you're moving left, etc.

As for scheduling, when I implemented this for Hysteron Proteron I had the interrupts maintain the screen position, and the mainline code perform the blitting in response to requests from the interrupt code. RMW instructions signalled from mainline back to interrupt so I didn't have to take care to avoid being interrupted between reading and updating a flag.
2019-04-09 14:31
knue

Registered: Dec 2012
Posts: 37
Well this is more or less clear to me. What really bugs me is the following:
* there are 4 scrolling cases to consider (left, right, top, bottom)
* 3*2 cases for each tile position
* 4 cases for x-scroll (assuming scrolling 2 pixels at once)
* 4 cases for y-scroll

So that's in total 384 cases! Even if I manage to program all that cases with some macro magic to at least share some of the code, I'm afraid that in the end of the day I need to have all 384 code variants in memory, or am I missing something?
2019-04-09 14:56
cadaver

Registered: Feb 2002
Posts: 1153
Shouldn't you only need "update horizontal span" and "update vertical span" routines, which redraw one char-column or one char-row worth of bitmap data at a time, and handle wrapping as they go?

If you check with e.g. ICU64 how Mythos updates the bitmap, it appears to be working like that.

You could compose your tiles from a virtual bitmap "charset" to save memory, instead of always storing unique data for each 3x2 tile.
2019-04-09 15:04
knue

Registered: Dec 2012
Posts: 37
But updating a complete row is too much to handle in one frame, no? Updating a complete row needs 40*10 reads & writes. (8 for bitmap + 1 for screen ram + 1 for color ram).

I already thought about this virtual char set for compressing the tile data but then the number of cases even explode more.
2019-04-09 15:15
cadaver

Registered: Feb 2002
Posts: 1153
It's still less than a char-mode standard hardscroll (1000 bytes for whole screen)

I'd recommend trying how your rastertime fares with that first, as it's simplest.

If your gamelogic can signal the IRQ with the sprite + scroll positions that should be shown on the next frame, while it already calculates ahead, it should be able to take the occasional heavier rastertime hit.
2019-04-09 16:20
mad
Account closed

Registered: Feb 2017
Posts: 6
Perhaps you can prebuild your charlines to append..

So that you only have (bitmapData*8,colorRam1*1,colorRam2*1)*40 into a buffer. Then when you really need to append the data you just do a simple copy loop whilst maintaining the wraparound.

The candidates for prebuilding depend on your (xyScrollPosition & 7)..

If x is bigger or equal 4 you can start prebuilding the buffer for the right. if x is below 4 you can start prebuilding the buffer for the left. The same for y.

On actual appending the prebuild buffers, you can handle the x+y appending cases.

it's just an idea perhaps it doesn't work. Most probably there are better solutions.

However I think it's easier to first inspect the rastertime needed like Cadaver suggested. You somehow have the whole (AGSP) frame to do the appending..
2019-04-09 16:22
mad
Account closed

Registered: Feb 2017
Posts: 6
Actually that doesn't work! :) You would have to implement some delay on a direct direction switch..
2019-04-09 16:29
knue

Registered: Dec 2012
Posts: 37
Any suggestions how to layout the tiles in memory?
Let's say a tile looks like this:
ABC
DEF

The most obvious solution would be this:
A0...A7 B0...B7 C0...C7 D0...D7 E0...E7 F0...F7 Next tile here

But I think address computations can be quite expansive.
Next option:
Tile0_A0...A7 Tile1_A0...A7 ... Tile_7F_A0..A7
Tile0_B0...B7 Tile1_B0...B7 ... Tile_7F_B0..B7
...
Tile0_F0...F7 Tile1_F0...F7 ... Tile_7F_F0..F7

But maybe using a virtual char set isn't that bad after all.
Maybe sth like this:
Tile0_A Tile1_A ... Tile_7F_A
Tile0_B Tile1_B ... Tile_7F_B
...
Tile0_F Tile1_F ... Tile_7F_F

char_00_row0 ... char_00_row7
char_01_row0 ... char_01_row7
...
char_FF_row0 ... char_FF_row7
2019-04-09 16:36
ChristopherJam

Registered: Aug 2004
Posts: 1370
You don't need a routine per two pixels; just do one for each row or column of chars. It's allowed to take three or four frames to execute if it's running in mainline instead of on interrupt.

(Or, start it at the end of your VBL interrupt, but CLI before entering the loop. Just make sure you don't trigger a second blit while you already have one in flight).
2019-04-09 16:42
ChristopherJam

Registered: Aug 2004
Posts: 1370
As for memory layout, suspect I'd lean towards a table for A0, then a table for A1, etc - so you can just index each source table by tile ID.

If you've the ram for it, then that's 60 tables, so nearly 16k for 256 tile elements (less if you've fewer tiles).

Could always go for a hierarchy to save memory of course (tiles are made of virtual chars etc).
2019-04-09 17:07
knue

Registered: Dec 2012
Posts: 37
Quote: You don't need a routine per two pixels; just do one for each row or column of chars. It's allowed to take three or four frames to execute if it's running in mainline instead of on interrupt.

(Or, start it at the end of your VBL interrupt, but CLI before entering the loop. Just make sure you don't trigger a second blit while you already have one in flight).


I don't really get this. Let's say I'm only scrolling left/right. Now the player moves to the right two pixels. So I'm starting the mainline scroll-left routine. But now the players moves back again. What should I do now? I somehow have to notify mainline that it should abort and start the scroll-right routine. I could do the copy for scroll-left from left to right and the copy for the scroll-right from right to left and pray for the best. Is this what you mean?
2019-04-09 17:31
ChristopherJam

Registered: Aug 2004
Posts: 1370
You've got a few options there.

You could indeed abort if the player changes direction, or alternately decouple the scroll position from the player position a little, and don't change scroll direction until you've finished the most recent blit.

It doesn't even have to be blitter dependent - for example if you implement a push scroll where the player can roam anywhere in the middle third of the screen before it starts scrolling, there will be a period of {screenwidth/3}/{player speed} when the screen is stationary.
2019-04-09 21:44
Oswald

Registered: Apr 2002
Posts: 5017
Quote: Conceptually, you "just" maintain a pointer to the the top left corner of the viewport, adding one whenever you scroll a character to the right, forty for down, -1 and -40 for up and left. Keep only the low ten bits, and the wrapping takes care of itself.

You can find addresses within screen ram or colour ram by adding that value to your screen ram or colour ram base address, and the address in bitmap by first multiplying by eight.

update column 39 when you're moving right, column -1 when you're moving left, etc.

As for scheduling, when I implemented this for Hysteron Proteron I had the interrupts maintain the screen position, and the mainline code perform the blitting in response to requests from the interrupt code. RMW instructions signalled from mainline back to interrupt so I didn't have to take care to avoid being interrupted between reading and updating a flag.


wow cj, this is so simple and brilliant at the same time.
2019-04-09 23:37
knue

Registered: Dec 2012
Posts: 37
Quote: You've got a few options there.

You could indeed abort if the player changes direction, or alternately decouple the scroll position from the player position a little, and don't change scroll direction until you've finished the most recent blit.

It doesn't even have to be blitter dependent - for example if you implement a push scroll where the player can roam anywhere in the middle third of the screen before it starts scrolling, there will be a period of {screenwidth/3}/{player speed} when the screen is stationary.


Looking at Mythos, the player is stuck in the middle of the screen. This is potentially sth I really like. There are way to many games where the screen starts scrolling when the player is in the last third or so and you have hardly time to react to the new stuff that is coming at you. In that regard the best scrolling I've seen so far is in Sam's Journey. There the screen actually overruns you such that you have plenty of space to see what is in front of you. Really cool. Would be interested how exactly this works.
2019-04-10 20:51
Copyfault

Registered: Dec 2001
Posts: 466
Don't know of what you're planning to have in the upper/Lower border part of screen, but assuming we're talking PAL-system here and the rasterlines in the border area are free (=no sprites to be shown, no other timing tricks for $3fff gfx etc.), you should have 312-200=112 Rasterlines in the upper/lower-border-area alone. This gives 112*63=7056 Cycles.

Now when copying a row, you'd need to do this for 40*10 bytes. Using speedcode (LDA/STA) this means we need 8 Cycles per byte, thus 400*8 = 3200 Cycles (<7056 Cycles -> can be done in one frame!)

Depending on all the other stuff you must calculate to keep your game engine going and depending on how fast you actually want to scroll, I'd go for a speedcode generator that does its job during the non-wrap-around frames and call the speed-code for copying when the wrap-around is due.

It might also help to start with an x-offset of 4 (setting $D016 accordingly) if the overall scrollingspeed allows for it, for example if you manage to do the speed-code calculation within say three frames and the scroll-speed is 1pixel/frame, the offset ensures that you have enough time no matter in which direction the player decides to go. Ofcourse the speedcode generator must take the direction into consideration. If the player decides to change direction before a wrap-around, you'll have enough time to do the calculation for the other direction.


Just some basic ideas that I would try out for agsp'ing.

Cheers-CF

[edit] x-offset is valid if you do left/right scrolling; y-offset is what is needed for up/down-scrolling in which case a row has to be copied upon wrap-around. But I guess you spotted this already, after all it's just a rough concept.
2019-04-10 22:56
cadaver

Registered: Feb 2002
Posts: 1153
Quote: Looking at Mythos, the player is stuck in the middle of the screen. This is potentially sth I really like. There are way to many games where the screen starts scrolling when the player is in the last third or so and you have hardly time to react to the new stuff that is coming at you. In that regard the best scrolling I've seen so far is in Sam's Journey. There the screen actually overruns you such that you have plenty of space to see what is in front of you. Really cool. Would be interested how exactly this works.

In SJ, moving horizontally shifts the camera "origin" position to the opposite side, so that you will see more. If you run fast, the shift happens faster until it reaches the maximum. Turning centers the camera again. Vertically it seems to be just keeping the player in the center, but the scrolling is fairly slow, so that a jump does not catch up with you at first.
2019-04-10 23:18
cadaver

Registered: Feb 2002
Posts: 1153
Btw. before going crazy with speedcode, I recommend checking out how traditional AGSP games like Fred's Back and Maximum Overdrive do the bitmap update. They're actually shockingly inefficient.

Mythos at least unrolls blitting a char onto the bitmap, in the manner of:

lda charrow1,x
sta (bitmap),y
iny
lda charrow2,x
sta (bitmap),y
iny
...

Where X is the char number to blit, and the destination is just a ZP pointer + Y.

Of course you can always go and optimize later, according to how much CPU you need for other things, but don't think you need to immediately break out the big guns just to get a basic scroller running.
2019-04-10 23:58
knue

Registered: Dec 2012
Posts: 37
Thanks for all the valuable input.

On another note: Are there any pixel editors out there to at least create the tile set? Preferably something that runs on Linux. Or are you guys just using sth like Gimp + some homebrewn scripts to convert it to your desired output format? On another note, I thought about double-buffering the screen ram and swapping them each frame. This is a pretty cheap effect for mixing colors %01 and %10. But this requirement makes it even more difficult to find an appropriate editor.

EDIT: I've just used a little bit of python magic to create a nice palette and tweaked gimp a little bit. So far, it works quite nicely :)
2019-04-11 08:43
Golara
Account closed

Registered: Jan 2018
Posts: 212
Quote: Thanks for all the valuable input.

On another note: Are there any pixel editors out there to at least create the tile set? Preferably something that runs on Linux. Or are you guys just using sth like Gimp + some homebrewn scripts to convert it to your desired output format? On another note, I thought about double-buffering the screen ram and swapping them each frame. This is a pretty cheap effect for mixing colors %01 and %10. But this requirement makes it even more difficult to find an appropriate editor.

EDIT: I've just used a little bit of python magic to create a nice palette and tweaked gimp a little bit. So far, it works quite nicely :)


interlaced game ? lol i'm not sure i'd like to look at that flickering while playing.

As for pixeling, there's lots of programs for drawing c64 graphics, for example charpad, but you can also draw it in whatever graphics program you want and then convert it, it's pretty easy. You can load bmp/png images directly in KickAssembler and convert it to charset/bitmap data there. It has functions like getMulticolorByte which takes a x,y coordinate and automatically makes a byte out of 8 pixels at this position inside the image.
2019-04-11 17:55
Hein

Registered: Apr 2004
Posts: 933
For bitmap tiles: GFX-Editor V1.4
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
CreaMD/React
kbs/Pht/Lxt
jmin
Guests online: 116
Top Demos
1 Next Level  (9.8)
2 Mojo  (9.7)
3 Coma Light 13  (9.7)
4 Edge of Disgrace  (9.6)
5 Comaland 100%  (9.6)
6 No Bounds  (9.6)
7 Uncensored  (9.6)
8 Wonderland XIV  (9.6)
9 The Ghost  (9.6)
10 Bromance  (9.6)
Top onefile Demos
1 It's More Fun to Com..  (9.9)
2 Party Elk 2  (9.7)
3 Cubic Dream  (9.6)
4 Copper Booze  (9.5)
5 Rainbow Connection  (9.5)
6 TRSAC, Gabber & Pebe..  (9.5)
7 Onscreen 5k  (9.5)
8 Dawnfall V1.1  (9.5)
9 Quadrants  (9.5)
10 Daah, Those Acid Pil..  (9.5)
Top Groups
1 Oxyron  (9.3)
2 Nostalgia  (9.3)
3 Booze Design  (9.3)
4 Censor Design  (9.3)
5 Crest  (9.3)
Top Logo Graphicians
1 Sander  (10)
2 Facet  (9.7)
3 Mermaid  (9.4)
4 Pal  (9.4)
5 Shine  (9.3)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.049 sec.