Skip to content

Commit

Permalink
Closes #5, enhancements and small fixes. Related problem with disp_cl…
Browse files Browse the repository at this point in the history
…ear fixed. Action update.
  • Loading branch information
PenguinOfWar committed Mar 16, 2021
1 parent d7cd78a commit 78ff41b
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 72 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: GitHub Pages
on:
push:
branches:
- main
release:
types: [published]

jobs:
build-and-deploy:
runs-on: ubuntu-latest
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
- Pause the emulator any time
- Local multiplayer (depending on the game)
- 60 fps video output to canvas
- 100hz simulated clock speed
- Authentic 120hz clockspeed
- Cutting edge sawtooth audio
- Desktop keyboard support
- Mobile and touch support with virtual hex keypad

## Cartridges

- Invaders
- Brix
- Tetris
- Pong
- UFO
- IBM
- Invaders
- Missile
- Tank
- Maze
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "chip.ts",
"description": "A CHIP-8 emulator in TypeScript",
"version": "0.2.0",
"version": "0.2.1",
"private": true,
"repository": {
"type": "git",
Expand Down
36 changes: 2 additions & 34 deletions src/containers/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,13 @@ import { Field, Form, Formik } from 'formik';
import request from 'axios';
import isClient from '@bagofholding/is-client';

import Chip from '../../libs/chip/chip';
import Chip, { games, keypad, instructions } from '../../libs/chip/chip';

import './App.scss';

function App() {
const canvas = useRef(null);

const games = [
'Brix',
'Tetris',
'Pong',
'UFO',
'IBM',
'Invaders',
'Missile',
'Tank',
'Maze'
];
const keypad = [
['1', '2', '3', '4'],
['q', 'w', 'e', 'r'],
['a', 's', 'd', 'f'],
['z', 'x', 'c', 'v']
];
const instructions: IInstructions = {
brix: 'Left: Q | Right: E',
tetris: 'Left: W | Right: E | Rotate: Q',
pong: 'P1 Up: 1 | P1 Down: Q | P2 Up: 4 | P2 Down: R',
ufo: 'Up/Left: Q | Up: W | Up/Right: E',
ibm: 'None',
invaders: '???',
missile: 'Shoot: S',
tank: 'Shoot: W | Left: Q | Up: S | Right: E | Down: 2',
maze: 'None'
};
const [slot, setSlot] = useState(games[0].toLowerCase());

const fetchData = useCallback(async () => {
Expand All @@ -60,7 +32,7 @@ function App() {
const blob = new Blob([response.data]);
const buffer = await blob.arrayBuffer();
const rom = new Uint8Array(buffer);
const chip = new Chip(rom, canvas);
const chip = new Chip(slot, rom, canvas);

window.chip = chip;
}, [slot]);
Expand Down Expand Up @@ -194,10 +166,6 @@ function App() {
);
}

export interface IInstructions {
[key: string]: string;
}

declare global {
interface Window {
chip: Chip;
Expand Down
70 changes: 64 additions & 6 deletions src/libs/chip/chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,57 @@ import Cpu from './drivers/cpu';
import Gfx from './drivers/gfx';
import Keyboard from './drivers/keyboard';

/**
* export some common stuff
*/

export const games = [
'Invaders',
'Brix',
'Tetris',
'Pong',
'UFO',
'IBM',
'Missile',
'Tank',
'Maze'
];

export const keypad = [
['1', '2', '3', '4'],
['q', 'w', 'e', 'r'],
['a', 's', 'd', 'f'],
['z', 'x', 'c', 'v']
];

export const instructions: IInstructions = {
brix: 'Left: Q | Right: E',
tetris: 'Left: W | Right: E | Rotate: Q',
pong: 'P1 Up: 1 | P1 Down: Q | P2 Up: 4 | P2 Down: R',
ufo: 'Up/Left: Q | Up: W | Up/Right: E',
ibm: 'None',
invaders: 'Start: W | Shoot: W| Left: Q | Right: R',
missile: 'Shoot: S',
tank: 'Shoot: W | Left: Q | Up: S | Right: E | Down: 2',
maze: 'None'
};

export interface SpecialCases {
[key: string]: any;
}

export interface IInstructions {
[key: string]: string;
}

export default class Chip {
/**
* Configure our preferred target framerate
* We'll also configure our frame pointer and play state
* Timing function from https://gist.github.com/addyosmani/5434533#gistcomment-2018050
*/

speed = 100;
speed = 120;
frame = 0;

/**
Expand All @@ -27,14 +70,29 @@ export default class Chip {
public gfx;
public keyboard;

/**
* lets fine tune some specific games
* our maximum is 1000
*/

specialCases: SpecialCases = {};

/**
* i couldnt figure out how to make typescript happy with canvas so i've checked it can't be null up the chain - bit risky tho
*
* @param rom - a CHIP-8 rom file as a Uint8Array
* @param canvas - an html canvas element for our renderer
*/

constructor(rom: Uint8Array, canvas: any) {
constructor(game: string, rom: Uint8Array, canvas: any) {
/**
* before we do anything check for special cases
*/

if (this.specialCases[game.toLowerCase()]) {
this.speed = this.specialCases[game.toLowerCase()].speed || this.speed;
}

const gfx = new Gfx(canvas);
const cpu = new Cpu(rom, gfx);

Expand All @@ -56,6 +114,10 @@ export default class Chip {
start(cpu: Cpu, gfx: Gfx) {
let working = false;

/**
* let's start a clock
*/

setInterval(() => {
if (working) {
return;
Expand All @@ -66,10 +128,6 @@ export default class Chip {
working = false;
}, 1000 / this.speed);

/**
* let's start a clock
*/

const animateLoop = () => {
this.frame = requestAnimationFrame(animateLoop);

Expand Down
21 changes: 19 additions & 2 deletions src/libs/chip/drivers/cpu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ export default class Cpu {
* 00E0 / disp_clear() - clears the screen
*/
case 0x00e0:
this.gfx.disp_clear();
this.disp_clear();
break;

/**
Expand Down Expand Up @@ -647,10 +647,13 @@ export default class Cpu {
this.stop();
return;
} else {
/**
* before we start again should we clear the screen ram and pause the rendering there too?
*/
this.registers[x] = this.key;
this.start();
break;
}
break;
}

/**
Expand Down Expand Up @@ -815,6 +818,20 @@ export default class Cpu {
this.speaker.close();
}
}

/**
* clear the display
*/
public disp_clear() {
/**
* feed our paint method an empty screen array and force a new paint
*/

const screen = new Uint8Array(
this.gfx.resolution.x * this.gfx.resolution.y
);
this.screen = screen;
}
}

export interface ICoordinates {
Expand Down
22 changes: 0 additions & 22 deletions src/libs/chip/drivers/gfx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,31 +61,9 @@ export default class Gfx {
this.context = this.canvas.getContext('2d');
this.canvas.width = this.resolution.x * this.resolution.scale;
this.canvas.height = this.resolution.y * this.resolution.scale;

this.disp_clear();
}

public disp_clear() {
/**
* man i cannot get typescript to shut the fuck about how this might be null
* look at all this extra code
* i love typescript but she doesnt make it easy
*/
this.context?.clearRect &&
this.context.clearRect(
0,
0,
this.resolution.x * this.resolution.scale,
this.resolution.y * this.resolution.scale
);
}

public paint(screen: Uint8Array) {
/**
* Start every render by clearing the screen
*/
this.disp_clear();

if (this.context) {
const context = this.context;
const resolution = this.resolution;
Expand Down
5 changes: 3 additions & 2 deletions src/libs/chip/drivers/keyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export default class Keyboard {
}

public release() {
this.cpu.input(0x00ff);
this.cpu.input(0);
}

listen() {
Expand All @@ -144,7 +144,8 @@ export default class Keyboard {

/**
* listen for keyup and clear the key register
* send it 255 if we're clear
* send it 0 if we're clear because why on earth should it be anything but
* note to self: when consulting the ancient texts they are not 1-2-1 gospel. ta.
*/
document.addEventListener('keyup', () => {
this.release();
Expand Down

0 comments on commit 78ff41b

Please sign in to comment.