Skip to content

Commit 0ee745a

Browse files
committed
Voeg een voorbeeld van het 2D actie avonturen spel toe
1 parent 7475c42 commit 0ee745a

16 files changed

+1646
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
categories:
3+
- Activiteiten
4+
tags:
5+
- 2D
6+
- Godot
7+
- Spel
8+
---
9+
10+
# Action Adventure
11+
12+
Tijdens deze activiteit gaan we een 2D, top-down, actie avonturen spel maken. Denk hierbij aan [de originele Zelda spellen](<https://nl.wikipedia.org/wiki/The_Legend_of_Zelda_(computerspel)>) voor de (S)NES, GameBoy, etc.
13+
14+
Voor het maken van het spel gebruiken we [een gratis, open-source, professionele game engine](https://godotengine.org/) waar vrijwel alle soorten spellen in gemaakt kunnen worden.
15+
16+
Hieronder vind je een voorbeeld van het soort spel dat we gaan maken.
17+
18+
[!embed height="370" text="Een voorbeeld van het 2D, top-down, actie avonturen spel wat we gaan maken. Klik op het spel en gebruik de pijltjestoetsen (of WASD) en de spatiebalk om te spelen." width="660"](./resources/example/)
19+
20+
_Dit is een erg lange activiteit die plaats vindt over meerdere CoderDojos! Zorg er voor dat je een eigen laptop meeneemt zodat je het spel kunt bewaren_
8.56 KB
Loading
11.6 KB
Loading
47.9 KB
Loading
11.6 KB
Loading
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**************************************************************************/
2+
/* godot.audio.position.worklet.js */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
const POST_THRESHOLD_S = 0.1;
32+
33+
class GodotPositionReportingProcessor extends AudioWorkletProcessor {
34+
constructor(...args) {
35+
super(...args);
36+
this.lastPostTime = currentTime;
37+
this.position = 0;
38+
this.ended = false;
39+
40+
this.port.onmessage = (event) => {
41+
if (event?.data?.type === 'ended') {
42+
this.ended = true;
43+
}
44+
};
45+
}
46+
47+
process(inputs, _outputs, _parameters) {
48+
if (this.ended) {
49+
return false;
50+
}
51+
52+
if (inputs.length > 0) {
53+
const input = inputs[0];
54+
if (input.length > 0) {
55+
this.position += input[0].length;
56+
}
57+
}
58+
59+
// Posting messages is expensive. Let's limit the number of posts.
60+
if (currentTime - this.lastPostTime > POST_THRESHOLD_S) {
61+
this.lastPostTime = currentTime;
62+
this.port.postMessage({ type: 'position', data: this.position });
63+
}
64+
65+
return true;
66+
}
67+
}
68+
69+
registerProcessor('godot-position-reporting-processor', GodotPositionReportingProcessor);
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/**************************************************************************/
2+
/* audio.worklet.js */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
class RingBuffer {
32+
constructor(p_buffer, p_state, p_threads) {
33+
this.buffer = p_buffer;
34+
this.avail = p_state;
35+
this.threads = p_threads;
36+
this.rpos = 0;
37+
this.wpos = 0;
38+
}
39+
40+
data_left() {
41+
return this.threads ? Atomics.load(this.avail, 0) : this.avail;
42+
}
43+
44+
space_left() {
45+
return this.buffer.length - this.data_left();
46+
}
47+
48+
read(output) {
49+
const size = this.buffer.length;
50+
let from = 0;
51+
let to_write = output.length;
52+
if (this.rpos + to_write > size) {
53+
const high = size - this.rpos;
54+
output.set(this.buffer.subarray(this.rpos, size));
55+
from = high;
56+
to_write -= high;
57+
this.rpos = 0;
58+
}
59+
if (to_write) {
60+
output.set(this.buffer.subarray(this.rpos, this.rpos + to_write), from);
61+
}
62+
this.rpos += to_write;
63+
if (this.threads) {
64+
Atomics.add(this.avail, 0, -output.length);
65+
Atomics.notify(this.avail, 0);
66+
} else {
67+
this.avail -= output.length;
68+
}
69+
}
70+
71+
write(p_buffer) {
72+
const to_write = p_buffer.length;
73+
const mw = this.buffer.length - this.wpos;
74+
if (mw >= to_write) {
75+
this.buffer.set(p_buffer, this.wpos);
76+
this.wpos += to_write;
77+
if (mw === to_write) {
78+
this.wpos = 0;
79+
}
80+
} else {
81+
const high = p_buffer.subarray(0, mw);
82+
const low = p_buffer.subarray(mw);
83+
this.buffer.set(high, this.wpos);
84+
this.buffer.set(low);
85+
this.wpos = low.length;
86+
}
87+
if (this.threads) {
88+
Atomics.add(this.avail, 0, to_write);
89+
Atomics.notify(this.avail, 0);
90+
} else {
91+
this.avail += to_write;
92+
}
93+
}
94+
}
95+
96+
class GodotProcessor extends AudioWorkletProcessor {
97+
constructor() {
98+
super();
99+
this.threads = false;
100+
this.running = true;
101+
this.lock = null;
102+
this.notifier = null;
103+
this.output = null;
104+
this.output_buffer = new Float32Array();
105+
this.input = null;
106+
this.input_buffer = new Float32Array();
107+
this.port.onmessage = (event) => {
108+
const cmd = event.data['cmd'];
109+
const data = event.data['data'];
110+
this.parse_message(cmd, data);
111+
};
112+
}
113+
114+
process_notify() {
115+
if (this.notifier) {
116+
Atomics.add(this.notifier, 0, 1);
117+
Atomics.notify(this.notifier, 0);
118+
}
119+
}
120+
121+
parse_message(p_cmd, p_data) {
122+
if (p_cmd === 'start' && p_data) {
123+
const state = p_data[0];
124+
let idx = 0;
125+
this.threads = true;
126+
this.lock = state.subarray(idx, ++idx);
127+
this.notifier = state.subarray(idx, ++idx);
128+
const avail_in = state.subarray(idx, ++idx);
129+
const avail_out = state.subarray(idx, ++idx);
130+
this.input = new RingBuffer(p_data[1], avail_in, true);
131+
this.output = new RingBuffer(p_data[2], avail_out, true);
132+
} else if (p_cmd === 'stop') {
133+
this.running = false;
134+
this.output = null;
135+
this.input = null;
136+
this.lock = null;
137+
this.notifier = null;
138+
} else if (p_cmd === 'start_nothreads') {
139+
this.output = new RingBuffer(p_data[0], p_data[0].length, false);
140+
} else if (p_cmd === 'chunk') {
141+
this.output.write(p_data);
142+
}
143+
}
144+
145+
static array_has_data(arr) {
146+
return arr.length && arr[0].length && arr[0][0].length;
147+
}
148+
149+
process(inputs, outputs, parameters) {
150+
if (!this.running) {
151+
return false; // Stop processing.
152+
}
153+
if (this.output === null) {
154+
return true; // Not ready yet, keep processing.
155+
}
156+
const process_input = GodotProcessor.array_has_data(inputs);
157+
if (process_input) {
158+
const input = inputs[0];
159+
const chunk = input[0].length * input.length;
160+
if (this.input_buffer.length !== chunk) {
161+
this.input_buffer = new Float32Array(chunk);
162+
}
163+
if (!this.threads) {
164+
GodotProcessor.write_input(this.input_buffer, input);
165+
this.port.postMessage({ 'cmd': 'input', 'data': this.input_buffer });
166+
} else if (this.input.space_left() >= chunk) {
167+
GodotProcessor.write_input(this.input_buffer, input);
168+
this.input.write(this.input_buffer);
169+
} else {
170+
// this.port.postMessage('Input buffer is full! Skipping input frame.'); // Uncomment this line to debug input buffer.
171+
}
172+
}
173+
const process_output = GodotProcessor.array_has_data(outputs);
174+
if (process_output) {
175+
const output = outputs[0];
176+
const chunk = output[0].length * output.length;
177+
if (this.output_buffer.length !== chunk) {
178+
this.output_buffer = new Float32Array(chunk);
179+
}
180+
if (this.output.data_left() >= chunk) {
181+
this.output.read(this.output_buffer);
182+
GodotProcessor.write_output(output, this.output_buffer);
183+
if (!this.threads) {
184+
this.port.postMessage({ 'cmd': 'read', 'data': chunk });
185+
}
186+
} else {
187+
// this.port.postMessage('Output buffer has not enough frames! Skipping output frame.'); // Uncomment this line to debug output buffer.
188+
}
189+
}
190+
this.process_notify();
191+
return true;
192+
}
193+
194+
static write_output(dest, source) {
195+
const channels = dest.length;
196+
for (let ch = 0; ch < channels; ch++) {
197+
for (let sample = 0; sample < dest[ch].length; sample++) {
198+
dest[ch][sample] = source[sample * channels + ch];
199+
}
200+
}
201+
}
202+
203+
static write_input(dest, source) {
204+
const channels = source.length;
205+
for (let ch = 0; ch < channels; ch++) {
206+
for (let sample = 0; sample < source[ch].length; sample++) {
207+
dest[sample * channels + ch] = source[ch][sample];
208+
}
209+
}
210+
}
211+
}
212+
213+
registerProcessor('godot-processor', GodotProcessor);

0 commit comments

Comments
 (0)