Author Topic: Assembly routine to move a bullet  (Read 317 times)

0 Members and 1 Guest are viewing this topic.

Offline AMSDOS

  • Supporter
  • 6128 Plus
  • *
  • Posts: 3.306
  • Country: au
    • index.php?action=treasury
    • Programs for Turbo Pascal 3
  • Liked: 593
Assembly routine to move a bullet
« on: 07:26, 14 September 17 »
I previously posted a structured BASIC Shoot-em-up engine in this thread with uses this bit of BASIC to move a bullet or two:


Code: [Select]
1210 FOR n=b TO t
1220   LOCATE bx(n),by(n)
1230   PRINT" ";
1240   PEN 3
1250   bx(n)=bx(n)+1
1260   LOCATE bx(n),by(n)
1270   PRINT b$;
1280   IF bx(n)=38 THEN LOCATE 38,by(n):PRINT" ";:b=b+1
1290 NEXT n
1300 IF bx(n-1)=38 AND b=3 THEN GOSUB 1590


though now I curious to try and write this in Assembly, this is what I've done so far:


Code: [Select]
org &9000

;; CALL &9000,bx(n),by(n),tot


ld a,(ix+00) ;; tot
;; ld h,(ix+05) ;; blank value
ld l,(ix+04) ;; l:=bx(n)
ld (scount),a ;; scount:=tot
ld d,0 ;; d:=0
ld e,a ;; e:=tot
ld a,l ;; a:=bx(n)
ld hl,bx ;; hl:=addr(bx)
call poke ;; poke hl+tot-1,bx(n)
ld l,(ix+02) ;; l:=by(n)
;; ld h,(ix+03) ;; blank value
ld a,(scount) ;; a:=scount (tot)
ld d,0 ;; d:=0
ld e,a ;; e:=scount (tot)
ld a,l ;; a:=by(n)
ld hl,by ;; hl:=addr(by)
call poke ;; poke hl+tot-1,by(n)


.loop ;; main loop
ld a,(bx)
ld h,a
ld a,(by)
ld l,a
call &bb75
ld a,32
call &bb5a


ld a,(bx)
inc a
ld (bx),a

ld a,(bx)
ld h,a
ld a,(by)
ld l,a
call &bb75
ld a,45
call &bb5a


ld a,(fcount) ;; a:=fcount
inc a ;; a:=a+1
ld (fcount),a ;; fcount:=a
ld b,a ;; b:=a
ld a,(scount) ;; a:=scount (tot)
cp b ;; if a<>b then
jr nz,loop ;;   goto loop
ld a,(frest)
ld hl,fcount
ld (hl),a
ret ;; back to BASIC




.poke add hl,de ;; addr(bx or by):=addr(bx or by)+tot
dec hl ;; addr(bx or by):=addr(bx or by)-1
ld (hl),a ;; poke addr(bx or by),bx(n) or by(n)
ret ;; return


.bx defb 0,0 ;; bx(1)..bx(2) - Bullets x 1 and 2
.by defb 0,0 ;; by(1)..by(2) - Bullets y 1 and 2
.fcount defb 0 ;; fcount
.scount defb 0 ;; scount (tot)
.frest defb 0 ;; frest  (bot)








At the moment it works when 1 bullet has to move and the good news is it's very fast. What I've done in the initial code is to get the values for bx & by array's & tot which can either be 1 or 2 to correctly put the bullets in bx(1) or bx(2) and by(1) or by(2). When I've setup the loop though, I'm having problems in how I need to gather the data from bx(2) & by(2), and what I want to try with the loop is to have it pass back to access the data from those positions.


Earlier I was doing something this to access it:


Code: [Select]
.loop
 ld hl,bxpos
 ld a,(hl)
 ld d,a
 ld hl,bypos
 ld a,(hl)
 ld e,a
 ex hl,de
 call &bb75
 ..


 ld hl,(bxpos)
 inc hl
 ld (bxpos),hl


.bxpos defw bx
.bypos defw by


though it led to other complications (mainly lack of control), though I thought I should have enough information that I'm passing from BASIC in order simply have it loop around. Anyone got any suggestions what I need to add to make the loop work for the 2nd pass?  :-[

Offline AMSDOS

  • Supporter
  • 6128 Plus
  • *
  • Posts: 3.306
  • Country: au
    • index.php?action=treasury
    • Programs for Turbo Pascal 3
  • Liked: 593
Re: Assembly routine to move a bullet
« Reply #1 on: 10:04, 14 September 17 »
Seems to be too difficult to do a 2-Bullet routine approach, so I've gone to the 1-Bullet, the loop has been removed, bx, by are single bytes & no 3rd parameter, so no calculating where everything has to go. The only thing which needs checking is when bx gets to the end of the screen, delete the character & reset bx/by to 0.


Code: [Select]

org &9000

;; CALL &9000,bx,by


ld a,(ix+02) ;; a:=bx
ld (bx),a ;; bx:=a
ld a,(ix+00) ;; a:=by
ld (by),a ;; by:=a


ld hl,(by) ;; l:=bx h:=by
call &bb75
ld a,32
call &bb5a


ld a,(bx) ;; a:=bx
inc a ;; a:=a+1
ld (bx),a ;; bx:=a

ld hl,(by) ;; l:=bx h:=by
call &bb75
ld a,45
call &bb5a


ret ;; back to BASIC


.by defb 0 ;; x position of bullet
.bx defb 0 ;; y position of bullet

Offline AMSDOS

  • Supporter
  • 6128 Plus
  • *
  • Posts: 3.306
  • Country: au
    • index.php?action=treasury
    • Programs for Turbo Pascal 3
  • Liked: 593
Re: Assembly routine to move a bullet
« Reply #2 on: 13:21, 14 September 17 »
What I ended up doing after I added some checking to my assembly code is taking that BASIC example earlier and incorporating the machine code into it:


Code: [Select]

100 ' Setup Inks and Screen Mode
110 INK 0,0
120 INK 1,26
130 INK 2,20
140 INK 3,18
150 BORDER 11
160 PAPER 0
170 PEN 1
180 MODE 1
190 GOSUB 1700 ' Poke Move Bullet to Memory
200 ' Define Characters & Objects
210 DEFINT a-z
220 s$=CHR$(143)
230 a$="@"
240 b$="-"
250 x=1
260 y=1
270 DIM bx(2)
280 DIM by(2)
290 b=1
300 t=0
310 sc=0
320 ay=1+INT(RND*23)
330 ax=37
340 GOSUB 810 ' Print Ship
350 GOSUB 1010 ' Print Alien
360 LOCATE 1,25
370 PRINT"Score:"
400 ' Main Loop
410 WHILE 1
420   IF INKEY(1)<>-1 AND x<30 THEN GOSUB 910:x=x+1:GOSUB 810
430   IF INKEY(8)<>-1 AND x>1 THEN GOSUB 910:x=x-1:GOSUB 810
440   IF INKEY(0)<>-1 AND y>1 THEN GOSUB 910:y=y-1:GOSUB 810
450   IF INKEY(2)<>-1 AND y<24 THEN GOSUB 910:y=y+1:GOSUB 810
460   GOSUB 710
470   GOSUB 1140 : GOSUB 1010 ' Delete & Reprint Alien
480   IF INKEY(47)<>-1 AND t<>2 THEN t=t+1:bx(t)=x+1:by(t)=y
490   IF t<>0 THEN GOSUB 1210
500 WEND
600 ' Has bullet or alien collided?
610 IF ((bx(1)=ax) AND (by(1)=ay)) OR ((bx(2)=ax) AND (by(2)=ay)) THEN GOSUB 1410
620 RETURN
700 ' Has Alien Collided with Ship?
710 IF (x=ax) AND (y=ay) THEN GOSUB 1410:LOCATE 15,12:PRINT"You're Dead!":END
720 RETURN
800 ' Display Ship
810 LOCATE x,y
820 PEN 1
830 PRINT s$;
840 RETURN
900 ' Delete Ship
910 LOCATE x,y
920 PRINT" ";
930 RETURN
1000 ' Display and Move Alien
1010 LOCATE ax,ay
1020 PEN 2
1030 PRINT a$;
1040 ax=ax-1
1050 GOSUB 710
1060 WHILE ax=0
1070   LOCATE 1,ay
1080   PRINT" ";
1090   ax=37
1100   ay=1+INT(RND*23)
1110 WEND
1120 GOSUB 610
1130 RETURN
1140 LOCATE ax+1,ay
1150 PRINT" ";
1160 RETURN
1200 ' Routine to Move Shots Fired
1210 FOR n=b TO t
1220   CALL &9000,bx(n),by(n)
1230   bx(n)=PEEK(&9049):by(n)=PEEK(&9048)
1280   IF PEEK(&9049)=0 THEN b=b+1
1290 NEXT n
1300 IF PEEK(&9049)=0 AND b=3 THEN GOSUB 1590
1310 GOSUB 610
1320 RETURN
1400 ' Death Sequence for Alien or Ship should they Collide
1410 LOCATE ax,ay
1420 PRINT" ";CHR$(238);
1430 sc=sc+20
1440 LOCATE 8,25
1450 PRINT sc;
1460 ax=39
1470 ay=1+INT(RND*23)
1480 FOR v=15 TO 0 STEP -1
1490   BORDER 6
1500   SOUND 1,0,3,v,,,31
1510   BORDER 11
1520   SOUND 2,1000,3,v,,,31
1530 NEXT v
1540 FOR c=1 TO t
1550   LOCATE bx(c),by(c)
1560   PRINT" ";
1570   bx(c)=0:by(c)=0
1580 NEXT c
1590 b=1:t=0
1600 RETURN
1700 MEMORY &8FFF:ln=1760:FOR adr=&9000 TO &904F STEP 16
1710 READ b$:chk=0:FOR i=0 TO 15
1720 v=VAL("&"+MID$(b$,i*2+1,2))
1730 POKE adr+i,v:chk=chk+v:NEXT
1740 IF chk<>VAL("&"+RIGHT$(b$,3)) THEN PRINT"ERROR In Line";ln:STOP
1750 ln=ln+10:NEXT:RETURN
1760 DATA DD7E02324990DD7E003248902A4890CD69C
1770 DATA 75BB3E20CD5ABB3A49903C3249902A4863C
1780 DATA 90CD75BB3E2DCD5ABB3A4990FE262017748
1790 DATA 3A4990673A48906FCD75BB3E20CD5ABB738
1800 DATA AF324990324890C9000000000000000038D


however I was able to make it a 2-bullet shoot-em-up by using BASIC code for where I was having difficulty writing the assembly which includes the Array and the varying FOR Loop which is subject to change depending on what the 'b' & 't' variables equal (which is what I'm mostly having trouble grasping to write in assembly). Naturally once the positions have been recalculated in the M/C routine, bx(n) & by(n) needs to know the new values, which is what Line 1230 does & b is altered when the address position of bx @ &9049 equals 0. Likewise the second IF in line 1300 checks if bx =0 and b=3 to reset.


It's definitely an improvement over the original BASIC, there is some slowdown, though not as noticeable as the original, which I'm happy with.


This was what I came up with, with the routine above after I added the check routine:




Code: [Select]

org &9000

;; CALL &9000,bx,by


ld a,(ix+02) ;; a:=bx
ld (bx),a ;; bx:=a
ld a,(ix+00) ;; a:=by
ld (by),a ;; by:=a


ld hl,(by) ;; l:=bx h:=by
call &bb75
ld a,32
call &bb5a


ld a,(bx) ;; a:=bx
inc a ;; a:=a+1
ld (bx),a ;; bx:=a

ld hl,(by) ;; l:=bx h:=by
call &bb75
ld a,45
call &bb5a


ld a,(bx) ;; a:=bx
cp 38 ;; if a<>38
jr nz,exit ;;  then goto exit


ld a,(bx)
ld h,a
ld a,(by)
ld l,a
call &bb75 ;; locate bx,by
ld a,32
call &bb5a ;; print" "
xor a ;; a:=0
ld (bx),a ;; bx:=0
ld (by),a ;; by:=0


.exit ret ;; back to BASIC


.by defb 0 ;; x position of bullet
.bx defb 0 ;; y position of bullet

Offline ervin

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.038
  • Country: au
    • index.php?action=treasury
  • Liked: 703
Re: Assembly routine to move a bullet
« Reply #3 on: 15:50, 14 September 17 »
That's rather cool.
 8)

I wonder if you could make a simple version of something like Tempest with this engine?
My entry for the CPCRetroDev 2017 Competition http://www.cpcwiki.eu/forum/programming/my-cpcretrodev-2017-entry/
FAST line drawing in CPCtelera http://www.cpcwiki.eu/forum/programming/drawing-lines-with-cpctelera-sdcc/
RUNCPC My entry for the CPCRetroDev 2015 Competition http://www.pouet.net/prod.php?which=66566

Offline AMSDOS

  • Supporter
  • 6128 Plus
  • *
  • Posts: 3.306
  • Country: au
    • index.php?action=treasury
    • Programs for Turbo Pascal 3
  • Liked: 593
Re: Assembly routine to move a bullet
« Reply #4 on: 11:43, 15 September 17 »
That's rather cool.
 8) 


Thanks.

Quote
I wonder if you could make a simple version of something like Tempest with this engine?


I'll have to play Tempest to find out, from the screenshots I looked it looks like you bear down on the aliens and give them a good blasting. At the moment the idea I'm playing at with this is a Defender / Planet Smashers sort of game. Defender in it's Horizontal nature, Planet Smashers in that if the Alien gets past you a little bit of shielding is depleted. It's pretty simple, though I'll only have 10 Lines to write it in, which means I won't be able to use this Assembly code (unless I submit for the WILD category).




Offline fgbrain

  • CPC6128
  • ****
  • Posts: 183
  • Country: gr
    • index.php?action=treasury
    • Chaos CPC Homepage
  • Liked: 77
Re: Assembly routine to move a bullet
« Reply #5 on: 22:03, 15 September 17 »
Just went through your code and I can suggest a small optimization trick:
Code: [Select]
LD HL„bx
INC (HL)  or DEC (HL)


is faster and shorter...

Moreover, you can just use this code
Code: [Select]
LD HL,(by)
CALL #BB75
_____

6128 (UK keyboard, Crtc type 0/2), 6128+ (UK keyboard), 3.5" and 5.25" drives, Reset switch and Digiblaster (selfmade), Inicron Romram box, Bryce Megaflash, SVideo & PS/2 mouse, , Magnum Lightgun, X-MEM, X4 Board, C4CPC, Multiface2 X4 and RTC X4.

Offline AMSDOS

  • Supporter
  • 6128 Plus
  • *
  • Posts: 3.306
  • Country: au
    • index.php?action=treasury
    • Programs for Turbo Pascal 3
  • Liked: 593
Re: Assembly routine to move a bullet
« Reply #6 on: 12:45, 16 September 17 »
Just went through your code and I can suggest a small optimization trick:
Code: [Select]
LD HL„bx
INC (HL)  or DEC (HL)


is faster and shorter...


Ah yes thanks! :)


Quote
Moreover, you can just use this code
Code: [Select]
LD HL,(by)
CALL #BB75


Yes I forgot to change that because initially I thought I had to increase the value of bx to delete it when it gets close to the end of the screen. Once I realised I didn't need it, I reversed the by, bx labels so I could get the right values into h & l for the Locate routine, but couldn't be bother changing the rest!  :D


I've amended the program so the lines to change are as follows:


Code: [Select]

1760 DATA DD7E02324190DD7E003240902A4090CD684
1770 DATA 75BB3E20CD5ABB214190342A4090CD756D2
1780 DATA BB3E2DCD5ABB3A4190FE2620122A4090663
1790 DATA CD75BB3E20CD5ABBAF324190324090C97BA
1800 DATA 00000000000000000000000000000000000



1230   bx(n)=PEEK(&9041):by(n)=PEEK(&9040)
1280   IF PEEK(&9041)=0 THEN b=b+1

1300 IF PEEK(&9041)=0 AND b=3 THEN GOSUB 1590




In addition to while I was testing the routine I found a bug, which can be corrected by altering the following line:


Code: [Select]

1540 FOR c=b TO t


The reason this is occurring now is because the M/C routine is returning bx(1) and by(1) to 0, this was quite tricky to track down as when I first discovered it, I tried to determine why it occurred, but it wasn't happening when I was too busy shooting blobs onscreen, however if the 1st bullet reaches the end of the screen, it gets deleted and reset to 0, the error occurs when I use my 2nd bullet to shoot the blob which triggers the Improper Argument. The routine between 1540..1580 is used to delete any remaining bullets onscreen (should one find a blob), as the 1st has disappeared, it makes that routine invalid, the b variable can be used to skip should that possibility occur, if the 2nd bullets misses then the routine won't get that far to become a problem (since it's part of the detect, though would if the blob hits the square, need to check if that could cause an error).