Chip8iEmulationCore

Chip8iEmulationCore 是一个 Swift 包,用于模拟 Chip8 系统并运行其程序。此包提供了一个模拟核心,允许您启动模拟、处理 Chip8 程序操作、处理输入以及订阅 Chip8 屏幕输出和声音更新。

模拟核心包可以在 macOS 和 iOS 上的前端应用程序中使用,您只需将用户输入传播到核心并订阅其输出即可。

安装

要将 Chip8iEmulationCore 包含在您的项目中,请将其添加为 Swift Package Dependency(Swift 包依赖项)。

  1. 在 Xcode 中,转到 File -> Add Packages...(文件 -> 添加包...)
  2. 输入仓库的 URL,并将包添加到您的项目中。

用法

导入包

在要使用模拟器的 Swift 文件中

import Chip8iEmulationCore

let emulationCore = Chip8EmulationCore()

加载 Chip8 程序

首先,从文件系统或其他方式以只读(ROM)数据 [UByte] 形式加载 chip8 程序二进制文件,并将其保存在 Chip8Program 结构中,以供模拟使用。

let programROM = Chip8Program(name: "My Pong Game", contentROM: myPongGameROMData)

启动模拟

emulate 函数在一个无限循环中运行(Chip8 程序没有退出命令),因此请确保它在适当的异步上下文中运行。

Task {
    await emulationCore.emulate(program: programROM)
}

处理按键事件

Chip8 有 16 个系统键,从 0 到 F。

    1 2 3 C
    4 5 6 D
    7 8 9 E
    A 0 B F

要处理按键按下和释放事件

emulationCore.onKeyDown(key: .Zero)  // Example: Press down Chip8 key '0'
emulationCore.onKeyDown(key: .One)  // Example: Press down Chip8 key '1'
emulationCore.onKeyUp(key: .F)  // Example: Release Chip8 key 'F'

使用 onKeyDownonKeyUp 方法将输入键 enum 发送到模拟器。有关键盘绑定的更多详细信息和示例,请参阅 EmulationControls 模块。

注意:键盘/控制器/触摸屏按钮可以自定义映射到 Chip8 键,这应该在前端应用程序中完成,模拟核心仅接受 EmulationControls.Chip8Key 枚举。

观察输出

outputScreenoutputSoundTimer 属性都标记为 @Published,因此您可以订阅它们,并在 SwiftUIUIKitAppKit 中更新视图和播放声音。

屏幕输出处理示例

Publisher Buffer outputScreen 是一个 64x32 的布尔值网格,表示像素状态。

outputScreen publisher buffer 反应式地显示屏幕更新的一种方法是使用 CGImage 扩展方法 fromMonochromeBitmap,它包含在 Chip8iEmulationCore 包中。

这是一个 macOS 前端应用程序中使用此方法的示例,它使用了此包。示例中还包括核心的初始化,启动游戏和订阅声音定时器更改。

    @StateObject var emulationCore = Chip8EmulationCore()
    private let singlePingSound = NSSound(named: NSSound.Name("Ping"))

    var body: some View {
        VStack {
            Image(CGImage.fromMonochromeBitmap(emulationCore.outputScreen, 
              width: 64, height: 32)!, 
            scale: 5, label: Text("Output"))
                .interpolation(.none)
                .resizable()
                .scaledToFit()
        }
        .padding()
        .onAppear(perform: {
            Task {
                let program = readProgramFromFile(fileName: "Pong.ch8")
                await emulationCore.emulate(program: program)
            }
        })
        .focusable()
        .focusEffectDisabled()
        .onKeyPress(phases: .down, action: onKeyDown)
        .onKeyPress(phases: .up, action: onKeyUp)
        .onChange(of: emulationCore.outputSoundTimer) { oldValue, newValue in
            handleSoundTimerChange(soundTimer: newValue)
        }
    }

声音输出处理说明

Publisher outputSoundTimer 是 Chip8 系统声音定时器的 UByte 值。 如果该值大于 0,则每次值更改时应播放短声音效果。

    func handleSoundTimerChange(soundTimer: UByte) {
        if soundTimer > 0 && !(singlePingSound?.isPlaying == true) {
            singlePingSound?.play()
        } else if soundTimer == 0 && singlePingSound?.isPlaying == true {
            singlePingSound?.stop()
        }
    }

使用示例

这是集成 chip8 模拟核心并从简单的 macOS 模拟器前端运行它的示例,该前端将游戏二进制文件和按键输入提供给核心,并显示核心的输出。

Usage example in macos app

许可

此包已获得 MIT 许可证的许可。 有关更多信息,请参阅 LICENSE 文件。