Vim으로 박자를 맞추다

16008 단어 Vimtech
예전에 화장실에 들어갔는데 갑자기 Vim으로 찍고 싶어졌어요skanehira/beatbanana.vim.
최근 지아이허브의 플러그인gh.vim을 만들고 있어서 이쪽 개발이 멈췄어요. 그 이야기를 조금 써보고 싶어요.

어떤 느낌?


그냥 하는 거지만 그런 느낌이에요.

위에서 블록을 무작위로 내리기 때문에 A~L의 키로 정타를 할 수 있는 수준에 이르렀다.
현재 네모난 블록은 무작위로 생성되어 앞으로 음성 기능과 악보 편집 기능을 실행할 것이다.
나는 만약 이 두 개가 완성된다면 아마 놀 수 있을 것이라고 생각한다.

어떤 실패?


블록의 생성에는 Vimpopup window이 사용됩니다.이것은 timer_start()를 사용하여 무작위로 생성된 것이다.
function! s:make_block(opt, timer) abort
  call timer_start(rand(srand()) % 1000, function('s:new_block', [a:opt]))
endfunction

(中略)
  for i in range(8)
    let press_key = s:bottom_bar_keys[i]
    let opt = {
          \ 'press_key': press_key,
          \ 'col_len': col_len,
          \ 'col_pos': col_pos,
          \ }
    call s:make_bottom_block(opt)
    exe printf('nnoremap <silent> <buffer> %s :call <SID>press_bottom_bar("%s")<CR>', press_key, press_key)
    call timer_start(1000, function('s:make_block', [opt]), {'repeat': -1})
    let col_pos += (col_len + 4)
  endfor
참고로 비동기(막히지 않는 조작)로Vimscript 함수를 실행하는 함수는 없지만 timer_start(0, f)를 사용하면 조작이 막히지 않기 때문에 아날로그 비동기 처리를 할 수 있습니다.
이것을 사용하면 네모난 블록을 떨어뜨리는 처리를 하면서 버튼이 눌린 사건을 주워 판정 처리할 수 있다.
블록을 내릴 때popup window의 위치를 중복 사용timer_start+1.
function! s:move_block_down(winid, press_key, timer) abort
  let opt = popup_getpos(a:winid)
  if opt.line is# s:winheight
    call timer_stop(a:timer)
    call popup_close(a:winid)
    call s:delete_block_winid(a:press_key, a:winid)
    return
  endif

  let opt.line += 1
  call popup_move(a:winid, opt)
endfunction

(中略)
function! s:new_block(opt, timer) abort
  let text = s:make_block_text('0', a:opt.col_len)
  let winid = popup_create(text, {
        \ 'col': a:opt.col_pos,
        \ 'line': 1,
        \ 'minwidth': strlen(text),
        \ })

  call win_execute(winid, 'syntax match beatbanana_bar /0/')

  call timer_start(60, function("s:move_block_down", [winid, a:opt.press_key]), {
        \ 'repeat': -1,
        \ })
  call add(s:bar_winid_set[a:opt.press_key], winid)
endfunction
판정 처리에 관해서는 간단하게 말하면 내려온 블록이 가지고 있는 키가 일치하는지 확인한 후 위치가 일치하는지 확인하는 것이다.
예를 들어 J의 버튼열에 J의 버튼이 있습니다. 이런 메시지 블록이 있기 때문에 그 블록에서 열쇠를 꺼내서 지금 눌렀던 키와 일치하는지 확인하세요.
자세한 논리는 코드를 읽어 주세요.
function! s:collision_detection(key) abort
  let winids = s:bar_winid_set[a:key]
  if empty(winids)
    return 0
  endif

  let bar_winid = winids[0]
  let opt = popup_getpos(bar_winid)

  return opt.line is# s:winheight || opt.line is# s:winheight - 1
endfunction

function! s:press_bottom_bar(key) abort
  let winid = s:bottom_bar_winid_set[a:key]
  if s:collision_detection(a:key)
    call win_execute(winid, 'syntax match beatbanana_hit_good /1/')
  else
    call win_execute(winid, 'syntax match beatbanana_hit /1/')
  endif
  call timer_start(150, function('s:restore_bottom_bar_highlight', [winid]))
endfunction

최후


아직 제작 중인데 제대로 놀 수 있을지 모르겠다는 말을 들으면 이상하겠지만 가능하면 플러그인화해서 공개하고 싶어요.
기대 많이 해주세요.

좋은 웹페이지 즐겨찾기