文章目录

    • 前言
    • 正文
      • 构思大概的逻辑与代码
    • 总结

前言

原神长草期,闲的无事便想试试里面的弹琴,奈何手残党,只能观望大佬的操作。但是,在我突发奇想下就想试试能否以我的能力使用代码将其自动化。

其实弹琴也就是掌握弹琴的按键和按下的时机即可,所以,理论上来说是比较简单的。

正文

首先,需要弹奏一首曲子,首先需要一个曲谱,这个可以在b站上找到很多热心的大佬会给出弹奏的曲子的曲谱。如下:

这个是我找b站上找到的尤拉的浪沫之舞的弹奏按键(PC)。

构思大概的逻辑与代码

  1. 创建一个曲谱(就是一个普通的类)来保存这首曲子的弹奏条件,包括按键和各个按键按下的时机
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;    }}
  1. 创建一个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