prog8/examples/c64/balloonflight.p8
2024-10-13 00:51:07 +02:00

211 lines
7.8 KiB
Lua

%import syslib
%import textio
%import math
; C64 version of a balloon sprites flying over a mountain landscape.
; There is also a X16 version of this in the examples.
main {
bool do_char_scroll = false
sub start() {
uword moon_x = 310
c64.set_sprite_ptr(0, $0f00) ; alternatively, set directly: c64.SPRPTR[0] = $0f00 / 64
c64.set_sprite_ptr(1, $0f00+64) ; alternatively, set directly: c64.SPRPTR[0] = $0f00 / 64
c64.SPENA = %00000011
c64.SP0COL = 14
c64.SP1COL = 7
c64.SPXY[0] = 80
c64.SPXY[1] = 100
set_moon_pos(moon_x)
c64.SCROLX &= %11110111 ; 38 column mode
sys.set_rasterirq(&irq.irqhandler, 250) ; enable animation via raster interrupt
ubyte target_height = 10
ubyte active_height = 25
bool upwards = true
repeat {
ubyte mountain = 223 ; slope upwards
if active_height < target_height {
active_height++
upwards = true
} else if active_height > target_height {
mountain = 233 ; slope downwards
active_height--
upwards = false
} else {
; determine new height for next mountain
ubyte old_height = target_height
if upwards {
mountain = 233
while target_height >= old_height
target_height = 9 + math.rnd() % 15
} else {
mountain = 223
while target_height <= old_height
target_height = 9 + math.rnd() % 15
}
}
while not do_char_scroll {
; let the raster irq do its timing job
}
do_char_scroll = false
scroll_characters_left()
; float the balloon and the moon sprites
if math.rnd() & 1 !=0
c64.SPXY[1] ++
else
c64.SPXY[1] --
moon_x--
if msb(moon_x)==255
moon_x = 340
set_moon_pos(moon_x)
; draw new mountain etc.
const ubyte RIGHT_COLUMN = 39
ubyte yy
for yy in 0 to active_height-1 {
txt.setcc(RIGHT_COLUMN, yy, 32, 2) ; clear top of screen
}
txt.setcc(RIGHT_COLUMN, active_height, mountain, 8) ; mountain edge
for yy in active_height+1 to 24 {
txt.setcc(RIGHT_COLUMN, yy, 160, 8) ; draw filled mountain
}
ubyte clutter = math.rnd()
if clutter > 100 {
; draw a star
txt.setcc(RIGHT_COLUMN, clutter % (active_height-1), sc:'.', math.rnd())
}
if clutter > 200 {
; draw a tree
ubyte tree = sc:''
ubyte treecolor = 5
if clutter & %00010000 != 0
tree = sc:''
else if clutter & %00100000 != 0
tree = sc:''
if math.rnd() > 130
treecolor = 13
txt.setcc(RIGHT_COLUMN, active_height, tree, treecolor)
}
if clutter > 235 {
; draw a camel
txt.setcc(RIGHT_COLUMN, active_height, sc:'π', 9)
}
}
}
sub set_moon_pos(uword x) {
c64.SPXY[2] = lsb(x)
c64.SPXY[3] = 55
if msb(x)!=0
c64.MSIGX |= %00000010
else
c64.MSIGX &= %11111101
}
sub scroll_characters_left () {
; Scroll the bottom half (approx.) of the character screen 1 character to the left
; contents of the rightmost column are unchanged, you should clear/refill this yourself
; Without clever split-screen tricks, the C64 is not fast enough to scroll the whole
; screen smootly without tearing. So for simplicity it's constrained to less rows
; such that what is scrolled, *does* scrolls smoothly.
; For maximum performance the scrolling is done in unrolled assembly code.
%asm {{
ldx #0
ldy #38
-
.for row=10, row<=24, row+=1
lda cbm.Screen + 40*row + 1,x
sta cbm.Screen + 40*row + 0,x
lda cbm.Colors + 40*row + 1,x
sta cbm.Colors + 40*row + 0,x
.next
inx
dey
bpl -
rts
}}
}
}
irq {
; does the smooth scrolling immediately after the visible screen area,
; so there is no screen tearing. The main loop does the "big" character
; scrolling when the soft-scroll runs out after 8 pixels
ubyte smoothx=0
sub irqhandler() -> bool {
smoothx = (smoothx-1) & 7
main.do_char_scroll = smoothx==7
c64.SCROLX = (c64.SCROLX & %11111000) | smoothx
return false
}
}
spritedata $0f00 {
; this memory block contains the sprite data. it must start on an address aligned to 64 bytes.
; for simplicity, it's currently statically located at $0f00 (not far in memory after the program code),
; but there are ways to do this more dynamically.
%option force_output ; make sure the data in this block appears in the resulting program
ubyte[] balloonsprite = [ %00000000,%01111111,%00000000,
%00000001,%11111111,%11000000,
%00000011,%11111111,%11100000,
%00000011,%11100011,%11100000,
%00000111,%11011100,%11110000,
%00000111,%11011101,%11110000,
%00000111,%11011100,%11110000,
%00000011,%11100011,%11100000,
%00000011,%11111111,%11100000,
%00000011,%11111111,%11100000,
%00000010,%11111111,%10100000,
%00000001,%01111111,%01000000,
%00000001,%00111110,%01000000,
%00000000,%10011100,%10000000,
%00000000,%10011100,%10000000,
%00000000,%01001001,%00000000,
%00000000,%01001001,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00011100,%00000000,
0]
ubyte[] moonsprite = [ %00000000,%00000110,%00000000,
%00000000,%00011100,%00000000,
%00000000,%01111000,%00000000,
%00000000,%11111000,%00000000,
%00000001,%11110000,%00000000,
%00000011,%11110000,%00000000,
%00000011,%11110000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000111,%11100000,%00000000,
%00000011,%11110000,%00000000,
%00000011,%11110000,%00000000,
%00000001,%11110000,%00000000,
%00000000,%11111000,%00000000,
%00000000,%01111000,%00000000,
%00000000,%00011100,%00000000,
%00000000,%00000110,%00000000,
0]
}