## Cargas de Produndidad / Depth Charge

Moderator: nitrofurano

Posts: 96

Joined: Tue Jul 12, 2011 5:23 pm

### Cargas de Produndidad / Depth Charge

Hi all, long time no see

Thanks to some spare time, I had the opportunity to retake the speccy programming, so here is my last creation: a clone of the Depthcharge arcade game. Nothing fancy, but at least I could have some fun developing for ours old but reliable Spectrums.
Game mechanic is simple: move your ship left and right and drop charges to destroy submarines, while avoiding their missiles. Number of submarines and missiles can be chosen at each game start.

The file attached contains:
- .TAP Spanish version
- .TAP English version
- Source code for both versions

Hope you enjoy and as always, any comments are welcome. Cheers!
Attachments
Cargas-Depthcharge.7z

Posts: 1538

Joined: Wed Nov 01, 2006 6:18 pm

Location: Santa Cruz de Tenerife, Spain

### Re: Cargas de Produndidad / Depth Charge

Woooow!
Super!!

Thanks for sharing!

Posts: 797

Joined: Mon Apr 27, 2009 7:26 pm

Location: Slough, Berkshire, UK

### Re: Cargas de Produndidad / Depth Charge

Very nice little fun thing. Good job.

By the way, my sneaky fast t() function is:

Code:
`FUNCTION t() as uLongasm    DI    LD DE,(23674)    LD D,0    LD HL,(23672)    EIend asmend function`

Which saves a lot of maths and division. If you want to divide by 50 to get whole seconds, you can do it outside the function - but generally, I found t() returning clock ticks and working with them as 50 times larger meant I have more precision on where I launch events. (Instead of at 1s, 2s, 3s, I go 50 frames, 100 frames, 150 frames - and then if I want to I can tweak that to 40,80,120 much more easily).

I notice you are actually using it in the line:
a = t1 / 30 * PI

So to get t you do a lot of stack work, then divide by 50 - and then divide by 30. I think I'd do it as frames and divide by 150 in one go when setting a, which is probably shorter than running the full division twice.

Anyway. Just my thougts. The game is quite fun Never enough depth charges.

Posts: 96

Joined: Tue Jul 12, 2011 5:23 pm

### Re: Cargas de Produndidad / Depth Charge

britlion wrote:Very nice little fun thing. Good job.

By the way, my sneaky fast t() function is:

Code:
`FUNCTION t() as uLongasm    DI    LD DE,(23674)    LD D,0    LD HL,(23672)    EIend asmend function`

Which saves a lot of maths and division. If you want to divide by 50 to get whole seconds, you can do it outside the function - but generally, I found t() returning clock ticks and working with them as 50 times larger meant I have more precision on where I launch events. (Instead of at 1s, 2s, 3s, I go 50 frames, 100 frames, 150 frames - and then if I want to I can tweak that to 40,80,120 much more easily).

I notice you are actually using it in the line:
a = t1 / 30 * PI

So to get t you do a lot of stack work, then divide by 50 - and then divide by 30. I think I'd do it as frames and divide by 150 in one go when setting a, which is probably shorter than running the full division twice.

Anyway. Just my thougts. The game is quite fun Never enough depth charges.

Many thanks! I'm not fond on ASM so any input is very welcome; at least I can compare your code with mine and learn something new
Besides, I updated the game with a few improvements: sonar is now draw OK , added a minor visual effect on it, load screen and intro music. And the inlays, shared with my other Escape game.

Cheers.

EDIT: just tried your ASM t() function and it's so fast I can now "play" with the sonar and add more effects
Anyway, just to try to understand a bit of ASM with your function:

DI -> disables interruptions, so the program won't interfere with the function
LD DE,(23674) -> load the value of the 23674 address (part of the Spectrum frames system variable) in the DE register (one of the Spectrum 8+8 -pair- bit registers)
LD D,0 -> load 0 into D register (?)
LD HL,(23672) -> load the value of the 23674 address (part of the Spectrum frames system variable) in the HL register (one of the Spectrum 8+8 -pair- bit registers)
EI -> enables interruptions before existing function

But the function, what returns? The sum of all values? And why load a zero value into D? Sorry if they are basic ASM questions, but my knowledge of ASM and the Z80 are almost none.
Attachments
Cargas-Depthcharge_v1.01.7z

Posts: 1538

Joined: Wed Nov 01, 2006 6:18 pm

Location: Santa Cruz de Tenerife, Spain

### Re: Cargas de Produndidad / Depth Charge

Note: You can directly do that in ZXBasic (replacing the ASM function) with:
Code:
`t = PEEK(Ulong, 23672) BAND 0xFFFFFF`

It won't be perhaps as fast as the ASM. Can you check it?

Posts: 96

Joined: Tue Jul 12, 2011 5:23 pm

### Re: Cargas de Produndidad / Depth Charge

boriel wrote:Note: You can directly do that in ZXBasic (replacing the ASM function) with:
Code:
`t = PEEK(Ulong, 23672) BAND 0xFFFFFF`

It won't be perhaps as fast as the ASM. Can you check it?

Tested and it's way faster than ASM; in fact, I can't control the speed of the sonar pointer. With the ASM function, I can do that changing the 360 in a = t1 / 360 * PI: REM a is the seconds pointer in radians line.
This is how the sonar subroutine is defined right now:
Code:
`REM Rutina del sonarSUB sonar()   REM sonido del sonar   segundos = segundos + 1   if segundos = 15 then      beep 0.07,45 : beep 0.13,30      segundos = 0      poke 23164+(RND*3),135      poke 23196+(RND*3),135      poke 23228+(RND*3),135         end if         REM grafico del sonar      FUNCTION t() as uLong      asm            DI            LD DE,(23674)            LD D,0            LD HL,(23672)            EI      end asm   end function   DIM t1 AS FLOAT   t1 = t()   a = t1 / 360 * PI: REM a is the seconds pointer in radians   sx = 20 * SIN a : LET sy = 20 * COS a   PLOT 237, 28: DRAW sx, sy      if sx2 <> sx then      over 1      PLOT 237, 28: DRAW sx2, sy2      sx2 = sx : sy2 = sy      over 0      CIRCLE 236, 28, 18      CIRCLE 236, 28, 13      CIRCLE 236, 28, 8      plot 236,9 : draw 0,38      plot 217,28 : draw 38,0   end if      if sx > 19.9 or sx < -19.9 or (sx > 0 and sx < 3) then      resetsonar = resetsonar + 1      if resetsonar = 1 then         for y = 18 to 23          print at y,27; "     ";         next y         CIRCLE 236, 28, 18         CIRCLE 236, 28, 13         CIRCLE 236, 28, 8         plot 236,9 : draw 0,38         plot 217,28 : draw 38,0      end if   else      resetsonar = 0   end if      return   END sub`

Cheers

Posts: 1538

Joined: Wed Nov 01, 2006 6:18 pm

Location: Santa Cruz de Tenerife, Spain

### Re: Cargas de Produndidad / Depth Charge

Ups, sorry. For the PEEK, it's in 1/50th of second. You have to divide by 50 to get the real value in seconds.

Posts: 96

Joined: Tue Jul 12, 2011 5:23 pm

### Re: Cargas de Produndidad / Depth Charge

Negative; after several tests it's still too fast and the radian still goes wild Sorry, but this time I'll have to take the ASM approach

Cheers

Posts: 797

Joined: Mon Apr 27, 2009 7:26 pm

Location: Slough, Berkshire, UK

### Re: Cargas de Produndidad / Depth Charge

How the heck is the compiled code faster than the ASM one? *blink*

I thought the ASM one was pretty optimal - I can't see how to do it faster. I must check that. Are you sure it's working correctly (if too fast) with it?

The ASM one does:

DI - disable interrupts. Just for a moment, it stops the clock. This means it can't tick mid measure. Technically it will lose a frame very very _very_ rarely, but in practice nobody would notice. It's a safety device to make all the bytes consistent while we read it.

LD DE, (23674) - The clock is at 23672,23763,23674. This loads D up with (23675) and E up with (23674). The contents of 23675 are redundant - it's a 3 byte clock, so we clear D with
LD D,0
LD HL, (23672) loads H with (23673) and L with (23672).
EI - Put interrupts back. We've got our numbers.
end ASM
Back to normal.

So all we've done is copy the clock bytes into DEHL (well, 0+E+H+L)
Since the function returns a uLong, which is 4 bytes in DEHL, it returns this number.

Boriel's peek method is technically not interrupt safe, by the way, though the probability of an interrupt hitting right in the middle of those small set of instructions is fairly low. That said, it's going to happen eventually.
Last edited by britlion on Sun Dec 09, 2018 6:19 pm, edited 3 times in total.

Posts: 797

Joined: Mon Apr 27, 2009 7:26 pm

Location: Slough, Berkshire, UK

### Re: Cargas de Produndidad / Depth Charge

Doesn't that peek band 63 (FFFFFF) mean that it only returns numbers from 0-63 ? That's a bit short. It rolls over every second and a bit, surely?

Shouldn't it be peek band 0xFFFFFFFFFFFFFFFFFFFFFFFF ?

Posts: 797

Joined: Mon Apr 27, 2009 7:26 pm

Location: Slough, Berkshire, UK

### Re: Cargas de Produndidad / Depth Charge

Code:
`a = t1 / 360 * PI: REM a is the seconds pointer in radians`

Surely this is 50 times too fast? My t() function returns FRAMES, not seconds - so it returns 50ths of a second as a count.

Posts: 96

Joined: Tue Jul 12, 2011 5:23 pm

### Re: Cargas de Produndidad / Depth Charge

britlion wrote:How the jeck is the compiled cosde faster than the ASM on? *blink*

You are right, my mistake :-S I really wanted to say I didn't know to implement/control the code provided by boriel as opposite as yours, what works "as is", without any modification.

Posts: 1538

Joined: Wed Nov 01, 2006 6:18 pm

Location: Santa Cruz de Tenerife, Spain

### Re: Cargas de Produndidad / Depth Charge

That Britlion said is what I tried to explain on first place (didn't make myself understood). Anyway, nice game, an congrats