diff --git a/demos/demo/demo_balloon.h b/demos/demo/demo_balloon.h index e30d95d..e82a8f5 100644 --- a/demos/demo/demo_balloon.h +++ b/demos/demo/demo_balloon.h @@ -1,62 +1,136 @@ #include +// the balloon sprite, manually copied from C64 User's guide #include "cbm_balloon.h" -void move_balloon(byte x, byte y, byte color) { - tms_sprite spr0,spr1; - spr0.x = x; - spr0.y = y; - spr0.name = 0; - spr0.color = color; - spr1.x = spr0.x; - spr1.y = spr0.y + 16*1; - spr1.name = spr0.name + 4; - spr1.color = spr0.color; - tms_set_sprite(0, &spr0); - tms_set_sprite(1, &spr1); +// a balloon is two 16x16 sprites, one above the other +typedef struct { + int x; // x coordinate of the balloon + int y; // y coordinate of the balloon + int dx; // x velocity of the balloon + int dy; // y velocity of the balloon + byte color; // color of the balloon + byte sprite_number; // sprite number (0-31) of the balloon + tms_sprite upper; // the upper sprite portion of the balloon + tms_sprite lower; // the lower sprite portion of the balloon +} balloon; + +// move ballon on the screen by its velocity +// and make it bounce over the borders +void animate_balloon(balloon *b) { + + // use temporary variables as KickC has issues dealing with "->" operator + int x = b->x; + int y = b->y; + int dx = b->dx; + int dy = b->dy; + + // border collision detection + if(x>=240 || x<=0) dx = -dx; + if(y>=172 || y<=0) dy = -dy; + + // move the balloon + x += dx; + y += dy; + + // write back temporary variables + b->x = x; + b->y = y; + b->dx = dx; + b->dy = dy; + + // update the sprite part of the balloon + b->upper.x = (byte) x; + b->upper.y = (signed char) y; + b->upper.name = 0; + b->upper.color = b->color; + b->lower.x = b->upper.x; + b->lower.y = b->upper.y + 16; // 16 pixels below the upper sprite + b->lower.name = b->upper.name + 4; + b->lower.color = b->color; + tms_set_sprite(b->sprite_number, &(b->upper)); + tms_set_sprite(b->sprite_number+1, &(b->lower)); } void demo_balloon() { tms_init_regs(SCREEN2_TABLE); - tms_set_color(COLOR_LIGHT_BLUE); - byte text_color = FG_BG(COLOR_GREY,COLOR_DARK_BLUE); + // we use only 4 sprites, two for each ot the two balloons on the screen + tms_set_total_sprites(4); + + // fake C64 bootup screen colors + tms_set_color(COLOR_LIGHT_BLUE); + byte text_color = FG_BG(COLOR_GREY,COLOR_DARK_BLUE); // alas, COLOR_LIGHT_BLUE doesn't fit well so we use GREY instead screen2_init_bitmap(text_color); - // 12345678901234567890123456789012 + + // C64-like screen text screen2_puts("*** COMMODORE-APPLE BASIC V2 ***", 0, 0, text_color); screen2_puts("38911 BASIC BYTES FREE" , 0, 2, text_color); screen2_puts("READY." , 0, 4, text_color); - screen2_puts(" " , 0, 5, FG_BG(COLOR_DARK_BLUE,COLOR_GREY)); - - // ballon demo - - // define sprites using bitmap fonts + + // copy the ballon graphic to VRAM tms_copy_to_vram(cbm_balloon, 4*8*2, TMS_SPRITE_PATTERNS); - tms_set_sprite_double_size(1); // set 16x16 sprites - tms_set_sprite_magnification(0); // set double pixel sprites - int x = 200; - int y = 80; - int dx = 1; - int dy = 1; - int delay = 0; - byte sprcolor = COLOR_LIGHT_YELLOW; + tms_set_sprite_double_size(1); // set 16x16 sprites + tms_set_sprite_magnification(0); // set single pixel sprites + + // we have two balloons bouncing around the screen + + // first balloon + balloon b1; + b1.x = 20; + b1.y = 20; + b1.dx = 1; + b1.dy = 1; + b1.color = COLOR_LIGHT_YELLOW; + b1.sprite_number = 0; + + // second balloon + balloon b2; + b2.x = 150; + b2.y = 150; + b2.dx = -1; + b2.dy = -1; + b2.color = COLOR_LIGHT_RED; + b2.sprite_number = 2; + + // counter for a fake blinking cursor + byte blink_counter=0; for(;;) { - for(delay=0; delay<800; delay++) { + + // delay the animation + for(int delay=0; delay<400; delay++) { delay = delay+1; delay = delay-1; } + // RETURN key ends the demo if(apple1_readkey()==0x0d) break; - - if(x>=228 || x<=0) { dx = -dx; sprcolor++; } - if(y>=148 || y<=0) { dy = -dy; sprcolor++; } - x += dx; - y += dy; - move_balloon((byte)x,(byte)y, COLOR_WHITE); + // if there's a collision invert the motion of the balloons + if(COLLISION_BIT(TMS_READ_CTRL_PORT)) { + int temp; + temp = b1.dx; b1.dx = -temp; // b1.dx = -b1.dx; // due to KickC issue + temp = b1.dy; b1.dy = -temp; // b1.dy = -b1.dy; // due to KickC issue + temp = b2.dx; b2.dx = -temp; // b2.dx = -b2.dx; // due to KickC issue + temp = b2.dy; b2.dy = -temp; // b2.dy = -b2.dy; // due to KickC issue + } + + // move the two balloons + animate_balloon(&b1); + animate_balloon(&b2); + + // since a balloon is made of two sprites, sometimes they overlap + // by one line during the move, causing a false collision + // so we clear the collision bit by simply reading the status register + tms_clear_collisions(); + + // fake a blinking cursor + blink_counter++; + if(blink_counter == 16) { screen2_puts(" ", 0, 5, FG_BG(COLOR_DARK_BLUE,COLOR_GREY)); } + if(blink_counter == 32) { screen2_puts(" ", 0, 5, FG_BG(COLOR_GREY,COLOR_DARK_BLUE)); blink_counter = 0; } } } diff --git a/demos/demo/demo_screen2.h b/demos/demo/demo_screen2.h index 38df09a..e2f7f95 100644 --- a/demos/demo/demo_screen2.h +++ b/demos/demo/demo_screen2.h @@ -28,24 +28,6 @@ void demo_screen2() { screen2_line(18+5+5, 45,232+5+5,187); screen2_line(18+5+5,187,232+5+5, 45); - screen2_plot_mode = PLOT_MODE_SET; - - // define sprites using bitmap fonts - tms_copy_to_vram(&FONT[64*8], 32*8, TMS_SPRITE_PATTERNS); - - // set 16x16 sprites - tms_set_sprite_double_size(1); - - // set double pixel sprites - tms_set_sprite_magnification(1); - - tms_sprite spr; - for(byte t=0;t<4;t++) { - spr.x = 200; - spr.y = 5 + t*32; - spr.name = t*4; - spr.color = t+1; - tms_set_sprite(t, &spr); - } + screen2_plot_mode = PLOT_MODE_SET; } diff --git a/lib/screen1.h b/lib/screen1.h index 133e561..9f0ffe4 100644 --- a/lib/screen1.h +++ b/lib/screen1.h @@ -48,12 +48,12 @@ void screen1_scroll_up() { } void screen1_prepare() { + // clear all the sprites + tms_set_total_sprites(0); + // fill name table with spaces (32) screen1_cls(); - // clear all the sprites - tms_clear_sprites(); - // fill pattern table with 0 tms_set_vram_write_addr(TMS_PATTERN_TABLE); for(word i=256*8;i!=0;i--) { diff --git a/lib/screen2.h b/lib/screen2.h index 6c3e858..d44a544 100644 --- a/lib/screen2.h +++ b/lib/screen2.h @@ -10,8 +10,8 @@ const word SCREEN2_SIZE = (32*24); // prepare the screen 2 to be used as a bitmap void screen2_init_bitmap(byte color) { - // erases all the sprites - tms_clear_sprites(); + // clear all the sprites + tms_set_total_sprites(0); // fill pattern table with 0 (clear screen) tms_set_vram_write_addr(TMS_PATTERN_TABLE); diff --git a/lib/sprites.h b/lib/sprites.h index 44fe62e..822c836 100644 --- a/lib/sprites.h +++ b/lib/sprites.h @@ -2,13 +2,22 @@ #define SPRITES_H typedef struct { - byte y; + signed char y; byte x; byte name; byte color; } tms_sprite; #define SIZEOF_SPRITE 4 +#define SPRITE_OFF_MARKER 0xD0 +#define EARLY_CLOCK 128 + +void tms_set_total_sprites(byte num) { + // write the value 0xD0 as Y coordinate of the first unused sprite + word addr = TMS_SPRITE_ATTRS + (word) (num * SIZEOF_SPRITE); + tms_set_vram_write_addr(addr); + TMS_WRITE_DATA_PORT(SPRITE_OFF_MARKER); // 0xD0 oi the sprite off indicator +} void tms_set_sprite(byte sprite_num, tms_sprite *s) { word addr = TMS_SPRITE_ATTRS + (word) (sprite_num * SIZEOF_SPRITE); @@ -34,21 +43,8 @@ void tms_set_sprite_magnification(byte m) { tms_write_reg(1, regval); } -// clears all the sprites -void tms_clear_sprites() { - // fills first sprite pattern with 0 - tms_set_vram_write_addr(TMS_SPRITE_PATTERNS); - for(byte i=0;i<8;i++) { - TMS_WRITE_DATA_PORT(0); - } - - // set sprite coordinates to (0,0) and set pattern name 0 - tms_set_vram_write_addr(TMS_SPRITE_ATTRS); - for(byte i=0;i<32;i++) { - TMS_WRITE_DATA_PORT(0); NOP; NOP; NOP; NOP; // y coordinate - TMS_WRITE_DATA_PORT(0); NOP; NOP; NOP; NOP; // x coordinate - TMS_WRITE_DATA_PORT(0); NOP; NOP; NOP; NOP; // name - TMS_WRITE_DATA_PORT(0); NOP; NOP; NOP; NOP; // color - } +// clear the collision flag by reading the status register +inline void tms_clear_collisions() { + asm { lda VDP_REG }; } #endif