文章目录
- 前言
- 正文
- 构思大概的逻辑与代码
- 总结
前言
原神长草期,闲的无事便想试试里面的弹琴,奈何手残党,只能观望大佬的操作。但是,在我突发奇想下就想试试能否以我的能力使用代码将其自动化。
其实弹琴也就是掌握弹琴的按键和按下的时机即可,所以,理论上来说是比较简单的。
正文
首先,需要弹奏一首曲子,首先需要一个曲谱,这个可以在b站上找到很多热心的大佬会给出弹奏的曲子的曲谱。如下:
这个是我找b站上找到的尤拉的浪沫之舞的弹奏按键(PC)。
构思大概的逻辑与代码
- 创建一个曲谱(就是一个普通的类)来保存这首曲子的弹奏条件,包括按键和各个按键按下的时机
package TestCode.Music;public class Music2 extends AbstractMusic{ private int DELAY_Space = 250; //空格所需要的时间间隔ms private int DELAY_None = 150; //表示连续的按下时间间隔ms private int DELAY_Same = 0; //表示按键同时按下ms //尤拉的浪沫之舞 private String music = "N EEE W Q (JB) Q W J G V " + "EEE W Q (JZ) Q T E (JZ)" + "X X EE (EX) W X Q (JN) Q N W (JN) (GN) (HM)" + "M (HM) J M Q" + "(JC) (JC) (JC) (JC) C" + "(QV) A V A B S QW (JB) H S G (DN) D J (JN) D N D N D" + "(QX) S (HX) S (DB) S QW (JB) H S G(HN) D E (EN) D" + "(EN)(EN) W N (EN)" + "(NX) DDD S A (MX) TU"; @Override public int getDELAY_Space() { return DELAY_Space; } @Override public int getDELAY_None() { return DELAY_None; } @Override public int getDELAY_Same() { return DELAY_Same; } @Override public String getMusic() { return music; }}
- 创建一个Analyze类,将输入的曲谱变成MusicPlay类可以识别的CD类.
CD类
package TestCode.CD;import java.util.List;public class CD { private List<Integer> keyEvent;//存储按键 private List<Integer> delay;//存储按键之间的时间间隔 public List<Integer> getKeyEvent() { return keyEvent; } public List<Integer> getDelay() { return delay; } public void setKeyEvent(List<Integer> keyEvent) { this.keyEvent = keyEvent; } public void setDelay(List<Integer> delay) { this.delay = delay; }}
Analyze类
package TestCode.Utils;import TestCode.Music.AbstractMusic;import TestCode.CD.CD;import java.awt.event.KeyEvent;import java.util.ArrayList;import java.util.List;/** * 用于识别曲谱 */public class Analyze { private AbstractMusic musicScores; private List<Integer> keyEvents; private List<Integer> delays; /** * 将传入的乐谱进行解析为播放器可以播放的CD * @param musicScores 传入的乐谱 */ public Analyze(AbstractMusic musicScores) throws Exception { this.musicScores = musicScores; dealMusicScores(); } /** * @return 获得播放器可以处理的CD */ public CD getCD() { CD cd = new CD(); cd.setKeyEvent(keyEvents); cd.setDelay(delays); return cd; } /** * 对歌曲进行处理,转化为播放器可以处理的文件 */ private void dealMusicScores() throws Exception { keyEvents = new ArrayList<>(); delays = new ArrayList<>(); String music = musicScores.getMusic().trim(); //去除首位空格 music = music.toLowerCase(); //全部转换为小写 music = music.replace("\n", ""); for (int i = 0; i < music.length(); i++) { char key = music.charAt(i); if (Character.isLetter(key)) { keyEvents.add(KeyEvent.getExtendedKeyCodeForChar(key)); delays.add(musicScores.getDELAY_None()); } else if (Character.isSpaceChar(key)) { keyEvents.add(-1); delays.add(musicScores.getDELAY_Space()); } else if (key == '(') { key = music.charAt(++i); while (key != ')') { keyEvents.add(KeyEvent.getExtendedKeyCodeForChar(key)); delays.add(musicScores.getDELAY_Same()); key = music.charAt(++i); } } else {// throw new Exception("error keyCode"); } } }}
MusicPlay类(其中,MusicPlay类实现了DirectPlay类,可以直接传入乐谱进行播放)
package TestCode.MusicPlay;import TestCode.CD.CD;import TestCode.Music.AbstractMusic;import TestCode.Utils.Analyze;import TestCode.Utils.DirectPlay;import TestCode.Utils.MusicPlay;import TestCode.Utils.MusicScoresShow;import java.awt.*;import java.util.List;/** * 一代有音乐播放器 */public class MusicPlayer1 extends MusicPlay implements MusicScoresShow, DirectPlay { private List<Integer> keyEvent; private List<Integer> delay; private int delayStart = 7 * 1000; //默认的音乐开始播放时间 @Override public void showMusicScores() { } /** * 进行音乐播放 */ @Override public void play() throws AWTException { Robot robot = new Robot(); robot.delay(delayStart); for (int i = 0; i < keyEvent.size(); i++) { if (keyEvent.get(i) != -1) { robot.keyPress(keyEvent.get(i)); robot.keyRelease(keyEvent.get(i)); } robot.delay(delay.get(i)); } } /** * 设置需要播放的CD * @param cd 需要播放的CD */ @Override public void setMusic(CD cd) { this.keyEvent = cd.getKeyEvent(); this.delay = cd.getDelay(); } /** * 使用DirectPlay接口,直接传入乐谱进行播放 * @param musicScores 需要进行播放的乐谱 * @throws Exception */ @Override public void musicPlay(AbstractMusic musicScores) throws Exception { Analyze analyze = new Analyze(musicScores); setMusic(analyze.getCD()); play(); } /** * 设置音乐开始播放的时间 * @param delayStart ms */ public void setDelayStart(int delayStart) { this.delayStart = delayStart; }}
用于播放音乐的主函数使用
package TestCode;import TestCode.Music.Music2;import TestCode.Music.Music_zhou;import TestCode.MusicPlay.MusicPlayer1;import TestCode.Utils.Analyze;import org.junit.Test;import java.awt.*;public class test1 { public static void main(String[] args) throws AWTException { try { //使用第一种方式播放七里香 Analyze analyze = new Analyze(new Music_zhou()); MusicPlayer1 musicPlayer1 = new MusicPlayer1(); musicPlayer1.setMusic(analyze.getCD()); musicPlayer1.play(); } catch (Exception e) { e.printStackTrace(); } } @Test public void test2() { //使用第二种方式播放浪沫之舞 try { MusicPlayer1 musicPlayer1 = new MusicPlayer1(); musicPlayer1.setDelayStart(5 * 1000); musicPlayer1.musicPlay(new Music2()); } catch (Exception e) { e.printStackTrace(); } }}
总结
其实只要掌握了Java的Robot类就可以实现一些基本的自动化,以上的主要使用的也就是Robot类。
!!!
需要注意的是,在找到对应的曲谱后需要根据曲谱对应的节奏进行适当更改,也就是DELAY,延迟时间。
最后附上工程总文件,需要的自取,里面有七里香和另一首比较简单的,当然本人的音乐节奏不是很好,以上技术权当抛砖引玉了。
如有疑问,欢迎留言交流
链接:https://pan.baidu.com/s/1RL0yb-7PT1hoBYOEaWEaxA
提取码:hsim
或直接点击
原神弹琴
提取码:
hsim