Skip to content

Commit 37e8a04

Browse files
authored
Merge pull request #67 from bertt6/single-player
single player game
2 parents 78680ad + e69d451 commit 37e8a04

File tree

10 files changed

+553
-8
lines changed

10 files changed

+553
-8
lines changed

API/API/urls.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
path('', include('Apps.Home.urls')),
2727
path('profile/', include('Apps.Profile.urls')),
2828
path('social/', include('Apps.SocialMedia.urls')),
29-
path('game/', include('Apps.Game.urls')),
29+
path('', include('Apps.Game.urls')),
3030
path('matchmaking/', include('Apps.Matchmaking.urls')),
3131
path('', include('Apps.Tournament.urls'))
3232
]

API/Apps/Game/urls.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
from . import views
55

66
urlpatterns = [
7-
path('<uuid:game_id>/',views.index,name='index'),
7+
path('game/<uuid:game_id>/', views.index, name='index'),
8+
path('play/', views.offline_game, name='offline_game'),
89
]

API/Apps/Game/views.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22

33

44
def index(request, game_id):
5-
return render(request, 'Game/Game.html')
5+
return render(request, 'Game/Game.html')
6+
7+
8+
def offline_game(request):
9+
return render(request, 'Game/OfflineGame.html')

API/static/scripts/login.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ import Spinner from "../components/spinner.js";
44
import {request} from "./Request.js";
55

66
document.getElementById('ecole-login-button').addEventListener('click', async () => {
7-
const response = await request(`direct-42-login-page/`, {
7+
const response = await request(`auth/direct-42-login-page/`, {
88
method: 'POST',
99
})
10+
console.log(response)
1011
if (response.oauth_url) {
1112
window.location.href = response.oauth_url
1213
}
1314
})
1415

1516
async function handle42APICallback(code) {
16-
const response = await request(`login-with-42/${code}/`, {
17+
const response = await request(`auth/login-with-42/${code}/`, {
1718
method: "POST",
1819
})
1920
if (response) {
@@ -32,7 +33,7 @@ async function loginForm(event)
3233
username: username,
3334
password: password
3435
};
35-
const endpoint = `send-email-for-verification/`;
36+
const endpoint = `auth/send-email-for-verification/`;
3637
const loginButton = document.getElementById('login-button');
3738
loginButton.disabled = true;
3839
const spinner = new Spinner({isVisible:true,className:"login-button-loader"}, loginButton);

API/static/scripts/offline-game.js

+221
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
import {BASE_URL, loadPage} from "./spa.js";
2+
3+
const canvas = document.getElementById('pongCanvas');
4+
const ctx = canvas.getContext('2d');
5+
6+
// Set initial positions for paddles and ball
7+
let ballX = canvas.width / 2;
8+
let ballY = canvas.height / 2;
9+
let ballSpeedX = 3;
10+
let ballSpeedY = 3;
11+
12+
const paddleHeight = 200;
13+
const paddleWidth = 10;
14+
const paddleSpeed = 5;
15+
16+
let player1Y = canvas.height / 2 - paddleHeight / 2;
17+
let player2Y = canvas.height / 2 - paddleHeight / 2;
18+
19+
let pause = false
20+
let finish = false
21+
let firstStart = true
22+
23+
let playerOneScore = 0
24+
let playerTwoScore = 0
25+
26+
let keysPressed = {};
27+
28+
function drawRect(x, y, width, height, color) {
29+
ctx.fillStyle = color;
30+
ctx.fillRect(x, y, width, height);
31+
}
32+
33+
function drawCircle(x, y, radius, color) {
34+
ctx.fillStyle = color;
35+
ctx.beginPath();
36+
ctx.arc(x, y, radius, 0, Math.PI * 2, true);
37+
ctx.fill();
38+
}
39+
40+
function pauseGame() {
41+
pause = true
42+
setTimeout(function () {
43+
pause = false
44+
}, 3000)
45+
}
46+
47+
function draw() {
48+
// clear the canvas
49+
drawRect(0, 0, canvas.width, canvas.height, 'black');
50+
// draw net
51+
drawRect(canvas.width / 2 - 1, 0, 2, 1000, 'gray');
52+
// draw paddles
53+
drawRect(0, player1Y, paddleWidth, paddleHeight, 'white');
54+
drawRect(canvas.width - paddleWidth, player2Y, paddleWidth, paddleHeight, 'white');
55+
// draw ball
56+
drawCircle(ballX, ballY, 15, 'white');
57+
if (firstStart) {
58+
firstStart = false
59+
printCountdown()
60+
pauseGame()
61+
}
62+
}
63+
64+
function update() {
65+
ballSpeedY *= 1.0004
66+
ballSpeedX *= 1.0004
67+
ballX += ballSpeedX;
68+
ballY += ballSpeedY;
69+
70+
// ball collision with top and bottom walls
71+
if (ballY < 0 || ballY > canvas.height) {
72+
ballSpeedY = -ballSpeedY;
73+
}
74+
75+
// ball collision with paddles
76+
if (
77+
(ballX <= paddleWidth && ballY > player1Y && ballY < player1Y + paddleHeight) ||
78+
(ballX >= canvas.width - paddleWidth && ballY > player2Y && ballY < player2Y + paddleHeight)
79+
) {
80+
ballSpeedX = -ballSpeedX;
81+
}
82+
83+
// ball out of bounds, reset position
84+
if (ballX < 0 || ballX > canvas.width) {
85+
setCurrentPoints()
86+
ballX = canvas.width / 2;
87+
ballY = canvas.height / 2;
88+
ballSpeedX = -ballSpeedX;
89+
player1Y = canvas.height / 2 - paddleHeight / 2;
90+
player2Y = canvas.height / 2 - paddleHeight / 2;
91+
if (!finish) {
92+
printCountdown()
93+
pauseGame()
94+
}
95+
}
96+
}
97+
98+
function gameLoop() {
99+
if (!pause && !finish) {
100+
updatePaddlePositions();
101+
update();
102+
draw();
103+
}
104+
requestAnimationFrame(gameLoop);
105+
}
106+
107+
gameLoop();
108+
109+
function setCurrentPoints() {
110+
if (ballX < 0) {
111+
playerTwoScore++
112+
113+
} else {
114+
playerOneScore++
115+
}
116+
117+
let points = document.getElementById("game-points");
118+
119+
points.innerText = `${playerOneScore} - ${playerTwoScore}`;
120+
121+
if (playerOneScore == 5) {
122+
printWinner("Player 1")
123+
} else if (playerTwoScore == 5) {
124+
printWinner("Player 2")
125+
}
126+
127+
}
128+
129+
// handle player controls
130+
// Object to track pressed keys
131+
132+
// Handle keydown event
133+
window.addEventListener('keydown', function (event) {
134+
keysPressed[event.key] = true;
135+
});
136+
137+
// Handle keyup event
138+
window.addEventListener('keyup', function (event) {
139+
keysPressed[event.key] = false;
140+
});
141+
142+
143+
// Update paddle positions based on keys pressed
144+
function updatePaddlePositions() {
145+
if (keysPressed['w']) {
146+
if (player1Y > 0) { // Check if paddle 1 is not at the top edge
147+
player1Y -= paddleSpeed;
148+
}
149+
}
150+
if (keysPressed['s']) {
151+
if (player1Y < canvas.height - paddleHeight) { // Check if paddle 1 is not at the bottom edge
152+
player1Y += paddleSpeed;
153+
}
154+
}
155+
if (keysPressed['ArrowUp']) {
156+
if (player2Y > 0) { // Check if paddle 2 is not at the top edge
157+
player2Y -= paddleSpeed;
158+
}
159+
}
160+
if (keysPressed['ArrowDown']) {
161+
if (player2Y < canvas.height - paddleHeight) { // Check if paddle 2 is not at the bottom edge
162+
player2Y += paddleSpeed;
163+
}
164+
}
165+
}
166+
167+
168+
function printCountdown() {
169+
let countdown = 3;
170+
let element = document.createElement("div");
171+
element.id = "game-message-wrapper";
172+
let textElement = document.createElement("h1");
173+
textElement.id = "countdown";
174+
textElement.innerText = countdown.toString();
175+
element.appendChild(textElement);
176+
document.body.appendChild(element);
177+
let interval = setInterval(() => {
178+
countdown -= 1;
179+
textElement.classList.add("fade-in");
180+
textElement.innerText = countdown.toString();
181+
if (countdown === 0) {
182+
clearInterval(interval);
183+
element.remove();
184+
}
185+
}, 1000);
186+
}
187+
188+
function printWinner(winner) {
189+
finish = true
190+
let winnerHTML = `
191+
<div class="winner-wrapper">
192+
<div class="winner-image-wrapper">
193+
<img src="https://picsum.photos/seed/picsum/200/300" alt="" />
194+
</div>
195+
<div class="info-area">
196+
<h2>Winner is ${winner}</h2>
197+
<h1 id="play-again" class="play-again">Play Again</h1>
198+
</div>
199+
</div>
200+
`
201+
let element = document.createElement("div");
202+
element.id = "game-message-wrapper";
203+
element.innerHTML = winnerHTML;
204+
document.body.appendChild(element);
205+
const playAgain = document.getElementById('play-again')
206+
playAgain.addEventListener('click', () => {
207+
element.remove()
208+
resStartGame()
209+
})
210+
}
211+
212+
213+
function resStartGame() {
214+
printCountdown()
215+
playerOneScore = 0
216+
playerTwoScore = 0
217+
let points = document.getElementById("game-points");
218+
points.innerText = `${playerOneScore} - ${playerTwoScore}`;
219+
pauseGame()
220+
finish = false
221+
}

API/static/scripts/spa.js

+49
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,54 @@ const routes = new Map([
654654
</div>
655655
`
656656

657+
}],
658+
['offline-game', {
659+
auth_required: true,
660+
url: ['/play/'],
661+
html: `
662+
<div
663+
class="background container-fluid social-background"
664+
style="padding: 0"
665+
>
666+
<div class="game-container">
667+
668+
<div class="game-wrapper">
669+
<div class="game-data-wrapper">
670+
671+
<div class="game-player-data" id="player-one">
672+
<div class="player-image">
673+
<img src="https://picsum.photos/seed/picsum/200/300" alt="Player 2">
674+
</div>
675+
<div class="player-description" id="player-one-details">
676+
<span class="player-name">Player 1</span>
677+
</div>
678+
</div>
679+
<div class="game-points">
680+
<h1 id="game-points" class="skeleton">
681+
0 - 0
682+
</h1>
683+
</div>
684+
<div class="game-player-data" id="player-two">
685+
<div class="player-image">
686+
<img src="https://picsum.photos/seed/picsum/200/300" alt="Player 2">
687+
</div>
688+
<div class="player-description" id="player-two-details">
689+
<span class="player-name">Player 2</span>
690+
</div>
691+
</div>
692+
693+
</div>
694+
<div class="" id="canvas-wrapper">
695+
<div class="spectators-wrapper" id="spectators-wrapper">
696+
</div>
697+
<div class="canvas-wrapper">
698+
<canvas class="canvas-class" id="pongCanvas" width="1368" height="600"></canvas>
699+
</div>
700+
</div>
701+
</div>
702+
</div>
703+
</div>
704+
`
657705
}]
658706
]);
659707
const routeToFile = [
@@ -668,6 +716,7 @@ const routeToFile = [
668716
[['/tournaments/'], 'tournaments'],
669717
[['/create-tournament/'], 'create-tournament'],
670718
[[/tournament\/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})/], 'tournament'],
719+
[['/play/'], 'offline-game'],
671720
]
672721
const requiredScripts = [
673722
'/static/components/Notification.js',

API/static/scripts/verification.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ document.getElementById("verify").addEventListener("click", async function() {
4949

5050
async function postVerificationCode(value) {
5151
try {
52-
let response = await request(`email-verification/`, {
52+
let response = await request(`auth/email-verification/`, {
5353
method: 'POST',
5454
headers: {
5555
'Content-Type': 'application/json',

API/static/styles/game.css

+17-1
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,24 @@
101101
align-items: center;
102102
justify-content: center;
103103
animation: fadeIn 1s;
104+
gap: 20px;
104105
}
105-
.winner-wrapper h1{
106+
107+
.play-again {
108+
cursor: pointer;
109+
transition: all 0.5s;
110+
}
111+
112+
.play-again:hover {
113+
scale: 1.06;
114+
}
115+
116+
.info-area {
117+
display: flex;
118+
flex-direction: column;
119+
}
120+
121+
.winner-wrapper h1 h2 {
106122
margin: 0;
107123
}
108124
.winner-image-wrapper{

0 commit comments

Comments
 (0)