Enterprise Forever
:UK => Programming => Topic started by: ssr86 on 2015.November.05. 18:17:59
-
Well, I thought to open a topic where we could share some useful code examples or ideas.
1. A method for switching buffer addresses (for drawing to the correct buffer) when using double buffering.
It comes from the source code for Rigor Mortis for the CPC which is based on disassembly of Elmar Krieger's (author of "Prehistorik 2" and "Super Cauldron" for the amstrad) game engine. The Source (among many others) can be found at http://cpcrulez.fr/coding_menu-src.htm
We prepare a LUT for the two buffer addresses:
first_buffer_address dw $0000
second_buffer_address dw $4000
...and we use a 16-bit variable for choosing between the two addresses:
double_buffer_offset dw $0002
We use it to offset to the wanted address so should be $0000 or $0002.
Everytime we want to change the offset we do:
ld hl,double_buffer_offset
ld a,(hl)
xor 2
ld (hl),a
To get the correct buffer address:
ld bc,(double_buffer_offset)
ld hl,first_buffer_address
add hl,bc
Now the wanted address is stored in memory at hl, so to get the address:
ld e,(hl)
inc l
ld d,(hl)
The address is now in de.
Earlier I switched the addresses by storing additional address variables for the active and hidden buffer address and switch the two for every game frame and also have a variable that stored the number of active buffer (0 or 1), because many times you have to choose which sprite background buffer to use (for which screen).
I find the one by Elmar Krieger to be somewhat cleaner and prettier...
2. Second is something like the strategy pattern in OOP (at least reminds me of it)...
When you want to use some optional code, like for example an optional gfx effect, additional game mode mechanic, switching music or something like that then you can do:
in your mainloop:
call something_dispatcher
the called subroutine is a simple jump:
something_dispatcher:
jp something
You can set the jump to what you want it to do...
For example for switching music/sfx/no sound you could set the dispatch address to the right routine...
When you don't want to do the "something" you set the jp address to a ret:
just_a_ret:
ret
To set the dispatch address to it:
ld hl,something_dispatch+1
ld (hl),just_a_ret
Else you can do conditionals every time but the presented method is a little quicker and cleaner (at least for me)...
One disadvantage would be that it's self modyfying code...
-
3. This I use for a simple Pause game mechanic after pressing the STOP button...:
try_pause_game:
;EP keyboard matrix:
; b7 b6 b5 b4 b3 b2 b1 b0
;Row 80H 40H 20H 10H 08H 04H 02H 01H
; 0 L.SH. Z X V C B \ N
; 1 CTRL A S F D G LOCK H
; 2 TAB W E T R Y Q U
; 3 ESC 2 3 5 4 6 1 7
; 4 F1 F2 F7 F5 F6 F3 F8 F4
; 5 ERASE ^ 0 - 9 8
; 6 ] : L ; K J
; 7 ALT ENTER LEFT HOLD UP RIGHT DOWN STOP
; 8 INS SPACE R.SH. . / , DEL M
; 9 [ P @ 0 I
check_stop_pressed:
ld a,7 ; row number
out (0b5h),a ; scan row and get result
in a,(0b5h)
bit 0,a
ret nz
; simple pause game mechanism...
; blocking the execution of interrupts
; and gameloop continuation after pressing
; the stop key and unblocking everything
; after pressing it for the second time
di
ld a,201
out (border),a
ld hl,last_key_pressed
call ploop1 ; wait until key released
call ploop1 ; wait until pressed second time
ld a,0
out (border),a
ei
ret
ploop1:
ld (hl),a
ld a,7
out (0b5h),a
in a,(0b5h)
cp (hl)
jr z,ploop1
bit 0,a
jr z,ploop1
ret
last_key_pressed db 0
-
Wiki topic?
-
4. Basic joystick "waggling" mechanics like in old sports games (decathlon, summer games etc.):
joy_control:
ld hl,last_key_pressed
call joyscan
ld e,(hl)
ld (hl),d
try_down:
bit 2,d
jp nz,try_up
bit 2,e
jp z,try_up
jp waggle_incrementation
try_up:
bit 3,d
ret nz
bit 3,e
ret z
waggle_incrementation:
ld a,(waggle_increment)
ld c,a
ld a,(counter)
add a,c
cp COUNTER_RESET-1
jr c,$+4
ld a,COUNTER_RESET-2
ld (counter),a
ret
joyscan:
ld c,0 ; first row
ld d,0
joy_loop1: ld b,5 ; read four directions + fire
;ld e,d
joy_loop2: ld a,c ; row number
inc c ; next row
out (0b5h),a ; scan row and get result
in a,(0b6h) ; get each bit in turn and
rra ; shift result into d
rl d
djnz joy_loop2
ret
waggle_counter_decrement:
; decrease counter:
ld hl,counter
ld a,(hl)
or a
ret z
ld a,(counter_decrement_step)
ld c,a
ld a,(hl)
sub c
jp nc,$+4
xor a
ld (hl),a
ret
; variables:
counter db counter_reset
counter_decrement_step db 1
waggle_increment db 2
COUNTER_RESET equ 64
"waggle_decrement" should be called every frame or few so the counter will go down (which could mean the player slows down).
"waggle_incrementation" is called when you do an up/down(can change to left/right or whatever) movement...
Wiki topic?
Sorry, but what does that mean? :oops:
-
Sorry, but what does that mean? :oops:
I _think_ he was about the wiki section of the site, check the top of this page out, the blue "WIKI" button. Wiki is (or would be) a great place to document things, collecting tricks etc.
-
I _think_ he was about the wiki section of the site, check the top of this page out, the blue "WIKI" button. Wiki is (or would be) a great place to document things, collecting tricks etc.
Oh, but the wiki pages don't seem to allow discussion... Also for the wiki everything would have to be better written...(I mean text quality). Forum topic allows more informal presentation..
-
Oh, but the wiki pages don't seem to allow discussion... Also for the wiki everything would have to be better written...(I mean text quality). Forum topic allows more informal presentation..
Yes, that's the point. For discussion it's better to do on the forum, of course. But of course if there are useful tips - I think! - it's maybe worth to document it on the wiki as well, still of course there can be a forum topic to discuss it. Personally what I always find hard is to try to find something I remember in one of the topics eg a year ago, always mission impossible to do ... If you see my point.
-
5. Adding 8 bit value to a 16-bit register
Instead of
ld bc,$00nn
add hl,bc
You can do:
; add $nn to HL
ld a,l
add a,$nn
ld l,a
adc a,h
; a=l+h+carry
sub l
ld h,a
It takes one byte more and is a little bit slower but if you don't want to corrupt bc or de then this is very useful.
Else you could save bc on the stack and restore its value after the add but the presented method is a little less expensive.
Below is a similar alternative to subtraction:
; subtract $nn from HL
ld a,l
sub $nn
ld l,a
sbc a,l
add a,h
ld h,a
Yes, that's the point. For discussion it's better to do on the forum, of course. But of course if there are useful tips - I think! - it's maybe worth to document it on the wiki as well, still of course there can be a forum topic to discuss it. Personally what I always find hard is to try to find something I remember in one of the topics eg a year ago, always mission impossible to do ... If you see my point.
If these "examples" are verified to be useful, tested for correctness and written with a "cleaner" language, maybe then I will try to put them to to the wiki page ;P .
I have an unfinished "article" about different methods for flipping and shifting of sprites (maybe also on clipping)... I'll try to finish it and maybe I will upload that to the wiki...
-
If these "examples" are verified to be useful, tested for correctness and written with a "cleaner" language, maybe then I will try to put them to to the wiki page ;P .
I have an unfinished "article" about different methods for flipping and shifting of sprites (maybe also on clipping)... I'll try to finish it and maybe I will upload that to the wiki...
I think this is the most correct way to do, indeed :)
-
GREAT!
-
6. Next comes from an example posted by Zozo in https://enterpriseforever.com/programming/19-faster-ldir/msg43374/#msg43374 and it shows how you can use the accumulator as the loop counter when you need to use it also in the middle of the loop and you can't use stack (because, like in the source example, you abuse the stack for moving data):
(although honestly the entire code posted by Zozo should be pasted here as an example of stack abuse technique)
routine_start:
ld a,INITIAL_LOOP_COUNTER_VALUE
ld (loop_counter+1),a
loop:
[...]
loop_counter:
ld a,0 ; SMC - loaded with INITIAL_LOOP_COUNTER_VALUE at the beginning
dec a
ld (loop_counter+1),a
jp nz,loop
ret