News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_khaz

How many bullets can be drawn on screen?

Started by khaz, 20:03, 01 April 16

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

khaz

aka "where is my Dodonpachi Daioujou 4 CPC?"*

As I was replaying Commando recently, I noticed the game was able to draw a damn lot of bullets on screen without much slowdown, the slowdown essentially coming from the many soldier sprites. With the same sort of engine, and some of the magic people making demo have (like the dot tunnel from the Batman Forever demo), how feasible would it be to make a playable vertical shmup? Make the bullets a single fat pixel if needed (with bright magenta or bright cyan.) The 8bit consoles had some crazy shmups already, like Recca on the NES or Power Strike 2 on the Master System, though these machines have hardware scrolling and hardware sprites, I suppose it helps a lot.

* If it isn't possible, I can settle for Z80 Mushihimesama, it's OK.

TFM

In MODE 0... using overscan.... a little less then 60.000 bullets maximum. There may be some ways to do more, but I can't.
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

reidrac

#2
Depends on the size, if you draw them with mask or not, but is not just drawing (and moving them), collision detection is also expensive.

I don't know the answer, but... it all depends.
Released The Return of Traxtor, Golden Tail, Magica, The Dawn of Kernel, Kitsune`s Curse, Brick Rick and Hyperdrive for the CPC.

If you like my games and want to show some appreciation, you can always buy me a coffee.

sigh

I love shooters with vertical scrollers being my favourite. I think that Axelay would be a good bet for an answer:)

arnoldemu

@khaz:

Those "bullet hell" games are on more powerful hardware or ones which have a lot of hardware help for sprites, tilemap backgrounds, co-processor for sound etc. The CPU is organising the work and doing the AI.

On CPC we have to do all of it (except the sound), all the drawing and organising and the AI and erasing and scrolling tc.

Also it depends on the frame rate you want, 50hz or 25hz or less?

I would say it's best to design a shoot em up that doesn't need lots of bullets or if you need lots of bullets have less enemies.

I know Axelay could come up with some nice ideas and a nice vertical scroller.

On CPC it may be easier to have no background and avoid masking completely and do everything with compiled sprites, that is how you're going to make it fast enough to make the play fun.


My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

TotO

Many on R-Type, using chars...  ;D (see stage 4)
About hardware, Cave used Altera FPGA as custom VDP for doing amazing things.
Personally, I had liked the PLUS use a blitter to do those sort of things, instead of the poor sprite system...
"You make one mistake in your life and the internet will never let you live it down" (Keith Goodyer)

khaz

Quote from: arnoldemu on 16:11, 02 April 16Those "bullet hell" games are on more powerful hardware or ones which have a lot of hardware help for sprites, tilemap backgrounds, co-processor for sound etc. The CPU is organising the work and doing the AI.

Of course they are. I was wondering if the gameplay would be able to translate at all on an underpowered machine that came well before the genre was even invented.

Quote from: arnoldemu on 16:11, 02 April 16On CPC it may be easier to have no background and avoid masking completely and do everything with compiled sprites, that is how you're going to make it fast enough to make the play fun.

I was wondering this as well. Graphics aren't that important, it's more about bullet patterns. You can look at more abstract games like the ones created by Kenta Cho, who recently released BulletML, a tool to make your own bullet waves, or the 2007 homebrew BulletGBA - Software for Gameboy Advance.


BulletGBA

http://pixelnest.io/work/bulletml-for-unity/-img/screenshot1.png
http://pixelnest.io/work/bulletml-for-unity/-img/screenshot2.png
examples of bullet patterns made with BulletML in Unity.

btw, slowdowns are completely acceptable! Arcade games tend to slow down when there are too many bullets, and it's also part of the gameplay, as it allows for a finer movement and better precision from the player. Ports to home consoles are often criticised according to whether or not the arcade slowdowns are accurately reproduced.

SRS

#7
@TFM: In MODE2 it could be 128.000 Bullets. But for what ?

Proof ?

Run this in Mode 2:

org &a000
ld hl,&c000
ld de,&c001
ld bc,&3fff
ld a,255
ld (hl),a
ldir
ret

Axelay

I think if you want a vertically scrolling backdrop, the answer is no, or not at much of a frame rate.  You'd be looking at something more traditional with a reasonable frame rate using a hardware scroll, but that would be about the limit.

Making the assumption of a clear, non scrolling background though, maybe there is some sort of possibility.  I've thrown together a bit of a bullet test, code below, assuming 32x32 char screen, 1 pixel mode 0 bullets. I've assumed there'd be a need for 16bit co-ordinates to allow for sub pixel movement, as I dont imagine you'd get very convincing fans of bullets otherwise, but that's just an initial thought, and it's quite slow, even without checking for going off the screen edge, so it would be slower still.  The end result is 128 bullets are taking about 3/4 of a screen refresh.  Maybe enough for a half way servicable 50fps or 25fps game, perhaps.

As an idea to reduce cpu time on collision, I've drawn the bullets making an assumption of 'dual playfield' with 3 bits for 8 colours for player bullets and other objects, and 1 bit for the enemy bullets in one colour.  This would mean that instead of having to collision detect every individual enemy bullet on the player by co-ordinates, you could just check a couple of bytes of screen ram at the centre of the player position.  Assuming the goal is bullet count and speed, not visual quality.


org &2000
run &2000
nolist

EBHighAddr equ &3f00
EBLowAddr equ &3e00
EBY equ &3b00
EBX equ &3c00
EBMv equ &3d00


.start
    di
    ld sp,&38
; set screen to mode 0 and 32x32
    ld bc,&7F8c
    out (c),c
;; set width of display window
;; this value is compatible with crtc type 2
ld bc,&bc01
out (c),c
ld bc,&bd00+32
out (c),c

;; set horizontal sync position; and therefore the
;; horizontal position of the display window
;; within the monitor display
;;
;; this value is compatible with crtc type 2
ld bc,&bc02
out (c),c
ld bc,&bd00+42;50 ;48
out (c),c

; during last interupt, wait until above 3rd last char line, only 2.5 chars visible, and set all colours to 1
;; set height of display window
ld bc,&bc06
out (c),c
ld bc,&bd00+32 ;45 ;35
out (c),c

;; set vertical sync position; and therefore the
;; vertical position of the display window
;; within the monitor display
ld bc,&bc07
out (c),c
ld bc,&bd00+34 ;47 ;35
out (c),c

ld hl,&8000
ld de,&8001
ld bc,&7fff
ld (hl),0
ldir
; make addr lookup tables
    call FillTitleScrLists

; fill scr addr list with dummy addr
    ld hl,EBLowAddr
    ld (hl),0
    ld de,EBLowAddr+1
    ld bc,&1ff
    ldir

; test co-ords
    ld hl,EBY+1
    ld de,EBMv
    ld b,128
.TestBulLp
    ld (hl),l
    inc h
    ld a,l
    and a,&7f
    ld (hl),a
    dec h
    ld a,l
    inc l
    inc l
    ld (de),a
    inc e
    neg
    ld (de),a
    inc e
    djnz TestBulLp

.MainLoop
    call FrameFlyB
    ld a,(WorkScr)
    ld e,a
    xor a,&40
    ld (WorkScr),a
    ld a,e
    rrca
    rrca
    ld bc,&bc0c
    out (c),c
    inc b
    out (c),a

;    ld hl,8*100
;    call delay
    ld bc,&7f10
    out (c),c
    ld bc,&7f44
    out (c),c

    call ClearNBullets
    ld bc,&7f10
    out (c),c
    ld bc,&7f46
    out (c),c
    call MoveNBullets
    ld bc,&7f10
    out (c),c
    ld bc,&7f56
    out (c),c
    call PrintBullets
    ld bc,&7f10
    out (c),c
    ld bc,&7f54
    out (c),c

    jr MainLoop

.WorkScr
    defb &c0

.ClearNBullets
; simply pop the 128 screen addresses for every bullet of current work screen and clear
; inactive bullets assumed to provide legal dummy to avoid checking
    ld (CNBExit+1),sp
    ld a,(WorkScr)
    bit 6,a
    jr nz,CNBHighClear
    ld sp,EBLowAddr
    jr CNBSkipHigh
.CNBHighClear
    ld sp,EBHighAddr
.CNBSkipHigh
    ld b,16
    xor a
.CNBLoop
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    djnz CNBLoop
.CNBExit
    ld sp,0
    ret

.PrintBullets
    ld (PNBExit+1),sp
    ld a,(WorkScr)
    bit 6,a
    jr nz,PNBHighPrint
    ld sp,EBLowAddr+&100
    exx
    ld h,&37 ; high byte of lookup table for low screen (&8000)
    jr PNBSkipHigh
.PNBHighPrint
    ld sp,EBHighAddr+&100
    exx
    ld h,&39 ; high byte of lookup table for high screen (&c000)
.PNBSkipHigh
    exx
    ld b,128
    ld hl,EBY+1 ; point to y co-ordinate, sub pixel co-ord not required
.PNBLoop
    ld a,(hl) ; get y
    inc h
    exx
    ld l,a    ; use it to point to low byte of screen address in lu table
    ld e,(hl)
    inc h
    ld d,(hl) ; base address in de
    dec h
    ex de,hl
    exx
    ld a,(hl) ; get x co-ord of bullet
    dec h
    inc l
    inc l ; set hl to point to y co-ord for next bullet
    exx
    srl a ; x = 0-127, halved as 64 bytes, bit 0 determines pixel position in byte
    jr c,PNBRight
; Print enemy bullet left
    or a,l
    ld l,a
    set 1,(hl)
    push hl
    ex de,hl
    exx
    djnz PNBLoop
    jr PNBExit
.PNBRight
; Print enemy bullet right
    or a,l
    ld l,a
    set 0,(hl)
    push hl
    ex de,hl
    exx
    djnz PNBLoop
.PNBExit
    ld sp,0
    ret

.MoveNBullets
    exx
    ld hl,EBY
    exx
    ld hl,EBMv
    ld b,128
.MNBLoop
    ld a,(hl) ; get y move
    exx
    ld e,(hl)
    inc l
    ld d,(hl) ; de holds current y
    ld b,0
    add a,a ; bit 7 determines if bullet moving up or down
    jr nc,MNBNotNegY
    ld b,&ff ; if moving up, make bc 'negative'
.MNBNotNegY
    ld c,a
    ex de,hl ; put current y in hl
    add hl,bc
    add hl,bc ; double the y move
    ex de,hl
    ld (hl),d
    dec l
    ld (hl),e ; write back new y
; now do x - almost identical to y
    inc h
    exx
    inc l
    ld a,(hl)
    exx
    ld e,(hl)
    inc l
    ld d,(hl)
    ld b,0
    add a,a
    jr nc,MNBNotNegX
    ld b,&ff
.MNBNotNegX
    ld c,a
    ex de,hl
    add hl,bc
    add hl,bc
    res 7,h ; x maximum of 127
    ex de,hl
    ld (hl),d
    dec l
    ld (hl),e
; now get to next bullet
    dec h
    inc l
    inc l
    exx
    inc l
    djnz MNBLoop
.MNBExit
    ret

.FrameFlyB
    ld b,&f5
.FFBLoop
    in a,(c)
    rra
    jr nc,FFBLoop
    ret

.delay
    dec hl
    nop
    ld a,h
    or l
    jr nz,delay
    ret

.FillTitleScrLists
; first fill screen address list
    ld de,&8000
    ld hl,&3700 ; location for screen address list
    call FillTitleScrAddr
    ld de,&c000
    ld hl,&3900 ; location for screen address list
.FillTitleScrAddr
    ld b,32
.FillTitleSRLpO
    ld c,8
    push de
.FillTitleSRLpI
    ld (hl),e
    inc h
    ld (hl),d
    dec h
    inc l
    ld a,&8
    add a,d
    ld d,a
    dec c
    jr nz,FillTitleSRLpI
    pop de
    ld a,64
    add a,e
    ld e,a
    jr nc,FillTitleLpOSkip
    inc d
.FillTitleLpOSkip
    djnz FillTitleSRLpO
    ret


sigh

#9
Quote from: Axelay on 08:27, 03 April 16
I think if you want a vertically scrolling backdrop, the answer is no, or not at much of a frame rate.  You'd be looking at something more traditional with a reasonable frame rate using a hardware scroll, but that would be about the limit.

Making the assumption of a clear, non scrolling background though, maybe there is some sort of possibility.  I've thrown together a bit of a bullet test, code below, assuming 32x32 char screen, 1 pixel mode 0 bullets. I've assumed there'd be a need for 16bit co-ordinates to allow for sub pixel movement, as I dont imagine you'd get very convincing fans of bullets otherwise, but that's just an initial thought, and it's quite slow, even without checking for going off the screen edge, so it would be slower still.  The end result is 128 bullets are taking about 3/4 of a screen refresh.  Maybe enough for a half way servicable 50fps or 25fps game, perhaps.

As an idea to reduce cpu time on collision, I've drawn the bullets making an assumption of 'dual playfield' with 3 bits for 8 colours for player bullets and other objects, and 1 bit for the enemy bullets in one colour.  This would mean that instead of having to collision detect every individual enemy bullet on the player by co-ordinates, you could just check a couple of bytes of screen ram at the centre of the player position.  Assuming the goal is bullet count and speed, not visual quality.


org &2000
run &2000
nolist

EBHighAddr equ &3f00
EBLowAddr equ &3e00
EBY equ &3b00
EBX equ &3c00
EBMv equ &3d00


.start
    di
    ld sp,&38
; set screen to mode 0 and 32x32
    ld bc,&7F8c
    out (c),c
;; set width of display window
;; this value is compatible with crtc type 2
ld bc,&bc01
out (c),c
ld bc,&bd00+32
out (c),c

;; set horizontal sync position; and therefore the
;; horizontal position of the display window
;; within the monitor display
;;
;; this value is compatible with crtc type 2
ld bc,&bc02
out (c),c
ld bc,&bd00+42;50 ;48
out (c),c

; during last interupt, wait until above 3rd last char line, only 2.5 chars visible, and set all colours to 1
;; set height of display window
ld bc,&bc06
out (c),c
ld bc,&bd00+32 ;45 ;35
out (c),c

;; set vertical sync position; and therefore the
;; vertical position of the display window
;; within the monitor display
ld bc,&bc07
out (c),c
ld bc,&bd00+34 ;47 ;35
out (c),c

ld hl,&8000
ld de,&8001
ld bc,&7fff
ld (hl),0
ldir
; make addr lookup tables
    call FillTitleScrLists

; fill scr addr list with dummy addr
    ld hl,EBLowAddr
    ld (hl),0
    ld de,EBLowAddr+1
    ld bc,&1ff
    ldir

; test co-ords
    ld hl,EBY+1
    ld de,EBMv
    ld b,128
.TestBulLp
    ld (hl),l
    inc h
    ld a,l
    and a,&7f
    ld (hl),a
    dec h
    ld a,l
    inc l
    inc l
    ld (de),a
    inc e
    neg
    ld (de),a
    inc e
    djnz TestBulLp

.MainLoop
    call FrameFlyB
    ld a,(WorkScr)
    ld e,a
    xor a,&40
    ld (WorkScr),a
    ld a,e
    rrca
    rrca
    ld bc,&bc0c
    out (c),c
    inc b
    out (c),a

;    ld hl,8*100
;    call delay
    ld bc,&7f10
    out (c),c
    ld bc,&7f44
    out (c),c

    call ClearNBullets
    ld bc,&7f10
    out (c),c
    ld bc,&7f46
    out (c),c
    call MoveNBullets
    ld bc,&7f10
    out (c),c
    ld bc,&7f56
    out (c),c
    call PrintBullets
    ld bc,&7f10
    out (c),c
    ld bc,&7f54
    out (c),c

    jr MainLoop

.WorkScr
    defb &c0

.ClearNBullets
; simply pop the 128 screen addresses for every bullet of current work screen and clear
; inactive bullets assumed to provide legal dummy to avoid checking
    ld (CNBExit+1),sp
    ld a,(WorkScr)
    bit 6,a
    jr nz,CNBHighClear
    ld sp,EBLowAddr
    jr CNBSkipHigh
.CNBHighClear
    ld sp,EBHighAddr
.CNBSkipHigh
    ld b,16
    xor a
.CNBLoop
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    djnz CNBLoop
.CNBExit
    ld sp,0
    ret

.PrintBullets
    ld (PNBExit+1),sp
    ld a,(WorkScr)
    bit 6,a
    jr nz,PNBHighPrint
    ld sp,EBLowAddr+&100
    exx
    ld h,&37 ; high byte of lookup table for low screen (&8000)
    jr PNBSkipHigh
.PNBHighPrint
    ld sp,EBHighAddr+&100
    exx
    ld h,&39 ; high byte of lookup table for high screen (&c000)
.PNBSkipHigh
    exx
    ld b,128
    ld hl,EBY+1 ; point to y co-ordinate, sub pixel co-ord not required
.PNBLoop
    ld a,(hl) ; get y
    inc h
    exx
    ld l,a    ; use it to point to low byte of screen address in lu table
    ld e,(hl)
    inc h
    ld d,(hl) ; base address in de
    dec h
    ex de,hl
    exx
    ld a,(hl) ; get x co-ord of bullet
    dec h
    inc l
    inc l ; set hl to point to y co-ord for next bullet
    exx
    srl a ; x = 0-127, halved as 64 bytes, bit 0 determines pixel position in byte
    jr c,PNBRight
; Print enemy bullet left
    or a,l
    ld l,a
    set 1,(hl)
    push hl
    ex de,hl
    exx
    djnz PNBLoop
    jr PNBExit
.PNBRight
; Print enemy bullet right
    or a,l
    ld l,a
    set 0,(hl)
    push hl
    ex de,hl
    exx
    djnz PNBLoop
.PNBExit
    ld sp,0
    ret

.MoveNBullets
    exx
    ld hl,EBY
    exx
    ld hl,EBMv
    ld b,128
.MNBLoop
    ld a,(hl) ; get y move
    exx
    ld e,(hl)
    inc l
    ld d,(hl) ; de holds current y
    ld b,0
    add a,a ; bit 7 determines if bullet moving up or down
    jr nc,MNBNotNegY
    ld b,&ff ; if moving up, make bc 'negative'
.MNBNotNegY
    ld c,a
    ex de,hl ; put current y in hl
    add hl,bc
    add hl,bc ; double the y move
    ex de,hl
    ld (hl),d
    dec l
    ld (hl),e ; write back new y
; now do x - almost identical to y
    inc h
    exx
    inc l
    ld a,(hl)
    exx
    ld e,(hl)
    inc l
    ld d,(hl)
    ld b,0
    add a,a
    jr nc,MNBNotNegX
    ld b,&ff
.MNBNotNegX
    ld c,a
    ex de,hl
    add hl,bc
    add hl,bc
    res 7,h ; x maximum of 127
    ex de,hl
    ld (hl),d
    dec l
    ld (hl),e
; now get to next bullet
    dec h
    inc l
    inc l
    exx
    inc l
    djnz MNBLoop
.MNBExit
    ret

.FrameFlyB
    ld b,&f5
.FFBLoop
    in a,(c)
    rra
    jr nc,FFBLoop
    ret

.delay
    dec hl
    nop
    ld a,h
    or l
    jr nz,delay
    ret

.FillTitleScrLists
; first fill screen address list
    ld de,&8000
    ld hl,&3700 ; location for screen address list
    call FillTitleScrAddr
    ld de,&c000
    ld hl,&3900 ; location for screen address list
.FillTitleScrAddr
    ld b,32
.FillTitleSRLpO
    ld c,8
    push de
.FillTitleSRLpI
    ld (hl),e
    inc h
    ld (hl),d
    dec h
    inc l
    ld a,&8
    add a,d
    ld d,a
    dec c
    jr nz,FillTitleSRLpI
    pop de
    ld a,64
    add a,e
    ld e,a
    jr nc,FillTitleLpOSkip
    inc d
.FillTitleLpOSkip
    djnz FillTitleSRLpO
    ret



It looks like a snowstorm. Very nice.

I was wondering if graphics were a problem, I remember a vertical shooter that was made with ascii text. It was incredibly fast and they used the asterix "*" for explosions, the letter "o" for the enemy bullets, the "()" for the player bullets along with a simple star field  background that was just the fullstops "."

It was an excellent a creative game and I played it to death! I lost it on my old Toshiba pentium laptop :(

Would something like this be possible using ascii/text on the CPC but keeping the speed and smoothness?

SPACESHIPS - ASCII ART

Sykobee (Briggsy)

Unfortunately the CPC doesn't have a text mode where such an ASCII based solution would make sense.


I'm guessing that if your game palette is laid out well (or the game background is mostly consistent), you will be able to render bullets with XOR, so you just [render, vsync, render (to erase), move].


Movement - there's another issue. Fastest is to write bytes to screen addresses, but that gives you only 80 x positions for the bullets (and wide bullets). So non-straight-down/up bullets will have less smooth movement on that axis. The benefit, of course, is likely to be a 3x speed up in bullet rendering as it's writes only, not shift, read, and/or merge, etc.

Powered by SMFPacks Menu Editor Mod