Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -4,6 +4,7 @@ import random
|
|
| 4 |
import time
|
| 5 |
import os
|
| 6 |
from streamlit_javascript import st_javascript
|
|
|
|
| 7 |
|
| 8 |
# Constants
|
| 9 |
GRID_SIZE = 10
|
|
@@ -26,7 +27,7 @@ def load_game_state():
|
|
| 26 |
if os.path.exists(GAME_STATE_FILE):
|
| 27 |
with open(GAME_STATE_FILE, "r") as f:
|
| 28 |
return json.load(f)
|
| 29 |
-
return {"players": {}}
|
| 30 |
|
| 31 |
# Function to save game state
|
| 32 |
def save_game_state(state):
|
|
@@ -48,26 +49,67 @@ def update_player_position(player_name, x, y):
|
|
| 48 |
def generate_svg(game_state):
|
| 49 |
svg = f'<svg width="{GRID_SIZE * CELL_SIZE}" height="{GRID_SIZE * CELL_SIZE}" xmlns="http://www.w3.org/2000/svg">'
|
| 50 |
|
| 51 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
for i in range(GRID_SIZE):
|
| 53 |
for j in range(GRID_SIZE):
|
| 54 |
-
svg += f'<rect x="{i * CELL_SIZE}" y="{j * CELL_SIZE}" width="{CELL_SIZE}" height="{CELL_SIZE}" fill="
|
| 55 |
|
| 56 |
-
# Draw players
|
| 57 |
for player, data in game_state["players"].items():
|
| 58 |
x, y = data["x"] * CELL_SIZE + CELL_SIZE // 2, data["y"] * CELL_SIZE + CELL_SIZE // 2
|
| 59 |
color = data.get("color", "#000000")
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
svg += '</circle>'
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
svg += '</svg>'
|
| 67 |
return svg
|
| 68 |
|
| 69 |
# Streamlit app
|
| 70 |
-
st.set_page_config(layout="wide")
|
| 71 |
st.title("Enhanced Multiplayer Grid Game")
|
| 72 |
|
| 73 |
# Display player name and allow updates
|
|
@@ -84,25 +126,46 @@ with col2:
|
|
| 84 |
# Create grid
|
| 85 |
grid = st.empty()
|
| 86 |
|
| 87 |
-
# JavaScript for smooth movement
|
| 88 |
js_code = """
|
| 89 |
function movePlayer(playerId, fromX, fromY, toX, toY) {
|
| 90 |
const player = document.getElementById(playerId);
|
| 91 |
if (player) {
|
| 92 |
-
const
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
}
|
| 101 |
}
|
| 102 |
"""
|
| 103 |
|
| 104 |
st.components.v1.html(f"<script>{js_code}</script>", height=0)
|
| 105 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
# Main game loop
|
| 107 |
while True:
|
| 108 |
# Load current game state
|
|
@@ -117,6 +180,7 @@ while True:
|
|
| 117 |
with col1:
|
| 118 |
if st.button("Select Your Character"):
|
| 119 |
st.session_state.selected_player = st.session_state.player_name
|
|
|
|
| 120 |
|
| 121 |
with col2:
|
| 122 |
if st.session_state.selected_player:
|
|
@@ -126,7 +190,7 @@ while True:
|
|
| 126 |
current_pos = game_state["players"].get(st.session_state.player_name, {"x": GRID_SIZE // 2, "y": GRID_SIZE // 2})
|
| 127 |
from_x, from_y = current_pos["x"] * CELL_SIZE + CELL_SIZE // 2, current_pos["y"] * CELL_SIZE + CELL_SIZE // 2
|
| 128 |
to_x, to_y = target_x * CELL_SIZE + CELL_SIZE // 2, target_y * CELL_SIZE + CELL_SIZE // 2
|
| 129 |
-
st_javascript(f"movePlayer('{st.session_state.player_name}', {from_x}, {from_y}, {to_x}, {to_y})")
|
| 130 |
update_player_position(st.session_state.player_name, target_x, target_y)
|
| 131 |
|
| 132 |
# Wait for update interval
|
|
|
|
| 4 |
import time
|
| 5 |
import os
|
| 6 |
from streamlit_javascript import st_javascript
|
| 7 |
+
from math import cos, sin, pi
|
| 8 |
|
| 9 |
# Constants
|
| 10 |
GRID_SIZE = 10
|
|
|
|
| 27 |
if os.path.exists(GAME_STATE_FILE):
|
| 28 |
with open(GAME_STATE_FILE, "r") as f:
|
| 29 |
return json.load(f)
|
| 30 |
+
return {"players": {}, "obstacles": []}
|
| 31 |
|
| 32 |
# Function to save game state
|
| 33 |
def save_game_state(state):
|
|
|
|
| 49 |
def generate_svg(game_state):
|
| 50 |
svg = f'<svg width="{GRID_SIZE * CELL_SIZE}" height="{GRID_SIZE * CELL_SIZE}" xmlns="http://www.w3.org/2000/svg">'
|
| 51 |
|
| 52 |
+
# Define gradients
|
| 53 |
+
svg += '''
|
| 54 |
+
<defs>
|
| 55 |
+
<linearGradient id="grid-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
| 56 |
+
<stop offset="0%" style="stop-color:#f0f0f0;stop-opacity:1" />
|
| 57 |
+
<stop offset="100%" style="stop-color:#d0d0d0;stop-opacity:1" />
|
| 58 |
+
</linearGradient>
|
| 59 |
+
<radialGradient id="player-gradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
|
| 60 |
+
<stop offset="0%" style="stop-color:#ffffff;stop-opacity:0.8" />
|
| 61 |
+
<stop offset="100%" style="stop-color:#000000;stop-opacity:0.1" />
|
| 62 |
+
</radialGradient>
|
| 63 |
+
</defs>
|
| 64 |
+
'''
|
| 65 |
+
|
| 66 |
+
# Draw grid with gradient
|
| 67 |
+
svg += f'<rect width="{GRID_SIZE * CELL_SIZE}" height="{GRID_SIZE * CELL_SIZE}" fill="url(#grid-gradient)" />'
|
| 68 |
for i in range(GRID_SIZE):
|
| 69 |
for j in range(GRID_SIZE):
|
| 70 |
+
svg += f'<rect x="{i * CELL_SIZE}" y="{j * CELL_SIZE}" width="{CELL_SIZE}" height="{CELL_SIZE}" fill="none" stroke="#a0a0a0" stroke-width="1" />'
|
| 71 |
|
| 72 |
+
# Draw players with complex shapes and animations
|
| 73 |
for player, data in game_state["players"].items():
|
| 74 |
x, y = data["x"] * CELL_SIZE + CELL_SIZE // 2, data["y"] * CELL_SIZE + CELL_SIZE // 2
|
| 75 |
color = data.get("color", "#000000")
|
| 76 |
+
player_id = f"player-{player}"
|
| 77 |
+
|
| 78 |
+
# Create a group for the player
|
| 79 |
+
svg += f'<g id="{player_id}">'
|
| 80 |
+
|
| 81 |
+
# Player body (hexagon)
|
| 82 |
+
points = " ".join([f"{x + PLAYER_SIZE // 2 * cos(i * pi / 3)},{y + PLAYER_SIZE // 2 * sin(i * pi / 3)}" for i in range(6)])
|
| 83 |
+
svg += f'<polygon points="{points}" fill="{color}" stroke="black" stroke-width="2">'
|
| 84 |
+
svg += f'<animate attributeName="transform" attributeType="XML" type="rotate" from="0 {x} {y}" to="360 {x} {y}" dur="10s" repeatCount="indefinite" />'
|
| 85 |
+
svg += '</polygon>'
|
| 86 |
+
|
| 87 |
+
# Player eye (circle)
|
| 88 |
+
eye_x, eye_y = x + PLAYER_SIZE // 4, y - PLAYER_SIZE // 4
|
| 89 |
+
svg += f'<circle cx="{eye_x}" cy="{eye_y}" r="{PLAYER_SIZE // 8}" fill="white" stroke="black" stroke-width="1">'
|
| 90 |
+
svg += f'<animate attributeName="r" values="{PLAYER_SIZE // 8};{PLAYER_SIZE // 10};{PLAYER_SIZE // 8}" dur="3s" repeatCount="indefinite" />'
|
| 91 |
svg += '</circle>'
|
| 92 |
+
|
| 93 |
+
# Player name
|
| 94 |
+
svg += f'<text x="{x}" y="{y + PLAYER_SIZE // 2 + 15}" text-anchor="middle" fill="black" font-size="12" font-weight="bold">{player[:3].upper()}</text>'
|
| 95 |
+
|
| 96 |
+
# Movement animations
|
| 97 |
+
svg += f'<animateTransform attributeName="transform" attributeType="XML" type="translate" from="0 0" to="0 0" dur="0.5s" repeatCount="1" />'
|
| 98 |
+
|
| 99 |
+
svg += '</g>'
|
| 100 |
+
|
| 101 |
+
# Draw obstacles
|
| 102 |
+
for obstacle in game_state.get("obstacles", []):
|
| 103 |
+
ox, oy = obstacle["x"] * CELL_SIZE, obstacle["y"] * CELL_SIZE
|
| 104 |
+
svg += f'<rect x="{ox}" y="{oy}" width="{CELL_SIZE}" height="{CELL_SIZE}" fill="url(#player-gradient)" stroke="black" stroke-width="2">'
|
| 105 |
+
svg += f'<animate attributeName="opacity" values="0.7;0.9;0.7" dur="{random.uniform(2,5)}s" repeatCount="indefinite" />'
|
| 106 |
+
svg += '</rect>'
|
| 107 |
|
| 108 |
svg += '</svg>'
|
| 109 |
return svg
|
| 110 |
|
| 111 |
# Streamlit app
|
| 112 |
+
st.set_page_config(layout="wide", page_title="Multiplayer Grid Game")
|
| 113 |
st.title("Enhanced Multiplayer Grid Game")
|
| 114 |
|
| 115 |
# Display player name and allow updates
|
|
|
|
| 126 |
# Create grid
|
| 127 |
grid = st.empty()
|
| 128 |
|
| 129 |
+
# JavaScript for smooth movement and player highlight
|
| 130 |
js_code = """
|
| 131 |
function movePlayer(playerId, fromX, fromY, toX, toY) {
|
| 132 |
const player = document.getElementById(playerId);
|
| 133 |
if (player) {
|
| 134 |
+
const animation = player.querySelector('animateTransform');
|
| 135 |
+
animation.setAttribute('from', `${fromX - toX} ${fromY - toY}`);
|
| 136 |
+
animation.setAttribute('to', '0 0');
|
| 137 |
+
animation.beginElement();
|
| 138 |
+
|
| 139 |
+
// Update player position after animation
|
| 140 |
+
setTimeout(() => {
|
| 141 |
+
const transform = player.getAttribute('transform') || '';
|
| 142 |
+
player.setAttribute('transform', transform + ` translate(${toX - fromX} ${toY - fromY})`);
|
| 143 |
+
}, 500);
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
function pulsePlayer(playerId) {
|
| 148 |
+
const player = document.getElementById(playerId);
|
| 149 |
+
if (player) {
|
| 150 |
+
const polygon = player.querySelector('polygon');
|
| 151 |
+
const originalColor = polygon.getAttribute('fill');
|
| 152 |
+
polygon.setAttribute('fill', '#ff0000');
|
| 153 |
+
setTimeout(() => polygon.setAttribute('fill', originalColor), 300);
|
| 154 |
}
|
| 155 |
}
|
| 156 |
"""
|
| 157 |
|
| 158 |
st.components.v1.html(f"<script>{js_code}</script>", height=0)
|
| 159 |
|
| 160 |
+
# Initialize obstacles if not present
|
| 161 |
+
game_state = load_game_state()
|
| 162 |
+
if "obstacles" not in game_state:
|
| 163 |
+
game_state["obstacles"] = [
|
| 164 |
+
{"x": random.randint(0, GRID_SIZE-1), "y": random.randint(0, GRID_SIZE-1)}
|
| 165 |
+
for _ in range(5)
|
| 166 |
+
]
|
| 167 |
+
save_game_state(game_state)
|
| 168 |
+
|
| 169 |
# Main game loop
|
| 170 |
while True:
|
| 171 |
# Load current game state
|
|
|
|
| 180 |
with col1:
|
| 181 |
if st.button("Select Your Character"):
|
| 182 |
st.session_state.selected_player = st.session_state.player_name
|
| 183 |
+
st_javascript(f"pulsePlayer('player-{st.session_state.player_name}')")
|
| 184 |
|
| 185 |
with col2:
|
| 186 |
if st.session_state.selected_player:
|
|
|
|
| 190 |
current_pos = game_state["players"].get(st.session_state.player_name, {"x": GRID_SIZE // 2, "y": GRID_SIZE // 2})
|
| 191 |
from_x, from_y = current_pos["x"] * CELL_SIZE + CELL_SIZE // 2, current_pos["y"] * CELL_SIZE + CELL_SIZE // 2
|
| 192 |
to_x, to_y = target_x * CELL_SIZE + CELL_SIZE // 2, target_y * CELL_SIZE + CELL_SIZE // 2
|
| 193 |
+
st_javascript(f"movePlayer('player-{st.session_state.player_name}', {from_x}, {from_y}, {to_x}, {to_y})")
|
| 194 |
update_player_position(st.session_state.player_name, target_x, target_y)
|
| 195 |
|
| 196 |
# Wait for update interval
|