Initial Game Logic
This commit is contained in:
89
django/templates/play/game/common_scripts.html
Normal file
89
django/templates/play/game/common_scripts.html
Normal file
@@ -0,0 +1,89 @@
|
||||
{% load static %}
|
||||
|
||||
<script>
|
||||
// Gemeinsame Funktionen für alle Spielseiten
|
||||
// Toast-Benachrichtigungen und WebSocket-Funktionen werden im globalen Scope definiert
|
||||
window.toast = {
|
||||
create(message, type = 'info') {
|
||||
const toastElement = document.createElement('div');
|
||||
toastElement.className = `toast toast-${type}`;
|
||||
toastElement.textContent = message;
|
||||
document.body.appendChild(toastElement);
|
||||
|
||||
// Animation
|
||||
setTimeout(() => {
|
||||
toastElement.classList.add('show');
|
||||
setTimeout(() => {
|
||||
toastElement.classList.remove('show');
|
||||
setTimeout(() => toastElement.remove(), 300);
|
||||
}, 3000);
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
// WebSocket-Hilfsfunktionen
|
||||
window.wsUtil = {
|
||||
handleClose(e) {
|
||||
if (e.code !== 1000 && e.code !== 1001) {
|
||||
console.error('WebSocket closed unexpectedly', e.code);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// WebSocket-Initialisierung
|
||||
window.initializeGameSocket = function(gameCode) {
|
||||
const wsScheme = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const gameSocket = new WebSocket(
|
||||
`${wsScheme}://${window.location.host}/ws/game/${gameCode}/`
|
||||
);
|
||||
|
||||
gameSocket.onmessage = (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.type === 'player_left') {
|
||||
const message = data.was_kicked
|
||||
? `${data.player_name} wurde wegen Inaktivität entfernt`
|
||||
: `${data.player_name} hat das Spiel verlassen`;
|
||||
toast.create(message, data.was_kicked ? 'error' : 'warning');
|
||||
}
|
||||
};
|
||||
|
||||
gameSocket.onclose = (e) => wsUtil.handleClose(e);
|
||||
|
||||
return gameSocket;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
padding: 12px 24px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
z-index: 9999;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.toast-info {
|
||||
background-color: #3498db;
|
||||
}
|
||||
|
||||
.toast-success {
|
||||
background-color: #2ecc71;
|
||||
}
|
||||
|
||||
.toast-warning {
|
||||
background-color: #f1c40f;
|
||||
}
|
||||
|
||||
.toast-error {
|
||||
background-color: #e74c3c;
|
||||
}
|
||||
</style>
|
||||
201
django/templates/play/game/finished.html
Normal file
201
django/templates/play/game/finished.html
Normal file
@@ -0,0 +1,201 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="bg-white rounded-lg shadow-md p-8 mb-6">
|
||||
<div class="text-center mb-8">
|
||||
<h1 class="text-4xl font-bold text-blue-600 mb-4">Quiz beendet!</h1>
|
||||
<p class="text-xl text-gray-600">Vielen Dank fürs Mitspielen!</p>
|
||||
</div>
|
||||
|
||||
{% if not is_host %}
|
||||
<div class="bg-blue-50 rounded-lg p-6 mb-8">
|
||||
<h2 class="text-2xl font-bold text-blue-800 mb-4 text-center">Wie hat dir das Quiz gefallen?</h2>
|
||||
<div class="stars flex justify-center space-x-4 mb-4">
|
||||
<i class="fas fa-star text-3xl transition-all duration-200 hover:scale-110" data-rating="1"></i>
|
||||
<i class="fas fa-star text-3xl transition-all duration-200 hover:scale-110" data-rating="2"></i>
|
||||
<i class="fas fa-star text-3xl transition-all duration-200 hover:scale-110" data-rating="3"></i>
|
||||
<i class="fas fa-star text-3xl transition-all duration-200 hover:scale-110" data-rating="4"></i>
|
||||
<i class="fas fa-star text-3xl transition-all duration-200 hover:scale-110" data-rating="5"></i>
|
||||
</div>
|
||||
<p id="rating-message" class="text-center text-blue-600 font-medium"></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="text-center">
|
||||
<a href="{% url 'homepage:home' %}"
|
||||
class="inline-block px-8 py-3 text-lg font-semibold text-white bg-blue-600 rounded-full hover:bg-blue-700 transform transition-all duration-200 hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
||||
Zurück zur Startseite
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if not is_host %}
|
||||
{% include 'play/game/common_scripts.html' %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const wsScheme = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
let gameSocket = null;
|
||||
let reconnectAttempts = 0;
|
||||
let pingInterval = null;
|
||||
const maxReconnectAttempts = 5;
|
||||
const pingDelay = 30000; // 30 seconds
|
||||
|
||||
function startPingInterval() {
|
||||
if (pingInterval) {
|
||||
clearInterval(pingInterval);
|
||||
}
|
||||
pingInterval = setInterval(() => {
|
||||
if (gameSocket && gameSocket.readyState === WebSocket.OPEN) {
|
||||
gameSocket.send(JSON.stringify({ type: 'ping' }));
|
||||
}
|
||||
}, pingDelay);
|
||||
}
|
||||
|
||||
function stopPingInterval() {
|
||||
if (pingInterval) {
|
||||
clearInterval(pingInterval);
|
||||
pingInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
function connectWebSocket() {
|
||||
if (gameSocket && (gameSocket.readyState === WebSocket.CONNECTING || gameSocket.readyState === WebSocket.OPEN)) {
|
||||
return gameSocket; // Already connected or connecting
|
||||
}
|
||||
|
||||
if (reconnectAttempts >= maxReconnectAttempts) {
|
||||
console.error('Max reconnection attempts reached');
|
||||
document.getElementById('rating-message').textContent = 'Verbindungsfehler. Bitte Seite neu laden.';
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
gameSocket = new WebSocket(
|
||||
`${wsScheme}://${window.location.host}/ws/game/{{ join_code }}/`
|
||||
);
|
||||
|
||||
gameSocket.onopen = function(e) {
|
||||
console.log('Game socket connected');
|
||||
reconnectAttempts = 0;
|
||||
startPingInterval();
|
||||
document.getElementById('rating-message').textContent = '';
|
||||
};
|
||||
|
||||
gameSocket.onclose = function(e) {
|
||||
wsUtil.handleClose(e);
|
||||
stopPingInterval();
|
||||
gameSocket = null;
|
||||
reconnectAttempts++;
|
||||
if (reconnectAttempts < maxReconnectAttempts) {
|
||||
document.getElementById('rating-message').textContent = 'Verbindung wird wiederhergestellt...';
|
||||
setTimeout(connectWebSocket, 1000 * Math.min(reconnectAttempts, 3));
|
||||
}
|
||||
};
|
||||
|
||||
gameSocket.onerror = function(e) {
|
||||
console.error('Game socket error:', e);
|
||||
document.getElementById('rating-message').textContent = 'Verbindungsfehler aufgetreten';
|
||||
};
|
||||
|
||||
return gameSocket;
|
||||
} catch (error) {
|
||||
console.error('Error creating WebSocket:', error);
|
||||
document.getElementById('rating-message').textContent = 'Verbindungsfehler aufgetreten';
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const stars = document.querySelectorAll('.stars i');
|
||||
let rated = false;
|
||||
|
||||
function setRating(rating) {
|
||||
stars.forEach((star, index) => {
|
||||
star.style.color = index < rating ? '#ffc107' : '#e4e5e9';
|
||||
});
|
||||
}
|
||||
|
||||
stars.forEach(star => {
|
||||
star.addEventListener('mouseover', function() {
|
||||
if (!rated) {
|
||||
setRating(this.dataset.rating);
|
||||
}
|
||||
});
|
||||
|
||||
star.addEventListener('mouseout', function() {
|
||||
if (!rated) {
|
||||
setRating(0);
|
||||
}
|
||||
});
|
||||
|
||||
star.addEventListener('click', function() {
|
||||
if (!rated) {
|
||||
const rating = parseInt(this.dataset.rating);
|
||||
rated = true;
|
||||
setRating(rating);
|
||||
|
||||
if (!gameSocket || gameSocket.readyState !== WebSocket.OPEN) {
|
||||
console.error('WebSocket is not connected');
|
||||
document.getElementById('rating-message').textContent = 'Verbindung wird hergestellt...';
|
||||
gameSocket = connectWebSocket();
|
||||
if (gameSocket) {
|
||||
const retryRating = () => {
|
||||
if (gameSocket.readyState === WebSocket.OPEN) {
|
||||
star.click();
|
||||
} else {
|
||||
setTimeout(retryRating, 500);
|
||||
}
|
||||
};
|
||||
setTimeout(retryRating, 1000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'submit_rating',
|
||||
'participant_id': '{{ participant_id }}',
|
||||
'rating': rating
|
||||
}));
|
||||
document.getElementById('rating-message').textContent = 'Danke für deine Bewertung!';
|
||||
stars.forEach(s => s.style.cursor = 'default');
|
||||
} catch (error) {
|
||||
console.error('Error sending rating:', error);
|
||||
document.getElementById('rating-message').textContent = 'Fehler beim Senden der Bewertung';
|
||||
rated = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Initial connection
|
||||
gameSocket = connectWebSocket();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.stars i {
|
||||
cursor: pointer;
|
||||
color: #e4e5e9;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.stars i:hover ~ i {
|
||||
color: #e4e5e9;
|
||||
}
|
||||
|
||||
.stars:hover i {
|
||||
color: #ffc107;
|
||||
}
|
||||
|
||||
.stars i:hover {
|
||||
transform: scale(1.2);
|
||||
color: #ffc107;
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user