Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Cargas de Produndidad / Depth Charge
#1
Hi all, long time no see Smile

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.
[Image: Capture.jpg]


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

Hope you enjoy and as always, any comments are welcome. Cheers!


Attached Files
.7z   Cargas-Depthcharge.7z (Size: 13.15 KB / Downloads: 488)
Reply
#2
Woooow! Confusedhock:
Super!!

Thanks for sharing!
Reply
#3
Very nice little fun thing. Good job.

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

Code:
FUNCTION t() as uLong
asm
    DI
    LD DE,(23674)
    LD D,0
    LD HL,(23672)
    EI
end asm
end 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 Big Grin Never enough depth charges.
Reply
#4
britlion Wrote:Very nice little fun thing. Good job.

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

Code:
FUNCTION t() as uLong
asm
    DI
    LD DE,(23674)
    LD D,0
    LD HL,(23672)
    EI
end asm
end 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 Big Grin 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  Smile
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.
Spanish inlay: https://drive.google.com/open?id=1aHkpNZ...Cfx5sgDVvJ
English inlay: https://drive.google.com/open?id=1TTmyl3...31KLPwTItz

Cheers.


EDIT: just tried your ASM t() function and it's so fast I can now "play" with the sonar and add more effects  Big Grin
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.


Attached Files
.tap   Cargas_de_Profundidad_v1.0_esp.tap (Size: 21 KB / Downloads: 2)
.tap   Depth Charge_v1.0_eng.tap (Size: 20.93 KB / Downloads: 2)
Reply
#5
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?
Reply
#6
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 sonar
SUB 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
Reply
#7
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.
Reply
#8
Negative; after several tests it's still too fast and the radian still goes wild Sad Sorry, but this time I'll have to take the ASM approach :wink:

Cheers
Reply
#9
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.
Reply
#10
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 ?
Reply
#11
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.
Reply
#12
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.
Reply
#13
That Britlion said is what I tried to explain on first place (didn't make myself understood). Anyway, nice game, an congrats Smile
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)