Skip to content

Commit c34a10a

Browse files
committed
Abstracts event handling (input, screen and sound) to an internal
package.
1 parent bf9a0f2 commit c34a10a

14 files changed

+111
-75
lines changed

.gitignore

100644100755
File mode changed.

Makefile

100644100755
File mode changed.

README.md

100644100755
File mode changed.

cmd/chip8/main.go

100644100755
+8-74
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,13 @@ import (
88
"time"
99

1010
"github.com/danmrichards/chip8/internal/chip8"
11-
"github.com/danmrichards/chip8/internal/sound"
11+
"github.com/danmrichards/chip8/internal/event"
1212
"github.com/faiface/pixel"
13-
"github.com/faiface/pixel/imdraw"
1413
"github.com/faiface/pixel/pixelgl"
15-
"golang.org/x/image/colornames"
1614
)
1715

1816
var (
19-
vm *chip8.VM
20-
window *pixelgl.Window
21-
22-
// TODO: Abstract this.
23-
keys = map[byte]pixelgl.Button{
24-
0x1: pixelgl.Key1, 0x2: pixelgl.Key2, 0x3: pixelgl.Key3, 0xC: pixelgl.Key4,
25-
0x4: pixelgl.KeyQ, 0x5: pixelgl.KeyW, 0x6: pixelgl.KeyE, 0xD: pixelgl.KeyR,
26-
0x7: pixelgl.KeyA, 0x8: pixelgl.KeyS, 0x9: pixelgl.KeyD, 0xE: pixelgl.KeyF,
27-
0xA: pixelgl.KeyZ, 0x0: pixelgl.KeyX, 0xB: pixelgl.KeyC, 0xF: pixelgl.KeyV,
28-
}
17+
vm *chip8.VM
2918

3019
rom string
3120
debug bool
@@ -67,15 +56,16 @@ func run() {
6756
VSync: true,
6857
}
6958

70-
var err error
71-
window, err = pixelgl.NewWindow(cfg)
59+
window, err := pixelgl.NewWindow(cfg)
7260
if err != nil {
73-
log.Fatal("Could not create window:", err)
61+
log.Fatal("Could not create event:", err)
7462
}
7563

7664
vm = chip8.New()
7765
vm.Debug = debug
7866

67+
eh := event.NewHandler(window, vm)
68+
7969
rom, err := os.Open(rom)
8070
if err != nil {
8171
log.Fatalln("Could not open ROM:", err)
@@ -85,7 +75,8 @@ func run() {
8575
log.Fatal("Could not load ROM:", err)
8676
}
8777

88-
go eventHandler()
78+
// Handle input, screen and sound events.
79+
go eh.Handle()
8980

9081
// Emulation loop.
9182
for !window.Closed() {
@@ -100,65 +91,8 @@ func run() {
10091
log.Fatal(err)
10192
}
10293

103-
inputHandler()
104-
10594
// A bit dirty, but block the next cycle until a tick. This prevents
10695
// the emulator from running too quickly.
10796
<-tick.C
10897
}
10998
}
110-
111-
func eventHandler() {
112-
for !window.Closed() {
113-
select {
114-
case <-vm.Draw():
115-
drawScreen()
116-
case <-vm.Beep():
117-
if err := sound.Beep(); err != nil {
118-
log.Printf("Error playing beep: %q\n", err)
119-
}
120-
default:
121-
}
122-
}
123-
}
124-
125-
// TODO: Abstract this.
126-
func drawScreen() {
127-
window.Clear(colornames.Black)
128-
129-
imd := imdraw.New(nil)
130-
imd.Color = pixel.RGB(0.14, 0.8, 0.26)
131-
132-
scrW := window.Bounds().W()
133-
scrH := window.Bounds().H()
134-
135-
// Calculate the screen ratio.
136-
rW, rH := scrW/64, scrH/32
137-
138-
for x := 0; x < 64; x++ {
139-
for y := 0; y < 32; y++ {
140-
if !vm.PixelSet((31-y)*64 + x) {
141-
continue
142-
}
143-
144-
// Scale the pixel co-ords.
145-
sX := rW * float64(x)
146-
sY := rH * float64(y)
147-
148-
imd.Push(pixel.V(sX, sY))
149-
imd.Push(pixel.V(sX+rW, sY+rH))
150-
imd.Rectangle(0)
151-
}
152-
}
153-
154-
imd.Draw(window)
155-
window.Update()
156-
}
157-
158-
func inputHandler() {
159-
for i, key := range keys {
160-
if window.Pressed(key) {
161-
vm.KeyDown(i)
162-
}
163-
}
164-
}

go.mod

100644100755
+1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ require (
1111
github.com/gobuffalo/packr v1.19.0
1212
github.com/hajimehoshi/oto v0.2.1 // indirect
1313
golang.org/x/image v0.0.0-20181109232246-249dc8530c0e
14+
golang.org/x/tools v0.0.0-20181204185109-3832e276fb48 // indirect
1415
)

go.sum

100644100755
+2
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ golang.org/x/mobile v0.0.0-20180806140643-507816974b79/go.mod h1:z+o9i4GpDbdi3rU
4242
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
4343
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
4444
golang.org/x/sys v0.0.0-20180806082429-34b17bdb4300/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
45+
golang.org/x/tools v0.0.0-20181204185109-3832e276fb48 h1:N6OJ2izGAYOu7TF6EHpWtlM+vFxWtFJoj/BxJI7UhSQ=
46+
golang.org/x/tools v0.0.0-20181204185109-3832e276fb48/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

internal/chip8/fontset.go

100644100755
File mode changed.

internal/chip8/opcodes.go

100644100755
File mode changed.

internal/chip8/opcodes_test.go

100644100755
File mode changed.

internal/chip8/vm.go

100644100755
File mode changed.

internal/event/event.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package event
2+
3+
import (
4+
"log"
5+
6+
"github.com/danmrichards/chip8/internal/chip8"
7+
"github.com/danmrichards/chip8/internal/sound"
8+
"github.com/faiface/pixel"
9+
"github.com/faiface/pixel/imdraw"
10+
"github.com/faiface/pixel/pixelgl"
11+
"golang.org/x/image/colornames"
12+
)
13+
14+
var keys = map[byte]pixelgl.Button{
15+
0x1: pixelgl.Key1, 0x2: pixelgl.Key2, 0x3: pixelgl.Key3, 0xC: pixelgl.Key4,
16+
0x4: pixelgl.KeyQ, 0x5: pixelgl.KeyW, 0x6: pixelgl.KeyE, 0xD: pixelgl.KeyR,
17+
0x7: pixelgl.KeyA, 0x8: pixelgl.KeyS, 0x9: pixelgl.KeyD, 0xE: pixelgl.KeyF,
18+
0xA: pixelgl.KeyZ, 0x0: pixelgl.KeyX, 0xB: pixelgl.KeyC, 0xF: pixelgl.KeyV,
19+
}
20+
21+
// Handler is responsible for handling input and output for the vm.
22+
type Handler struct {
23+
window *pixelgl.Window
24+
vm *chip8.VM
25+
}
26+
27+
// NewHandler returns a new event handler.
28+
func NewHandler(win *pixelgl.Window, vm *chip8.VM) Handler {
29+
return Handler{
30+
window: win,
31+
vm: vm,
32+
}
33+
}
34+
35+
// Handle continually loops while the VM window is open; handling events.
36+
// Events are handled with a non-blocking select. Draw and sound events are
37+
// handled independently with input being treated as the default event to check.
38+
func (h *Handler) Handle() {
39+
for !h.window.Closed() {
40+
select {
41+
case <-h.vm.Draw():
42+
h.draw()
43+
case <-h.vm.Beep():
44+
if err := sound.Beep(); err != nil {
45+
log.Printf("Error playing beep: %q\n", err)
46+
}
47+
default:
48+
h.input()
49+
}
50+
}
51+
}
52+
53+
// input iterates over the keyset, checking if any of them are pressed and
54+
// updates the vm accordingly.
55+
func (h *Handler) input() {
56+
for i, key := range keys {
57+
if h.window.Pressed(key) {
58+
h.vm.KeyDown(i)
59+
}
60+
}
61+
}
62+
63+
// draw updates the window based on the current state of the VM graphics array.
64+
func (h *Handler) draw() {
65+
h.window.Clear(colornames.Black)
66+
67+
imd := imdraw.New(nil)
68+
imd.Color = pixel.RGB(0.14, 0.8, 0.26)
69+
70+
scrW := h.window.Bounds().W()
71+
scrH := h.window.Bounds().H()
72+
73+
// Calculate the screen ratio.
74+
rW, rH := scrW/64, scrH/32
75+
76+
for x := 0; x < 64; x++ {
77+
for y := 0; y < 32; y++ {
78+
if !h.vm.PixelSet((31-y)*64 + x) {
79+
continue
80+
}
81+
82+
// Scale the pixel co-ords.
83+
sX := rW * float64(x)
84+
sY := rH * float64(y)
85+
86+
imd.Push(pixel.V(sX, sY))
87+
imd.Push(pixel.V(sX+rW, sY+rH))
88+
imd.Rectangle(0)
89+
}
90+
}
91+
92+
imd.Draw(h.window)
93+
h.window.Update()
94+
}

internal/sound/a_sound-packr.go

100644100755
File mode changed.

internal/sound/data/beep.wav

100644100755
File mode changed.

internal/sound/sound.go

100644100755
+6-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ func Beep() error {
2525
return err
2626
}
2727

28-
speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
28+
if err = speaker.Init(
29+
format.SampleRate,
30+
format.SampleRate.N(time.Second/10),
31+
); err != nil {
32+
return err
33+
}
2934

3035
done := make(chan struct{})
3136
speaker.Play(beep.Seq(s, beep.Callback(func() {

0 commit comments

Comments
 (0)