Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions shared/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export const GAME_CONSTANTS = {
dt: 1 / tickRate, // 각 틱의 시간 (초 단위)

// Worm
HEAD_SPEED: 350, // 머리가 마우스를 쫓는 속도(px/s)
HEAD_SPRINT_SPEED: 550, // 달리기 속도
HEAD_SPEED: 500, // 머리가 마우스를 쫓는 속도(px/s)
HEAD_SPRINT_SPEED: 750, // 달리기 속도
SPRINT_FOOD_DROP_INTERVAL: 500, // 달리기 중 먹이 방출 간격 (ms)
TURN_RATE: 5.0, // 지렁이 회전 속도 (라디안/초)

Expand Down
Binary file removed web-io-game/public/background.jpeg
Binary file not shown.
192 changes: 148 additions & 44 deletions web-io-game/public/loginform.html
Original file line number Diff line number Diff line change
@@ -1,49 +1,153 @@
<div
style="
background-color: rgba(0, 0, 0, 0.5);
padding: 40px;
border-radius: 10px;
<style>
.lobby-shell {
width: min(92vw, 520px);
padding: 34px 32px 30px;
border-radius: 24px;
border: 1px solid rgba(78, 127, 198, 0.35);
background: rgba(0, 15, 40, 0.88);
box-shadow:
0 20px 60px rgba(0, 0, 0, 0.55),
0 0 30px rgba(0, 255, 136, 0.1);
backdrop-filter: blur(8px);
font-family: "Trebuchet MS", Arial, sans-serif;
color: #d8e9ff;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
"
>
<h1 style="color: white; font-size: 32px; margin: 0 0 10px 0">BeyondWorm</h1>
<input
type="text"
id="username-input"
placeholder="Enter your ID"
style="padding: 10px; font-size: 16px; width: 250px; border-radius: 5px; border: none"
/>

<div id="server-list-container" style="width: 300px; color: white">
<h2 style="font-size: 20px; margin-bottom: 10px">Server List</h2>
<ul
id="server-list"
style="
list-style: none;
padding: 0;
height: 150px;
overflow-y: auto;
border: 1px solid #555;
border-radius: 5px;
"
></ul>
gap: 18px;
}

.lobby-title {
margin: 0;
font-size: clamp(34px, 6vw, 54px);
font-weight: 800;
letter-spacing: 0.06em;
text-align: center;
color: #00ff88;
text-shadow: 0 0 26px rgba(0, 255, 136, 0.38);
}

.lobby-subtitle {
margin: -6px 0 8px;
text-align: center;
font-size: 12px;
letter-spacing: 0.22em;
color: rgba(132, 180, 255, 0.8);
}

.lobby-label {
margin: 0 0 8px;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.16em;
color: rgba(132, 180, 255, 0.85);
}

#username-input {
width: 100%;
box-sizing: border-box;
padding: 12px 14px;
border: 1px solid rgba(78, 127, 198, 0.45);
border-radius: 12px;
outline: none;
font-size: 16px;
color: #e8f3ff;
background: rgba(7, 21, 42, 0.95);
}

#username-input:focus {
border-color: rgba(0, 255, 136, 0.75);
box-shadow: 0 0 0 2px rgba(0, 255, 136, 0.16);
}

#server-list-container {
margin-top: 2px;
}

#server-list {
margin: 0;
padding: 8px;
list-style: none;
max-height: 182px;
overflow-y: auto;
border-radius: 14px;
border: 1px solid rgba(78, 127, 198, 0.4);
background: rgba(7, 21, 42, 0.72);
}

.server-item {
padding: 11px 12px;
border-radius: 10px;
border: 1px solid transparent;
color: #c7dcff;
font-size: 14px;
cursor: pointer;
transition: 120ms ease;
}

.server-item + .server-item {
margin-top: 6px;
}

.server-item:hover {
background: rgba(78, 127, 198, 0.18);
border-color: rgba(78, 127, 198, 0.42);
}

.server-item.selected {
background: rgba(0, 255, 136, 0.16);
border-color: rgba(0, 255, 136, 0.62);
color: #00ff88;
}

.server-empty {
padding: 10px 12px;
color: #8ea8cf;
font-size: 14px;
}

.server-error {
color: #ff7f93;
}

#start-button {
margin-top: 8px;
width: 100%;
padding: 14px 16px;
border-radius: 14px;
border: 2px solid rgba(0, 255, 136, 0.58);
background: rgba(0, 255, 136, 0.14);
color: #00ff88;
font-size: 17px;
font-weight: 800;
letter-spacing: 0.1em;
cursor: pointer;
transition: 130ms ease;
}

#start-button:hover {
transform: translateY(-1px);
background: rgba(0, 255, 136, 0.22);
box-shadow: 0 10px 26px rgba(0, 255, 136, 0.16);
}

#start-button:active {
transform: translateY(0);
}
</style>

<div class="lobby-shell">
<h1 class="lobby-title">BEYOND WORM</h1>
<p class="lobby-subtitle">EAT . GROW . SURVIVE</p>

<div>
<p class="lobby-label">플레이어 닉네임</p>
<input type="text" id="username-input" placeholder="Enter your ID" />
</div>

<div id="server-list-container">
<p class="lobby-label">SERVER LIST</p>
Comment thread
konempty marked this conversation as resolved.
Outdated
<ul id="server-list"></ul>
</div>

<button
id="start-button"
style="
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
"
>
Start Game
</button>
<button id="start-button">PLAY</button>
</div>
159 changes: 122 additions & 37 deletions web-io-game/src/DeathScene.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,141 @@
import Phaser from "phaser";

export default class DeathScene extends Phaser.Scene {
private rootContainer?: Phaser.GameObjects.Container;

constructor() {
super({ key: "DeathScene" });
}

create() {
// 반투명 배경 오버레이
const overlay = this.add.rectangle(0, 0, this.cameras.main.width, this.cameras.main.height, 0x000000, 0.7);
overlay.setOrigin(0, 0);
overlay.setScrollFactor(0); // 카메라 이동에 영향받지 않음

// 중앙에 위치할 컨테이너
const centerX = this.cameras.main.width / 2;
const centerY = this.cameras.main.height / 2;

// 죽음 메시지
const deathText = this.add.text(centerX, centerY - 50, "You Died!", {
fontSize: "48px",
color: "#ff0000",
fontStyle: "bold",
});
deathText.setOrigin(0.5);
deathText.setScrollFactor(0);

// 로비로 돌아가기 버튼
const backButton = this.add.text(centerX, centerY + 20, "Back to Lobby", {
fontSize: "24px",
color: "#ffffff",
backgroundColor: "#333333",
padding: { x: 20, y: 10 },
create(data: { score?: number; bestScore?: number }) {
this.renderUI(data);

this.scale.on("resize", (gameSize: Phaser.Structs.Size) => {
this.rootContainer?.destroy(true);
this.renderUI(data, gameSize.width, gameSize.height);
});
backButton.setOrigin(0.5);
backButton.setScrollFactor(0);
backButton.setInteractive({ useHandCursor: true });
}

private renderUI(
data: { score?: number; bestScore?: number },
width: number = this.cameras.main.width,
height: number = this.cameras.main.height,
) {
const centerX = width / 2;
const centerY = height / 2;

const overlay = this.add.rectangle(0, 0, width, height, 0x000913, 0.78).setOrigin(0, 0).setScrollFactor(0);

const panelGfx = this.add.graphics();
panelGfx.fillStyle(0x000f28, 0.9);
panelGfx.lineStyle(2, 0xff3350, 0.35);
panelGfx.fillRoundedRect(-220, -190, 440, 380, 26);
panelGfx.strokeRoundedRect(-220, -190, 440, 380, 26);

const gameOverText = this.add
.text(0, -130, "GAME OVER", {
fontFamily: "Trebuchet MS, Arial, sans-serif",
fontSize: "52px",
color: "#ff3350",
fontStyle: "bold",
})
.setOrigin(0.5)
.setStroke("#2a0f18", 6);

// 버튼 호버 효과
backButton.on("pointerover", () => {
backButton.setStyle({ backgroundColor: "#555555" });
const scoreLabel = this.add
.text(0, -54, "FINAL SCORE", {
fontFamily: "Trebuchet MS, Arial, sans-serif",
fontSize: "16px",
color: "#84b4ff",
fontStyle: "bold",
})
.setOrigin(0.5);

const scoreValue = this.add
.text(0, -10, `${data.score ?? 0}`, {
fontFamily: "Trebuchet MS, Arial, sans-serif",
fontSize: "64px",
color: "#00ff88",
fontStyle: "bold",
})
.setOrigin(0.5)
.setStroke("#0a1324", 6);

const bestLabel = this.add
.text(0, 46, "BEST", {
fontFamily: "Trebuchet MS, Arial, sans-serif",
fontSize: "14px",
color: "#ffd166",
fontStyle: "bold",
})
.setOrigin(0.5);

const bestValue = this.add
.text(0, 72, `${data.bestScore ?? data.score ?? 0}`, {
fontFamily: "Trebuchet MS, Arial, sans-serif",
fontSize: "30px",
color: "#ffd166",
fontStyle: "bold",
})
.setOrigin(0.5)
.setStroke("#2d220f", 4);

const buttonGfx = this.add.graphics();
buttonGfx.fillStyle(0x00ff88, 0.17);
buttonGfx.lineStyle(2, 0x00ff88, 0.55);
buttonGfx.fillRoundedRect(-110, 108, 220, 58, 18);
buttonGfx.strokeRoundedRect(-110, 108, 220, 58, 18);

const playAgainText = this.add
.text(0, 136, "PLAY AGAIN", {
fontFamily: "Trebuchet MS, Arial, sans-serif",
fontSize: "24px",
color: "#00ff88",
fontStyle: "bold",
})
.setOrigin(0.5);

const buttonHitArea = this.add
.rectangle(0, 136, 220, 58, 0x000000, 0.001)
.setInteractive({ useHandCursor: true });

buttonHitArea.on("pointerover", () => {
buttonGfx.clear();
buttonGfx.fillStyle(0x00ff88, 0.24);
buttonGfx.lineStyle(2, 0x00ff88, 0.8);
buttonGfx.fillRoundedRect(-110, 108, 220, 58, 18);
buttonGfx.strokeRoundedRect(-110, 108, 220, 58, 18);
});

backButton.on("pointerout", () => {
backButton.setStyle({ backgroundColor: "#333333" });
buttonHitArea.on("pointerout", () => {
buttonGfx.clear();
buttonGfx.fillStyle(0x00ff88, 0.17);
buttonGfx.lineStyle(2, 0x00ff88, 0.55);
buttonGfx.fillRoundedRect(-110, 108, 220, 58, 18);
buttonGfx.strokeRoundedRect(-110, 108, 220, 58, 18);
});

// 버튼 클릭 시 로비로 이동
backButton.on("pointerdown", () => {
this.cameras.main.fadeOut(300, 0, 0, 0);
buttonHitArea.on("pointerdown", () => {
this.cameras.main.fadeOut(220, 0, 0, 0);
});

this.cameras.main.on(Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE, () => {
this.cameras.main.once(Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE, () => {
location.reload();
});
Comment thread
konempty marked this conversation as resolved.
Outdated

this.rootContainer = this.add.container(centerX, centerY, [
panelGfx,
gameOverText,
scoreLabel,
scoreValue,
bestLabel,
bestValue,
buttonGfx,
playAgainText,
buttonHitArea,
]);
this.rootContainer.setScrollFactor(0);
this.rootContainer.setDepth(11000);
overlay.setDepth(10999);
}
}
Loading