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
|