Skip to content

Commit 6e2c3b8

Browse files
committed
Game Controller support
1 parent a0312cb commit 6e2c3b8

File tree

10 files changed

+132
-14
lines changed

10 files changed

+132
-14
lines changed

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,25 @@ Prince of Persia reimplementation written in HTML5 / JavaScript (MS-DOS version)
77
- Browser: https://princejs.com
88
- Keyboard
99
- `Cursor keys`: Movement
10-
- `Left/Right key`: Move Left/Right, Advance/Retreat
10+
- `Left / Right key`: Move Left/Right, Advance/Retreat
1111
- `Up key`: Jump, Climb Up, Block Attack
1212
- `Down key`: Crouch, Crawl, Climb Down, Sheathe Sword
1313
- `SHIFT`: Drink Potion, Grab Edge, Sword Strike
1414
- `SPACE`: Show Remaining Time
1515
- `ENTER`: Continue Game
16-
- Mouse Controls
16+
- Mouse
1717
- See Touch Controls for Mobile
18+
- Game Controller
19+
- `Left / Right Stick, DPad`: Movement
20+
- `Left / Right`: Move Left/Right, Advance/Retreat
21+
- `Up`: Jump, Climb Up, Block Attack
22+
- `Down`: Crouch, Crawl, Climb Down, Sheathe Sword
23+
- `A / R / ZR Button`: Jump, Climb Up, Block Attack
24+
- `B / X / Y / L / ZL Button`: Drink Potion, Grab Edge, Sword Strike
25+
- `Home/Record`: (1x) Show Remaining Time, (2x) Restart Level
26+
- `Minus Button`: Previous Level
27+
- `Plus Button`: Next Level
28+
- `Any`: Continue Game
1829

1930
## Play Mobile
2031

src/Credits.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ PrinceJS.Credits.prototype = {
6969
this.back.updateCrop();
7070
this.credits.updateCrop();
7171

72-
if (PrinceJS.Utils.pointerPressed(this.game)) {
72+
if (PrinceJS.Utils.continueGame(this.game)) {
7373
this.play();
7474
}
7575
},

src/Cutscene.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ PrinceJS.Cutscene.prototype = {
146146
},
147147

148148
update: function () {
149-
if (PrinceJS.Utils.pointerPressed(this.game)) {
149+
if (PrinceJS.Utils.continueGame(this.game)) {
150150
this.continue();
151151
}
152152
},

src/EndTitle.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ PrinceJS.EndTitle.prototype = {
6161
this.tick++;
6262
this.textBack.updateCrop();
6363

64-
if (PrinceJS.Utils.pointerPressed(this.game)) {
64+
if (PrinceJS.Utils.continueGame(this.game)) {
6565
this.next();
6666
}
6767
},

src/Enemy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ PrinceJS.Enemy.prototype.canWalkSafely = function (tile, below = false) {
187187
return tile.isSafeWalkable();
188188
}
189189
return false;
190-
}
190+
};
191191

192192
PrinceJS.Enemy.prototype.engarde = function () {
193193
if (!this.hasSword) {

src/Game.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ PrinceJS.Game.prototype = {
140140
},
141141

142142
update: function () {
143-
if (PrinceJS.Utils.pointerPressed(this.game)) {
143+
if (PrinceJS.Utils.continueGame(this.game)) {
144144
this.buttonPressed();
145145
let pos = PrinceJS.Utils.effectivePointer(this.game);
146146
let size = PrinceJS.Utils.effectiveScreenSize(this.game);
@@ -161,6 +161,17 @@ PrinceJS.Game.prototype = {
161161
this.showRemainingMinutes();
162162
}
163163
}
164+
if (PrinceJS.Utils.gamepadInfoPressed(this.game)) {
165+
if (this.isRemainingMinutesShown() || this.isLevelShown()) {
166+
this.restartLevel(true);
167+
} else {
168+
this.showRemainingMinutes();
169+
}
170+
} else if (PrinceJS.Utils.gamepadPreviousPressed(this.game)) {
171+
this.previousLevel(PrinceJS.currentLevel, true);
172+
} else if (PrinceJS.Utils.gamepadNextPressed(this.game)) {
173+
this.nextLevel(PrinceJS.currentLevel, true, true);
174+
}
164175
}
165176
},
166177

src/Kid.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,23 +1096,23 @@ PrinceJS.Kid.prototype.tryPickup = function () {
10961096
};
10971097

10981098
PrinceJS.Kid.prototype.keyL = function () {
1099-
return this.cursors.left.isDown || this.pointerL();
1099+
return this.cursors.left.isDown || this.pointerL() || PrinceJS.Utils.gamepadLeftPressed(this.game);
11001100
};
11011101

11021102
PrinceJS.Kid.prototype.keyR = function () {
1103-
return this.cursors.right.isDown || this.pointerR();
1103+
return this.cursors.right.isDown || this.pointerR() || PrinceJS.Utils.gamepadRightPressed(this.game);
11041104
};
11051105

11061106
PrinceJS.Kid.prototype.keyU = function () {
1107-
return this.cursors.up.isDown || this.pointerU();
1107+
return this.cursors.up.isDown || this.pointerU() || PrinceJS.Utils.gamepadUpPressed(this.game);
11081108
};
11091109

11101110
PrinceJS.Kid.prototype.keyD = function () {
1111-
return this.cursors.down.isDown || this.pointerD();
1111+
return this.cursors.down.isDown || this.pointerD() || PrinceJS.Utils.gamepadDownPressed(this.game);
11121112
};
11131113

11141114
PrinceJS.Kid.prototype.keyS = function () {
1115-
return this.shiftKey.isDown || this.pointerS();
1115+
return this.shiftKey.isDown || this.pointerS() || PrinceJS.Utils.gamepadActionPressed(this.game);
11161116
};
11171117

11181118
PrinceJS.Kid.prototype.pointerL = function () {

src/Preloader.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,15 @@ PrinceJS.Preloader.prototype = {
100100
this.game.input.addPointer();
101101
this.game.input.addPointer();
102102

103+
this.game.input.gamepad.start();
104+
103105
this.game.canvas.oncontextmenu = function (event) {
104106
event.preventDefault();
105107
};
106108
},
107109

108110
update: function () {
109-
if (PrinceJS.Utils.pointerPressed(this.game)) {
111+
if (PrinceJS.Utils.continueGame(this.game)) {
110112
this.start();
111113
}
112114
},

src/Title.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ PrinceJS.Title.prototype = {
8989
this.tick++;
9090
this.textBack.updateCrop();
9191

92-
if (PrinceJS.Utils.pointerPressed(this.game)) {
92+
if (PrinceJS.Utils.continueGame(this.game)) {
9393
this.play();
9494
}
9595
},

src/Utils.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,100 @@ PrinceJS.Utils = {
114114
return Math.floor(Math.random() * Math.floor(max));
115115
},
116116

117+
continueGame: function (game) {
118+
return PrinceJS.Utils.pointerPressed(game) || PrinceJS.Utils.gamepadAnyPressed(game);
119+
},
120+
121+
gamepadButtonPressedCheck: function (game, buttons, name = "default") {
122+
if (this[`_${name}Pressed`]) {
123+
return false;
124+
}
125+
let pressed = false;
126+
let pad = game.input.gamepad.pad1;
127+
if (pad && pad.connected) {
128+
if (!buttons) {
129+
buttons = Object.keys(pad._rawPad.buttons).map((button) => parseInt(button));
130+
}
131+
for (let button of buttons) {
132+
if (pad.justPressed(button)) {
133+
pressed = true;
134+
}
135+
}
136+
}
137+
if (pressed) {
138+
this[`_${name}Pressed`] = true;
139+
PrinceJS.Utils.delayed(() => {
140+
this[`_${name}Pressed`] = false;
141+
}, 500);
142+
}
143+
return pressed;
144+
},
145+
146+
gamepadButtonDownCheck: function (game, buttons) {
147+
let pad = game.input.gamepad.pad1;
148+
if (pad && pad.connected) {
149+
if (!buttons) {
150+
buttons = Object.keys(pad._rawPad.buttons).map((button) => parseInt(button));
151+
}
152+
for (let button of buttons) {
153+
if (pad.isDown(button)) {
154+
return true;
155+
}
156+
}
157+
}
158+
return false;
159+
},
160+
161+
gamepadAxisCheck: function (game, axes, comparison) {
162+
let pad = game.input.gamepad.pad1;
163+
if (pad && pad.connected) {
164+
for (let axis of axes) {
165+
if (comparison === "<" && pad.axis(axis) < -0.75) {
166+
return true;
167+
} else if (comparison === ">" && pad.axis(axis) > 0.75) {
168+
return true;
169+
}
170+
}
171+
}
172+
return false;
173+
},
174+
175+
gamepadAnyPressed: function (game) {
176+
return PrinceJS.Utils.gamepadButtonPressedCheck(game);
177+
},
178+
179+
gamepadUpPressed: function (game) {
180+
return PrinceJS.Utils.gamepadButtonDownCheck(game, [1, 5, 7, 12]) || PrinceJS.Utils.gamepadAxisCheck(game, [1, 3], "<");
181+
},
182+
183+
gamepadDownPressed: function (game) {
184+
return PrinceJS.Utils.gamepadButtonDownCheck(game, [13]) || PrinceJS.Utils.gamepadAxisCheck(game, [1, 3], ">");
185+
},
186+
187+
gamepadLeftPressed: function (game) {
188+
return PrinceJS.Utils.gamepadButtonDownCheck(game, [14]) || PrinceJS.Utils.gamepadAxisCheck(game, [0, 2], "<");
189+
},
190+
191+
gamepadRightPressed: function (game) {
192+
return PrinceJS.Utils.gamepadButtonDownCheck(game, [15]) || PrinceJS.Utils.gamepadAxisCheck(game, [0, 2], ">");
193+
},
194+
195+
gamepadActionPressed: function (game) {
196+
return PrinceJS.Utils.gamepadButtonDownCheck(game, [0, 2, 3, 4, 6]);
197+
},
198+
199+
gamepadInfoPressed: function (game) {
200+
return PrinceJS.Utils.gamepadButtonPressedCheck(game, [16, 17, 18, 19, 20, 21], "info");
201+
},
202+
203+
gamepadPreviousPressed: function (game) {
204+
return PrinceJS.Utils.gamepadButtonPressedCheck(game, [8], "previous");
205+
},
206+
207+
gamepadNextPressed: function (game) {
208+
return PrinceJS.Utils.gamepadButtonPressedCheck(game, [9], "next");
209+
},
210+
117211
pointerPressed: function (game) {
118212
let pointerPressed = this._pointerPressed;
119213
this._pointerPressed = PrinceJS.Utils.pointerDown(game);

0 commit comments

Comments
 (0)