1 | - **Character Name**: [](:?CharacterName)
|
2 | - **Music**: [](:XMusicOn)
|
3 |
|
4 | ---
|
5 |
|
6 | ```p5js/playable/autoplay
|
7 | // A sound file object
|
8 | var song;
|
9 | var spriteX;
|
10 | var spriteY;
|
11 | var statusHeight = 30;
|
12 | var controlHeight = 50;
|
13 | var trapezoidWidth = 100;
|
14 | var trapezoidHeight = 200;
|
15 | var upButton, downButton, leftButton, rightButton, spaceButton;
|
16 | var musicOn = env.MusicOn;
|
17 |
|
18 | var myCanvas;
|
19 | var myDiv = this.div;
|
20 | myDiv.style.setProperty ("width", "420px", "important");
|
21 | myDiv.style.setProperty ("height", "420px", "important");
|
22 | myDiv.style.setProperty ("margin", "auto", "important");
|
23 | myDiv.style.setProperty ("padding", "5px", "important");
|
24 |
|
25 | function centerCanvas() {
|
26 | if (myCanvas) {
|
27 | var x = (p5.windowWidth - myDiv.width) / 2;
|
28 | var y = (p5.windowHeight - myDiv.height) / 2;
|
29 | myCanvas.position(x, y);
|
30 | }
|
31 | }
|
32 |
|
33 | p5.preload = function () {
|
34 | // Load a sound file
|
35 | var sound = 'https://gist.githubusercontent.com/DoctorBud/fce56b81a1902c551c3dfe86afbaf6bb/raw/5c9ca439a6dfc234b48a677c22e3286850a7747b/Crystal2.ogg.mp3';
|
36 | song = p5.loadSound(sound);
|
37 | };
|
38 |
|
39 | p5.setup = function () {
|
40 | // song.loop(); // Loop the sound forever
|
41 |
|
42 | myCanvas = p5.createCanvas(400, 400);
|
43 | p5.textSize(20);
|
44 | p5.textFont('Helvetica');
|
45 | p5.strokeWeight(2);
|
46 |
|
47 | function makeButton(label, right, top, keyCode) {
|
48 | var result = p5.createButton(label);
|
49 | result.class('btn-mobile-button');
|
50 | // result.style('right', right + 'px');
|
51 | result.style('left', (200 + right) + 'px');
|
52 | result.style('top', (top) + 'px');
|
53 | result.size(25, 25);
|
54 | result.mouseClicked(function() {
|
55 | p5.handleKey(keyCode);
|
56 | });
|
57 | return result;
|
58 | }
|
59 |
|
60 | upButton = makeButton('↑', 60, 55, p5.UP_ARROW);
|
61 | downButton = makeButton('↓', 60, 115, p5.DOWN_ARROW);
|
62 | leftButton = makeButton('←', 30, 85, p5.LEFT_ARROW);
|
63 | rightButton = makeButton('→', 90, 85, p5.RIGHT_ARROW);
|
64 | spaceButton = makeButton('∞', 60, 85, 32);
|
65 |
|
66 | p5.windowResized();
|
67 | };
|
68 |
|
69 | p5.windowResized = function() {
|
70 | var w = 400; // p5.windowWidth - 40;
|
71 | var h = 400;
|
72 | p5.resizeCanvas(w, 400);
|
73 | centerCanvas();
|
74 |
|
75 | if (!spriteX) {
|
76 | spriteX = w / 2;
|
77 | }
|
78 | if (!spriteY) {
|
79 | spriteY = h / 2;
|
80 | }
|
81 | if (spriteX > w) {
|
82 | spriteX = w;
|
83 | }
|
84 | if (spriteY > h) {
|
85 | spriteY = h;
|
86 | }
|
87 | };
|
88 |
|
89 | p5.handleKey = function(key) {
|
90 | var delta = 5;
|
91 | if (key === p5.LEFT_ARROW) {
|
92 | spriteX -= delta;
|
93 | if (spriteX < 0) {
|
94 | spriteX = 0;
|
95 | }
|
96 | }
|
97 | else if (key === p5.RIGHT_ARROW) {
|
98 | spriteX += delta;
|
99 | if (spriteX > p5.width) {
|
100 | spriteX = p5.width;
|
101 | }
|
102 | }
|
103 | else if (key === p5.UP_ARROW) {
|
104 | spriteY -= delta;
|
105 | if (spriteY < 0) {
|
106 | spriteY = 0;
|
107 | }
|
108 | }
|
109 | else if (key === p5.DOWN_ARROW) {
|
110 | spriteY += delta;
|
111 | if (spriteY > p5.height) {
|
112 | spriteY = p5.height;
|
113 | }
|
114 | }
|
115 | else if (key === 32) {
|
116 | spriteX = p5.width / 2;
|
117 | spriteY = p5.height / 2;
|
118 | }
|
119 | };
|
120 |
|
121 | p5.keyPressed = function(e) {
|
122 | var validKeys = [
|
123 | p5.LEFT_ARROW,
|
124 | p5.RIGHT_ARROW,
|
125 | p5.UP_ARROW,
|
126 | p5.DOWN_ARROW,
|
127 | 32
|
128 | ];
|
129 |
|
130 | if (validKeys.indexOf(p5.keyCode) < 0) {
|
131 | return true;
|
132 | }
|
133 | else {
|
134 | p5.handleKey(p5.keyCode);
|
135 | }
|
136 | };
|
137 |
|
138 | p5.draw = function () {
|
139 | if (!musicOn && env.MusicOn) {
|
140 | song.loop();
|
141 | }
|
142 | else if (musicOn && !env.MusicOn) {
|
143 | song.stop();
|
144 | }
|
145 | musicOn = env.MusicOn;
|
146 |
|
147 | if (p5.keyIsPressed) {
|
148 | p5.keyPressed();
|
149 | }
|
150 |
|
151 | p5.background('lightgray');
|
152 |
|
153 | var forwardViewWidth = p5.width;
|
154 | var forwardViewHeight = p5.height - statusHeight;
|
155 | var forwardViewX = 0;
|
156 | var forwardViewY = statusHeight;
|
157 | var trapezoidX = forwardViewX + forwardViewWidth / 2 - trapezoidWidth / 2;
|
158 | var trapezoidY = forwardViewY + forwardViewHeight / 2 - trapezoidHeight / 2;
|
159 | p5.fill('lightblue');
|
160 | p5.stroke('darkslateblue');
|
161 | p5.rect(trapezoidX, trapezoidY, trapezoidWidth, trapezoidHeight);
|
162 | p5.fill('lightyellow');
|
163 | p5.quad(
|
164 | forwardViewX, forwardViewY,
|
165 | trapezoidX, trapezoidY,
|
166 | trapezoidX, trapezoidY + trapezoidHeight,
|
167 | forwardViewX, forwardViewY + forwardViewHeight);
|
168 | p5.quad(
|
169 | forwardViewX + forwardViewWidth, forwardViewY,
|
170 | forwardViewX + trapezoidX + trapezoidWidth, trapezoidY,
|
171 | forwardViewX + trapezoidX + trapezoidWidth, trapezoidY + trapezoidHeight,
|
172 | forwardViewX + forwardViewWidth, forwardViewY + forwardViewHeight);
|
173 | p5.fill('black');
|
174 | p5.stroke('black');
|
175 | var yDelta = 38; // FIXME - Trigonometry needed here
|
176 | p5.rect(forwardViewX + forwardViewWidth / 6, forwardViewY + yDelta,
|
177 | 1, forwardViewHeight - 2 * yDelta);
|
178 | p5.rect(forwardViewX + 5 * forwardViewWidth / 6, forwardViewY + yDelta,
|
179 | 1, forwardViewHeight - 2 * yDelta);
|
180 |
|
181 | p5.fill('red');
|
182 | p5.stroke('darkslateblue');
|
183 | p5.ellipse(spriteX, spriteY, 10, 10);
|
184 |
|
185 | p5.fill('black');
|
186 | p5.rect(0, 0, p5.width, statusHeight);
|
187 | var name = env.CharacterName || 'Dungeoneer';
|
188 | p5.fill('lightgreen');
|
189 | p5.stroke('lightgreen');
|
190 | p5.text(name, 5, 0.75 * statusHeight);
|
191 | };
|
192 |
|
193 | ```
|
194 |
|
195 | ---
|
196 |
|
197 | ## SmartDown Game Tech Example - Part I
|
198 |
|
199 | I initially began this project in late 2016, inspired by [Global Game Jam Weekend](http://globalgamejam.org). Although I didn't complete it during the Game Jam, I have been slowly advancing it and fixing Smartdown to make it more easy.
|
200 |
|
201 | This is an experiment in using [Smartdown](http://smartdown.site/?url=README.md) and [p5.js](http://p5js.org) to build a simple, but extensible and distributed, game. The game UI is primarily written using `p5.js`, and Smartdown is being used as a prose-oriented wrapper that also provides a way to render the `p5.js`. Smartdown *Variables* are used to communicate the player name and the MusicOn/Off status between the Smartdown and the embedded sketch.
|
202 |
|
203 | My goal with this first example is to build a rough skeleton of a game that has keyboard controls, some sort of goal or transition (e.g., to a next level), and some visual navigation. Currently, the keyboard controls can be used to move a little red dot around on the screen. There are currently no transitions or goals achievable.
|
204 |
|
205 | My ultimate goal, probably in Parts II or III of this sequence, is to build a Wizardry-style game with a simple vector hallway/room representation, and to be able to link different *levels* together via URL so that a dungeon can be stored and explored in a completely distributed fashion, with some authors hosting their content on GitHub, others on websites, and others via dynamically generated API servers.
|
206 |
|
207 | In theory, I could first try to implement my [Basilisk Game](http://doctorbud.com/celestial-toys/post/2015-02-03-slide-puzzle-combinators/) example, which was written as a ReactJS exercise.
|
208 |
|
209 | ---
|
210 |
|
211 | [Back to Home](:@Home)
|