#IFNDEF __lib_pointer #DEFINE __lib_pointer 1 GOTO __skip_lib_pointer // ============================================================================ // SPRITE POINTER DRIVER FOR COMMODORE 64 // ============================================================================ // This library provides sprite-based pointer/cursor control. // Can be driven by joystick, mouse, keyboard, or other input methods. // // Usage: // #INCLUDE "pointer.c65" // pointer_init(100, 50, 1, 192) // Init at x=100, y=50, white color, sprite data block 192 // WHILE 1 // // Read your input device (joystick, mouse, etc.) // pointer_move(delta_x, delta_y) // Move pointer // WEND // ============================================================================ // VIC-II Sprite registers WORD CONST VIC2 = $D000 BYTE sprite_x0 @ VIC2+0 // Sprite 0 X position BYTE sprite_y0 @ VIC2+1 // Sprite 0 Y position BYTE sprite_x_msb @ VIC2+16 // Sprite X MSB (for X > 255) BYTE sprite_enable @ VIC2+21 // Sprite enable register BYTE sprite_color0 @ VIC2+39 // Sprite 0 color BYTE sprite_pointer0 @ $07F8 // Sprite 0 pointer (screen + $3F8) // Pointer position variables WORD pointer_x // Current pointer X position (0-511) BYTE pointer_y // Current pointer Y position BYTE pointer_speed // Base movement speed BYTE pointer_accel // Current acceleration counter BYTE pointer_max_speed // Maximum speed with acceleration // ============================================================================ // Compact arrow pointer sprite - 7 pixels tall // Tip at (0,0) for easy pointing at coordinates // ============================================================================ LABEL pointer_sprite_data ASM // Simple compact arrow !8 $80, $00, $00 // Row 0: * !8 $C0, $00, $00 // Row 1: ** !8 $E0, $00, $00 // Row 2: *** !8 $F0, $00, $00 // Row 3: **** !8 $E0, $00, $00 // Row 4: *** !8 $C0, $00, $00 // Row 5: ** !8 $80, $00, $00 // Row 6: * !8 $00, $00, $00 // Row 7-20: blank !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00, $00, $00 !8 $00 // Padding ENDASM LABEL pointer_sprite_data_end // ============================================================================ // FUNC pointer_init // Initialize sprite 0 as a pointer at given position // Parameters: // x_pos: Initial X position (0-255) // y_pos: Initial Y position (0-250) // color: Sprite color (0-15) // sprite_data: Sprite data block number (0-255) // ============================================================================ FUNC pointer_init({BYTE x_pos} {BYTE y_pos} {BYTE color} {BYTE sprite_data}) BYTE temp // Set pointer position pointer_x = x_pos pointer_y = y_pos pointer_speed = 1 // Base speed: 1 pixel pointer_accel = 0 // No acceleration initially pointer_max_speed = 10 // Max accelerated speed // Set sprite X position (low byte) sprite_x0 = x_pos sprite_y0 = y_pos // Clear X MSB for sprite 0 (x_pos is < 256) temp = sprite_x_msb temp = temp & %11111110 // Clear bit 0 sprite_x_msb = temp // Set sprite color sprite_color0 = color // Set sprite data pointer sprite_pointer0 = sprite_data // Enable sprite 0 sprite_enable = 1 FEND // ============================================================================ // FUNC pointer_move_left // Move pointer left by speed amount // ============================================================================ FUNC pointer_move_left({BYTE speed}) // Move left with bounds check IF pointer_x >= speed pointer_x = pointer_x - speed ELSE pointer_x = 0 ENDIF IF pointer_x < 24 pointer_x = 24 ENDIF // Update VIC registers sprite_x0 = pointer_x IF pointer_x > 255 sprite_x_msb = sprite_x_msb | %00000001 ELSE sprite_x_msb = sprite_x_msb & %11111110 ENDIF FEND // ============================================================================ // FUNC pointer_move_right // Move pointer right by speed amount // ============================================================================ FUNC pointer_move_right({BYTE speed}) // Move right with bounds check pointer_x = pointer_x + speed IF pointer_x > 320+20 pointer_x = 320+20 ENDIF // Update VIC registers sprite_x0 = pointer_x IF pointer_x > 255 sprite_x_msb = sprite_x_msb | %00000001 ELSE sprite_x_msb = sprite_x_msb & %11111110 ENDIF FEND // ============================================================================ // FUNC pointer_move_up // Move pointer up by speed amount // ============================================================================ FUNC pointer_move_up({BYTE speed}) IF pointer_y >= speed pointer_y = pointer_y - speed ENDIF IF pointer_y < 50 pointer_y = 50 // Stop at top edge, not 0 ENDIF sprite_y0 = pointer_y FEND // ============================================================================ // FUNC pointer_move_down // Move pointer down by speed amount // ============================================================================ FUNC pointer_move_down({BYTE speed}) WORD new_y new_y = pointer_y + speed // Stop at bottom edge (around Y=229 for NTSC, 249 for PAL) IF new_y > 247 pointer_y = 247 ELSE pointer_y = new_y ENDIF sprite_y0 = pointer_y FEND // ============================================================================ // FUNC pointer_update_joystick // Update pointer based on joystick input state with acceleration // Expects joy_state to be set (from joystick.c65 library) // joy_state bits: UP=bit0, DOWN=bit1, LEFT=bit2, RIGHT=bit3, FIRE=bit4 // ============================================================================ FUNC pointer_update_joystick({BYTE joy_state}) BYTE actual_speed BYTE any_direction BYTE test_bit // Check if any direction is pressed (mask all direction bits) any_direction = joy_state & %00001111 // Reset acceleration if joystick is neutral IF any_direction == 0 pointer_accel = 0 ELSE // Increase acceleration while moving IF pointer_accel < 255 pointer_accel++ ENDIF ENDIF // Calculate actual speed with acceleration // Divide accel by 8 (shift right 3 times) actual_speed = pointer_accel ASM lda |actual_speed| ;lsr lsr lsr lsr sta |actual_speed| ENDASM actual_speed = pointer_speed + actual_speed IF actual_speed > pointer_max_speed actual_speed = pointer_max_speed ENDIF // Move in pressed directions test_bit = joy_state & %00000100 // LEFT mask IF test_bit pointer_move_left(actual_speed) ENDIF test_bit = joy_state & %00001000 // RIGHT mask IF test_bit pointer_move_right(actual_speed) ENDIF test_bit = joy_state & %00000001 // UP mask IF test_bit pointer_move_up(actual_speed) ENDIF test_bit = joy_state & %00000010 // DOWN mask IF test_bit pointer_move_down(actual_speed) ENDIF FEND // ============================================================================ // FUNC pointer_update_mouse // Update pointer based on mouse delta movements // Expects mouse_delta_x and mouse_delta_y to be set (from mouse.c65 library) // Mouse deltas are signed 8-bit values // ============================================================================ FUNC pointer_update_mouse({BYTE delta_x} {BYTE delta_y}) BYTE sign_x BYTE sign_y BYTE abs_x BYTE abs_y // Handle X movement sign_x = delta_x & %10000000 IF sign_x // Negative (moving left) abs_x = 0 - delta_x // Get absolute value IF abs_x > 0 pointer_move_left(abs_x) ENDIF ELSE // Positive (moving right) IF delta_x > 0 pointer_move_right(delta_x) ENDIF ENDIF // Handle Y movement sign_y = delta_y & %10000000 IF sign_y // Negative (moving up) abs_y = 0 - delta_y // Get absolute value IF abs_y > 0 pointer_move_up(abs_y) ENDIF ELSE // Positive (moving down) IF delta_y > 0 pointer_move_down(delta_y) ENDIF ENDIF FEND // ============================================================================ // FUNC pointer_set_speed // Set pointer movement speed // Parameters: // speed: Pixels to move per movement (1-8 recommended) // ============================================================================ FUNC pointer_set_speed({BYTE speed}) pointer_speed = speed FEND // ============================================================================ // FUNC pointer_get_x // Get current pointer X position // Parameters: // out:x_pos: X position (0-511) // ============================================================================ FUNC pointer_get_x(out:{WORD x_pos}) x_pos = pointer_x FEND // ============================================================================ // FUNC pointer_get_y // Get current pointer Y position // Returns: Y position in out parameter // ============================================================================ FUNC pointer_get_y(out:{BYTE y_pos}) y_pos = pointer_y FEND // ============================================================================ // FUNC pointer_enable // Enable or disable pointer sprite // Parameters: // enable: 1 to enable, 0 to disable // ============================================================================ FUNC pointer_enable({BYTE enable}) BYTE temp temp = sprite_enable IF enable temp = temp | %00000001 ELSE temp = temp & %11111110 ENDIF sprite_enable = temp FEND // ============================================================================ // FUNC pointer_set_color // Change pointer sprite color // Parameters: // color: Color value (0-15) // ============================================================================ FUNC pointer_set_color({BYTE color}) sprite_color0 = color FEND LABEL __skip_lib_pointer #IFEND