Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/pages/BattleAnimation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import "../styles/cannon.css";

interface BattleProps {
fire: boolean;
explode: boolean;
result: string | null;
}

export default function Battle({ fire, explode, result }: BattleProps) {
// 아무 상태도 아니면 렌더링 안 함
if (!fire && !explode) return null;

return (
<div className="battle-field">
{/* 대포 */}
<div className={`cannon ${fire ? "fire" : ""}`}>🧨</div>

{/* 포탄 */}
{fire && <div className="bullet" />}

{/* 폭발 */}
{explode && (
<div className="explosion">
💥
<div className="result-text">{result}</div>
</div>
)}
</div>
);
}
28 changes: 26 additions & 2 deletions src/pages/EventMainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { apiFetch } from "../utils/apiFetch";
import axios from 'axios';
import SockJS from 'sockjs-client';
import Stomp from 'stompjs';
import Battle from "./BattleAnimation";

type Comment = {
id: string;
Expand Down Expand Up @@ -136,6 +137,11 @@ export default function EventMainPage() {
});
const [cannonLoading, setCannonLoading] = useState(false);

//대포
const [fire, setFire] = useState(false);
const [explode, setExplode] = useState(false);
const [result, setResult] = useState<string | null>(null);

const formatDateOnly = (isoString: string) => {
if (!isoString) return "";

Expand Down Expand Up @@ -192,8 +198,21 @@ export default function EventMainPage() {
const client = Stomp.over(socket);
client.connect({}, () => {
client.subscribe(`/sub/game/${eventId}/result`, (msg: any) => {
console.log('💥 결과:', msg.body);
alert(msg.body);
setResult(msg.body);

// 1. 발사 시작
setFire(true);

// 2. 날아간 뒤 폭발
setTimeout(() => {
setExplode(true);
}, 800);

// 3. 전체 종료
setTimeout(() => {
setFire(false);
setExplode(false);
}, 2500);
});
});
setStompClient(client);
Expand Down Expand Up @@ -1581,6 +1600,11 @@ export default function EventMainPage() {
</div>
</DialogContent>
</Dialog>
<Battle
fire={fire}
explode={explode}
result={result}
/>
</div>
);
}
77 changes: 77 additions & 0 deletions src/styles/cannon.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
.battle-field {
position: fixed;
inset: 0;
background: radial-gradient(circle at bottom left, #111, #000);
overflow: hidden;
z-index: 9999;
}

.cannon {
position: absolute;
bottom: 60px;
left: 60px;
font-size: 64px;
transform-origin: center;
}

.cannon.fire {
animation: recoil 0.3s ease-out;
}

@keyframes recoil {
0% { transform: translateX(0); }
50% { transform: translateX(-15px); }
100% { transform: translateX(0); }
}

.bullet {
position: absolute;
bottom: 90px;
left: 110px;
width: 18px;
height: 18px;
background: orange;
border-radius: 50%;
box-shadow: 0 0 12px orange;
animation: fly 0.8s linear forwards;
}

@keyframes fly {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(calc(100vw - 200px), -300px);
}
}

.explosion {
position: absolute;
top: 35%;
right: 20%;
font-size: 80px;
animation: explode 0.4s ease-out;
text-align: center;
}

@keyframes explode {
0% {
transform: scale(0.3);
opacity: 0;
}
60% {
transform: scale(1.4);
opacity: 1;
}
100% {
transform: scale(1);
}
}

.result-text {
margin-top: 16px;
font-size: 36px;
font-weight: bold;
color: #fff;
text-shadow: 0 0 10px red;
}