mirror of
https://github.com/iamlukethedev/Claw3D.git
synced 2026-07-30 19:22:28 +00:00
Expand outdoor shopping district
Co-authored-by: Luke The Dev <iamlukethedev@users.noreply.github.com>
This commit is contained in:
co-authored by
Luke The Dev
parent
94aff0f3da
commit
89a4e359bd
@@ -19,28 +19,30 @@ export const LOCAL_OFFICE_ZONE: DistrictZone = {
|
||||
maxY: LOCAL_OFFICE_CANVAS_HEIGHT,
|
||||
};
|
||||
|
||||
export const CITY_PATH_ZONE: DistrictZone = {
|
||||
export const SHOPPING_ZONE: DistrictZone = {
|
||||
minX: 0,
|
||||
maxX: LOCAL_OFFICE_CANVAS_WIDTH,
|
||||
minY: 760,
|
||||
maxY: 980,
|
||||
minY: 720,
|
||||
maxY: 1080,
|
||||
};
|
||||
|
||||
export const CITY_PATH_ZONE: DistrictZone = SHOPPING_ZONE;
|
||||
|
||||
export const REMOTE_OFFICE_ZONE: DistrictZone = {
|
||||
minX: 0,
|
||||
maxX: LOCAL_OFFICE_CANVAS_WIDTH,
|
||||
minY: 1020,
|
||||
maxY: 1020 + LOCAL_OFFICE_CANVAS_HEIGHT,
|
||||
minY: SHOPPING_ZONE.maxY,
|
||||
maxY: SHOPPING_ZONE.maxY + LOCAL_OFFICE_CANVAS_HEIGHT,
|
||||
};
|
||||
|
||||
export const REMOTE_ROAM_POINTS = [
|
||||
{ x: 800, y: 1220 },
|
||||
{ x: 850, y: 1520 },
|
||||
{ x: 820, y: 1600 },
|
||||
{ x: 450, y: 1440 },
|
||||
{ x: 250, y: 1440 },
|
||||
{ x: 650, y: 1440 },
|
||||
{ x: 150, y: 1640 },
|
||||
{ x: 800, y: 1280 },
|
||||
{ x: 850, y: 1580 },
|
||||
{ x: 820, y: 1660 },
|
||||
{ x: 450, y: 1500 },
|
||||
{ x: 250, y: 1500 },
|
||||
{ x: 650, y: 1500 },
|
||||
{ x: 150, y: 1700 },
|
||||
] as const;
|
||||
|
||||
export const DISTRICT_CAMERA_POSITION: [number, number, number] = [14, 16, 18];
|
||||
|
||||
@@ -62,8 +62,8 @@ const DEFAULT_JUKEBOX: FurnitureSeed = {
|
||||
|
||||
const DEFAULT_SHOP: FurnitureSeed = {
|
||||
type: "shop",
|
||||
x: 320,
|
||||
y: 840,
|
||||
x: 140,
|
||||
y: 820,
|
||||
facing: 0,
|
||||
};
|
||||
|
||||
@@ -117,15 +117,28 @@ const DEFAULT_DINING_ITEMS: FurnitureSeed[] = [
|
||||
];
|
||||
|
||||
const DEFAULT_SHOPPING_STRIP_ITEMS: FurnitureSeed[] = [
|
||||
{ type: "table_rect", x: 230, y: 820, w: 110, h: 40, facing: 0 },
|
||||
{ type: "vending", x: 470, y: 790, facing: 0 },
|
||||
{ type: "table_rect", x: 670, y: 870, w: 120, h: 40, facing: 0 },
|
||||
{ type: "plant", x: 210, y: 930 },
|
||||
{ type: "plant", x: 520, y: 930 },
|
||||
{ type: "plant", x: 860, y: 930 },
|
||||
{ type: "couch", x: 1010, y: 820, w: 90, h: 30, facing: 0 },
|
||||
{ type: "couch", x: 1200, y: 820, w: 90, h: 30, facing: 0 },
|
||||
{ type: "couch", x: 1390, y: 820, w: 90, h: 30, facing: 0 },
|
||||
{ type: "table_rect", x: 120, y: 780, w: 120, h: 42, facing: 0 },
|
||||
{ type: "vending", x: 120, y: 930, facing: 0 },
|
||||
{ type: "bookshelf", x: 420, y: 780, w: 80, h: 120, facing: 0 },
|
||||
{ type: "bookshelf", x: 420, y: 930, w: 80, h: 120, facing: 0 },
|
||||
{ type: "bookshelf", x: 650, y: 780, w: 80, h: 120, facing: 0 },
|
||||
{ type: "bookshelf", x: 650, y: 930, w: 80, h: 120, facing: 0 },
|
||||
{ type: "bookshelf", x: 880, y: 780, w: 80, h: 120, facing: 0 },
|
||||
{ type: "bookshelf", x: 880, y: 930, w: 80, h: 120, facing: 0 },
|
||||
{ type: "bookshelf", x: 1110, y: 780, w: 80, h: 120, facing: 0 },
|
||||
{ type: "bookshelf", x: 1110, y: 930, w: 80, h: 120, facing: 0 },
|
||||
{ type: "bookshelf", x: 1340, y: 780, w: 80, h: 120, facing: 0 },
|
||||
{ type: "bookshelf", x: 1340, y: 930, w: 80, h: 120, facing: 0 },
|
||||
{ type: "table_rect", x: 1560, y: 790, w: 120, h: 42, facing: 0 },
|
||||
{ type: "table_rect", x: 1560, y: 930, w: 120, h: 42, facing: 0 },
|
||||
{ type: "couch", x: 1490, y: 1010, w: 90, h: 30, facing: 0 },
|
||||
{ type: "couch", x: 1640, y: 1010, w: 90, h: 30, facing: 0 },
|
||||
{ type: "plant", x: 300, y: 1030 },
|
||||
{ type: "plant", x: 560, y: 1030 },
|
||||
{ type: "plant", x: 790, y: 1030 },
|
||||
{ type: "plant", x: 1020, y: 1030 },
|
||||
{ type: "plant", x: 1250, y: 1030 },
|
||||
{ type: "plant", x: 1480, y: 1030 },
|
||||
];
|
||||
|
||||
const DEFAULT_SERVER_ROOM_ITEMS: FurnitureSeed[] = [
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SHOPPING_ZONE } from "@/features/retro-office/core/district";
|
||||
import { getItemBaseSize } from "@/features/retro-office/core/geometry";
|
||||
import type {
|
||||
FacingPoint,
|
||||
@@ -5,9 +6,21 @@ import type {
|
||||
ShopRoute,
|
||||
} from "@/features/retro-office/core/types";
|
||||
|
||||
export const SHOP_ENTRY_TARGET: FacingPoint = {
|
||||
x: 900,
|
||||
y: SHOPPING_ZONE.minY + 40,
|
||||
facing: 0,
|
||||
};
|
||||
|
||||
export const SHOP_AISLE_TARGET: FacingPoint = {
|
||||
x: 980,
|
||||
y: 910,
|
||||
facing: 0,
|
||||
};
|
||||
|
||||
export const SHOP_TARGET: FacingPoint = {
|
||||
x: 280,
|
||||
y: 840,
|
||||
x: 180,
|
||||
y: 920,
|
||||
facing: 0,
|
||||
};
|
||||
|
||||
@@ -18,40 +31,57 @@ export const resolveShopRoute = (
|
||||
): ShopRoute => {
|
||||
if (!item) {
|
||||
return {
|
||||
stage: "counter",
|
||||
stage: "checkout",
|
||||
targetX: SHOP_TARGET.x,
|
||||
targetY: SHOP_TARGET.y,
|
||||
facing: SHOP_TARGET.facing,
|
||||
};
|
||||
}
|
||||
const { width, height } = getItemBaseSize(item);
|
||||
const centerY = item.y + height / 2;
|
||||
const approachTarget = {
|
||||
const checkoutTarget = {
|
||||
x: item.x + width / 2,
|
||||
y: item.y + height + 50,
|
||||
y: item.y + height + 44,
|
||||
facing: 0,
|
||||
};
|
||||
const counterTarget = {
|
||||
x: item.x + width / 2,
|
||||
y: centerY,
|
||||
facing: 0,
|
||||
};
|
||||
|
||||
const atCounter =
|
||||
y <= approachTarget.y + 6 || Math.hypot(x - approachTarget.x, y - approachTarget.y) < 18;
|
||||
if (atCounter) {
|
||||
const closeToCheckout =
|
||||
Math.hypot(x - checkoutTarget.x, y - checkoutTarget.y) < 44;
|
||||
if (closeToCheckout) {
|
||||
return {
|
||||
stage: "counter",
|
||||
targetX: counterTarget.x,
|
||||
targetY: counterTarget.y,
|
||||
facing: counterTarget.facing,
|
||||
stage: "checkout",
|
||||
targetX: checkoutTarget.x,
|
||||
targetY: checkoutTarget.y,
|
||||
facing: checkoutTarget.facing,
|
||||
};
|
||||
}
|
||||
|
||||
const closeToAisle =
|
||||
y >= SHOPPING_ZONE.minY + 70 &&
|
||||
Math.hypot(x - SHOP_AISLE_TARGET.x, y - SHOP_AISLE_TARGET.y) < 90;
|
||||
if (closeToAisle) {
|
||||
return {
|
||||
stage: "checkout",
|
||||
targetX: checkoutTarget.x,
|
||||
targetY: checkoutTarget.y,
|
||||
facing: checkoutTarget.facing,
|
||||
};
|
||||
}
|
||||
|
||||
const enteredStore =
|
||||
y >= SHOP_ENTRY_TARGET.y - 10 ||
|
||||
Math.hypot(x - SHOP_ENTRY_TARGET.x, y - SHOP_ENTRY_TARGET.y) < 70;
|
||||
if (enteredStore) {
|
||||
return {
|
||||
stage: "aisle",
|
||||
targetX: SHOP_AISLE_TARGET.x,
|
||||
targetY: SHOP_AISLE_TARGET.y,
|
||||
facing: SHOP_AISLE_TARGET.facing,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
stage: "approach",
|
||||
targetX: approachTarget.x,
|
||||
targetY: approachTarget.y,
|
||||
facing: approachTarget.facing,
|
||||
stage: "entrance",
|
||||
targetX: SHOP_ENTRY_TARGET.x,
|
||||
targetY: SHOP_ENTRY_TARGET.y,
|
||||
facing: SHOP_ENTRY_TARGET.facing,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -137,7 +137,7 @@ export type SmsBoothRoute = {
|
||||
};
|
||||
|
||||
export type ShopRoute = {
|
||||
stage: "approach" | "counter";
|
||||
stage: "entrance" | "aisle" | "checkout";
|
||||
targetX: number;
|
||||
targetY: number;
|
||||
facing: number;
|
||||
|
||||
@@ -277,11 +277,11 @@ export const FloorAndWalls = memo(function FloorAndWalls({
|
||||
>
|
||||
<planeGeometry
|
||||
args={[
|
||||
(CITY_PATH_ZONE.maxX - CITY_PATH_ZONE.minX) * SCALE * 0.72,
|
||||
(CITY_PATH_ZONE.maxY - CITY_PATH_ZONE.minY) * SCALE * 0.26,
|
||||
(CITY_PATH_ZONE.maxX - CITY_PATH_ZONE.minX) * SCALE * 0.92,
|
||||
(CITY_PATH_ZONE.maxY - CITY_PATH_ZONE.minY) * SCALE * 0.74,
|
||||
]}
|
||||
/>
|
||||
<meshStandardMaterial color="#c9ae8d" roughness={0.94} metalness={0.02} />
|
||||
<meshStandardMaterial color="#c9ae8d" roughness={0.9} metalness={0.04} />
|
||||
</mesh>
|
||||
|
||||
{Array.from({ length: 8 }).map((_, index) => {
|
||||
@@ -355,8 +355,8 @@ export const FloorAndWalls = memo(function FloorAndWalls({
|
||||
);
|
||||
})}
|
||||
|
||||
{Array.from({ length: 5 }).map((_, index) => {
|
||||
const [wx, , wz] = toWorld(220 + index * 280, 785);
|
||||
{Array.from({ length: 6 }).map((_, index) => {
|
||||
const [wx, , wz] = toWorld(190 + index * 270, 770);
|
||||
return (
|
||||
<group key={`shopping-awning-${index}`} position={[wx, 0, wz]}>
|
||||
<mesh position={[0, 0.9, 0]} castShadow receiveShadow>
|
||||
@@ -374,6 +374,44 @@ export const FloorAndWalls = memo(function FloorAndWalls({
|
||||
</group>
|
||||
);
|
||||
})}
|
||||
|
||||
{Array.from({ length: 5 }).map((_, index) => {
|
||||
const [wx, , wz] = toWorld(300 + index * 280, 1010);
|
||||
return (
|
||||
<group key={`shopping-section-${index}`} position={[wx, 0, wz]}>
|
||||
<mesh position={[0, 0.52, 0]} castShadow receiveShadow>
|
||||
<boxGeometry args={[1.55, 0.14, 0.22]} />
|
||||
<meshStandardMaterial color="#3e2723" roughness={0.74} metalness={0.08} />
|
||||
</mesh>
|
||||
<mesh position={[0, 0.86, 0]} castShadow receiveShadow>
|
||||
<boxGeometry args={[0.08, 0.68, 0.08]} />
|
||||
<meshStandardMaterial color="#6d4c41" roughness={0.62} metalness={0.12} />
|
||||
</mesh>
|
||||
<mesh position={[0, 1.18, 0]} castShadow receiveShadow>
|
||||
<boxGeometry args={[0.94, 0.18, 0.16]} />
|
||||
<meshStandardMaterial
|
||||
color={["#22c55e", "#f59e0b", "#38bdf8", "#a855f7", "#ef4444"][index]}
|
||||
roughness={0.34}
|
||||
metalness={0.06}
|
||||
/>
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
})}
|
||||
|
||||
{Array.from({ length: 6 }).map((_, index) => {
|
||||
const [wx, , wz] = toWorld(360 + index * 230, 905);
|
||||
return (
|
||||
<mesh
|
||||
key={`shopping-aisle-mark-${index}`}
|
||||
position={[wx, 0.008, wz]}
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
>
|
||||
<planeGeometry args={[0.05, (CITY_PATH_ZONE.maxY - CITY_PATH_ZONE.minY) * SCALE * 0.58]} />
|
||||
<meshBasicMaterial color="#fff5d6" transparent opacity={0.16} />
|
||||
</mesh>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
) : null}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user