代码拉取完成,页面将自动刷新
同步操作将从 小白杨/nes4j 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
nes4j是使用java语言实现任天堂红白机模拟器,主要包括CPU、 PPU和APU三部分组成.其中PPU是红白机 实现难度最大的一个模块,理解起来有点困难.
nes4j
├── app UI模块(javafx)
├── bin 模拟器核心模块(CPU/PPU/APU)
└── document 开发文档
git clone https://gitee.com/navigatorCode/nes4j.git
mvn run
更多卡带Mapper正在实现中,敬请期待。
如果你觉得当前游戏输出程序无法满足你的需求,你可以给我们提PR,我们会尽可能满足你的需求,另外一种方法就是你自己引入nes4j-bin模块自己实现 游戏视屏和音频输出
<dependency>
<groupId>cn.navclub</groupId>
<artifactId>nes4j-bin</artifactId>
<version>1.0.2</version>
</dependency>
implementation group: 'cn.navclub', name: 'nes4j-bin', version: '1.0.2'
or
implementation 'cn.navclub:nes4j-bin:1.0.2'
implementation("cn.navclub:nes4j-bin:1.0.2")
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) {
}
}
@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通知我删除对应侵权素材.
如果你也想编写自己的模拟器或想了解模拟器内部结构,以下资源可以给你提供一些模拟器基础知识:
主界面 -> 工具 -> 调试
程序内存快照 (内存)
名称 | 描述 |
---|---|
Jetbrain | 免费提供全套集成开发环境 |
NES forum | 提供技术支持 |
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。