1 Star 0 Fork 60

/ nes4j

forked from 小白杨 / nes4j 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README_zh.md 7.07 KB
一键复制 编辑 原始数据 按行查看 历史
Nes4j logo

Nes4j

任天堂红白机模拟器

nes4j DuckTables Super Mario

项目介绍

nes4j是使用java语言实现任天堂红白机模拟器,主要包括CPUPPUAPU三部分组成.其中PPU是红白机 实现难度最大的一个模块,理解起来有点困难.

项目结构

nes4j
├── app UI模块(javafx)
├── bin 模拟器核心模块(CPU/PPU/APU)
└── document 开发文档

快速启动

下载项目

git clone https://gitee.com/navigatorCode/nes4j.git

启动项目

 mvn run

已实现卡带Mapper

更多卡带Mapper正在实现中,敬请期待。

自定义音视频输出

如果你觉得当前游戏输出程序无法满足你的需求,你可以给我们提PR,我们会尽可能满足你的需求,另外一种方法就是你自己引入nes4j-bin模块自己实现 游戏视屏和音频输出

首先引入依赖

  • Apache Maven

<dependency>
    <groupId>cn.navclub</groupId>
    <artifactId>nes4j-bin</artifactId>
    <version>1.0.2</version>
</dependency>
  • Gradle(groovy)
implementation group: 'cn.navclub', name: 'nes4j-bin', version: '1.0.2'

or

implementation 'cn.navclub:nes4j-bin:1.0.2'
  • Gradle(Kotlin)
implementation("cn.navclub:nes4j-bin:1.0.2")

创建NES实例并初始化

  • GameWorld.java

import cn.navclub.nes4j.bin.NES;
import cn.navclub.nes4j.bin.io.JoyPad;
import cn.navclub.nes4j.bin.ppu.Frame;

public class GameWorld {
    public NES create() {
        NES instance = NES.NESBuilder
                .newBuilder()
                //nes游戏rom
                .file(file)
                //音频输出程序 
                .player(JavaXAudio.class)
                //Game loop 回调
                .gameLoopCallback(GameWorld.this::gameLoopCallback)
                .build();
        try {
            //一旦当前方法被调用将会阻塞当前线程直到游戏结束或者异常发生
            instance.execute();
        } catch (Exception e) {
            //todo 当异常发生当前游戏立即停止
        }
    }

    //当PPU输出一帧视屏时回调该函数
    private void gameLoopCallback(Frame frame, JoyPad joyPad, JoyPad joyPad1) {

    }
}
  • JavaXAudio.java

@SuppressWarnings("all")
public class JavaXAudio implements Player {
    private final byte[] sample;
    private final Line.Info info;
    private final AudioFormat format;
    private final SourceDataLine line;
    private int ldx;
    //当前填充下标
    private int index;
    private Thread thread;
    private volatile boolean stop;
    private final static int SAMPLE_SIZE = 735 * 2;
    //音频默认缓存区大小为32kb
    private final static int DEF_BUF_SIZE = 32 * 1024;

    private static final LoggerDelegate log = LoggerFactory.logger(JavaXAudio.class);


    public JavaXAudio() throws LineUnavailableException {
        this.sample = new byte[DEF_BUF_SIZE];
        this.format = new AudioFormat(44100, 8, 1, false, false);
        this.info = new DataLine.Info(SourceDataLine.class, format);
        this.line = (SourceDataLine) AudioSystem.getLine(info);

        line.open(format);
        line.start();

        CompletableFuture.runAsync((this::exec));
    }

    @Override
    public synchronized void output(byte sample) {
        this.sample[this.index++] = sample;
        if (this.lcalculate() > SAMPLE_SIZE && thread != null) {
            LockSupport.unpark(this.thread);
        }
        index = index % DEF_BUF_SIZE;
    }


    private void exec() {
        var arr = new byte[DEF_BUF_SIZE];
        this.thread = Thread.currentThread();
        while (!this.stop) {
            LockSupport.park();
            final int length;
            synchronized (this) {
                length = lcalculate();
                if ((length + ldx > DEF_BUF_SIZE)) {
                    var tmp = DEF_BUF_SIZE - this.ldx;
                    System.arraycopy(this.sample, this.ldx, arr, 0, tmp);
                    System.arraycopy(this.sample, 0, arr, tmp, this.index);
                } else {
                    System.arraycopy(this.sample, this.ldx, arr, 0, length);
                }
                this.ldx = this.index;
            }
            this.line.write(arr, 0, length);
        }
    }

    private int lcalculate() {
        var len = this.index - this.ldx;
        if (len > 0) {
            return len;
        }
        return DEF_BUF_SIZE - ldx + index;
    }


    @Override
    public void stop() {
        this.stop = true;
        LockSupport.unpark(this.thread);
        this.line.close();
    }
}

参与贡献

我们强烈欢迎有兴趣的开发者参与到项目建设中来,同时欢迎大家对项目提出宝贵意见建议和功能需求,项目正在积极开发,欢迎 PR 👏。

版权说明

目前市场上绝大部分游戏版权为任天堂所有,请勿在未取得任天堂授权的情况下私自分发游戏. 如果因此引发的任何侵权行为均与本软件无关.如果本软件中设计任何侵权素材请发送邮件到GZYangKui@126.com通知我删除对应侵权素材.

文档

如果你也想编写自己的模拟器或想了解模拟器内部结构,以下资源可以给你提供一些模拟器基础知识:

汇编调试(实验功能)

主界面 -> 工具 -> 调试

Assembler

程序内存快照 (内存)

Assembler

技术交流学习

qq

特别感谢

名称 描述
Jetbrain 免费提供全套集成开发环境
NES forum 提供技术支持
Java
1
https://gitee.com/521MM/nes4j.git
git@gitee.com:521MM/nes4j.git
521MM
nes4j
nes4j
master

搜索帮助