#include #include #include #include // number of sprite patterns #define NUM_SPRITE_PATTERNS 1 // Sprite bitmap -- can edit with Edit Bitmap button const uint8_t sprite_data[NUM_SPRITE_PATTERNS][32] = {/*{w:16,h:16,remap:[4,0,1,2,3],brev:1}*/ {0xE0, 0xC0, 0xA0, 0x11, 0x0B, 0x05, 0x0B, 0x1F, 0x1F, 0x0F, 0x05, 0x0B, 0x11, 0xA0, 0xC0, 0xE0, 0x07, 0x03, 0x05, 0x88, 0xD0, 0xA0, 0xD0, 0xF8, 0xF8, 0xD0, 0xA0, 0xD0, 0x88, 0x05, 0x03, 0x07} }; const cv_vmemp IMAGE = 0x1800; const cv_vmemp SPRITES = 0x3c00; const cv_vmemp SPRITE_PATTERNS = 0x3800; // Make this variable volatile since it's modified in the NMI handler. volatile bool vblank; // NMI handler routine. void nmi(void) { vblank = true; } // Wait for next VBLANK (next frame) void waitvblank() { vblank = false; // reset vblank flag while(!vblank); // wait for the NMI handler to set this flag. } // Move sprite s with specified controller. void move_cursor(struct cvu_sprite *s, int controller) { int x, y; struct cv_controller_state cs; // Read the game controller state. cv_get_controller_state(&cs, controller); // Copy the sprite X and Y coordinates to local variables. x = s->x; y = s->y; // Move one pixel in the direction the joystick is pointed. if (cs.joystick & CV_RIGHT) x++; if (cs.joystick & CV_LEFT) x--; if (cs.joystick & CV_DOWN) y++; if (cs.joystick & CV_UP) y--; // Move cursor by the spinner controllers (if present) x += cvu_get_spinner(0); y += cvu_get_spinner(1); // Make sure cursor doesn't leave the screen. if(x < 0) x = 0; if(x > 239) x = 239; if(y < 0) y = 0; if(y > 152) y = 152; // Update the cursor struct in CPU RAM. s->x = x; s->y = y; } // Set all sprites offscreen. void set_sprites_offscreen() { struct cvu_sprite s; s.x = 0; s.y = 208; // set offscreen s.name = 0; s.tag = 0; for (int i=0; i<32; i++) { cvu_set_sprite(SPRITES, i, &s); // set sprite in Video RAM } } void setup_vdp() { cv_set_screen_active(false); // Switch screen off. cv_set_color_table(0x3fff); cv_set_character_pattern_t(0x1fff); cv_set_image_table(IMAGE); cv_set_sprite_pattern_table(SPRITE_PATTERNS); cv_set_sprite_attribute_table(SPRITES); cv_set_screen_mode(CV_SCREENMODE_BITMAP); // Doesn't really matter much here. We only need a screen mode that supports sprites. cvu_vmemset(0, 0, 0x4000); // clear Video RAM } void main(void) { struct cvu_sprite s; // The sprite used for the player cursor. struct cvu_sprite s2; // The sprite used for the target cursor. setup_vdp(); cv_set_sprite_magnification(false); // no sprite magnification cv_set_sprite_big(true); // 16x16 pixel sprites. // Set all sprites offscreen initially. // This ensures they won't set the collision bit. set_sprites_offscreen(); // Set attributes for sprite 0. s.x = 60; s.y = 60; s.name = 0; // Use sprite pattern number 0. cvu_set_sprite_color(&s, CV_COLOR_WHITE); // Set attributes for sprite 1. s2.x = 120; s2.y = 60; s2.name = 0; cvu_set_sprite_color(&s2, CV_COLOR_YELLOW); // Copy sprite pattern number 0 to graphics memory. // Each sprite takes up 16*2 = 32 bytes. cvu_memtovmemcpy(SPRITE_PATTERNS, sprite_data, NUM_SPRITE_PATTERNS*32); // Turn on video display. cv_set_screen_active(true); // Set NMI handler so we can detect VBLANK. cv_set_vint_handler(nmi); // Set background color cv_set_colors(0, CV_COLOR_BLUE); for(;;) { // Wait for VBLANK (next frame). waitvblank(); // Turn sprite 0 red if there was a collision last frame. cvu_set_sprite_color(&s, cv_get_sprite_collission() ? CV_COLOR_RED : CV_COLOR_WHITE); // Move both cursors by their corresponding joystick. move_cursor(&s, 0); move_cursor(&s2, 1); // Update VRAM with new sprite records. cvu_set_sprite(SPRITES, 0, &s); cvu_set_sprite(SPRITES, 1, &s2); } }